From 2dec3ba8d872aa3ffbcdb8f6f8a2c0bcd44e9910 Mon Sep 17 00:00:00 2001 From: Yu Luming Date: Tue, 19 Dec 2006 12:56:17 -0800 Subject: output: Add display output class support Add generic abstract layer for display output switch control. The output sysfs class driver provides an abstract video output layer that can be used to hook platform specific methods to enable/disable video output device through common sysfs interface. Signed-off-by: Luming Yu Cc: "Antonino A. Daplas" Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- include/linux/video_output.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 include/linux/video_output.h (limited to 'include/linux') diff --git a/include/linux/video_output.h b/include/linux/video_output.h new file mode 100644 index 000000000000..e63e0c03ee0d --- /dev/null +++ b/include/linux/video_output.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (C) 2006 Luming Yu + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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_VIDEO_OUTPUT_H +#define _LINUX_VIDEO_OUTPUT_H +#include +struct output_device; +struct output_properties { + int (*set_state)(struct output_device *); + int (*get_status)(struct output_device *); +}; +struct output_device { + int request_state; + struct output_properties *props; + struct class_device class_dev; +}; +#define to_output_device(obj) container_of(obj, struct output_device, class_dev) +struct output_device *video_output_register(const char *name, + struct device *dev, + void *devdata, + struct output_properties *op); +void video_output_unregister(struct output_device *dev); +#endif -- cgit v1.2.3 From ad71860a17ba33eb0e673e9e2cf5ba0d8e3e3fdd Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Fri, 2 Feb 2007 19:48:19 +0300 Subject: ACPICA: minimal patch to integrate new tables into Linux Signed-off-by: Len Brown --- arch/i386/kernel/acpi/boot.c | 17 ++--- arch/ia64/kernel/acpi.c | 8 +-- arch/ia64/sn/kernel/io_common.c | 17 +++-- arch/ia64/sn/kernel/iomv.c | 10 +-- arch/x86_64/kernel/time.c | 18 +++--- drivers/acpi/asus_acpi.c | 9 +-- drivers/acpi/blacklist.c | 15 ++--- drivers/acpi/bus.c | 25 ++++---- drivers/acpi/ec.c | 4 +- drivers/acpi/motherboard.c | 40 ++++++------ drivers/acpi/osl.c | 47 ++++++-------- drivers/acpi/processor_core.c | 2 +- drivers/acpi/processor_idle.c | 29 +++++---- drivers/acpi/processor_perflib.c | 27 +++----- drivers/acpi/scan.c | 4 +- drivers/acpi/sleep/proc.c | 36 ++++++----- drivers/acpi/system.c | 15 ++--- drivers/acpi/tables.c | 29 ++++----- drivers/acpi/tables/Makefile | 3 +- drivers/acpi/tables/tbutils.c | 2 +- drivers/acpi/tables/tbxface.c | 8 ++- include/acpi/acglobal.h | 2 + include/acpi/acpi_bus.h | 1 - include/acpi/actbl.h | 7 +- include/acpi/actbl2.h | 49 -------------- include/acpi/actbl71.h | 134 --------------------------------------- include/asm-i386/acpi.h | 8 +-- include/asm-ia64/acpi.h | 8 +-- include/asm-ia64/sn/acpi.h | 16 ----- include/asm-x86_64/acpi.h | 8 +-- include/linux/acpi.h | 46 -------------- 31 files changed, 191 insertions(+), 453 deletions(-) delete mode 100644 include/acpi/actbl2.h delete mode 100644 include/acpi/actbl71.h delete mode 100644 include/asm-ia64/sn/acpi.h (limited to 'include/linux') diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index cbcb2c27f48b..9adabc4dba70 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -716,33 +716,26 @@ static int __init acpi_parse_fadt(unsigned long phys, unsigned long size) printk(KERN_WARNING PREFIX "Unable to map FADT\n"); return 0; } - /* initialize sci_int early for INT_SRC_OVR MADT parsing */ - acpi_fadt.sci_int = fadt->sci_int; - - /* initialize rev and apic_phys_dest_mode for x86_64 genapic */ - acpi_fadt.revision = fadt->revision; - acpi_fadt.force_apic_physical_destination_mode = - fadt->force_apic_physical_destination_mode; #ifdef CONFIG_X86_PM_TIMER /* detect the location of the ACPI PM Timer */ - if (fadt->revision >= FADT2_REVISION_ID) { + if (fadt->header.revision >= FADT2_REVISION_ID) { /* FADT rev. 2 */ - if (fadt->xpm_tmr_blk.address_space_id != + if (fadt->xpm_timer_block.space_id != ACPI_ADR_SPACE_SYSTEM_IO) return 0; - pmtmr_ioport = fadt->xpm_tmr_blk.address; + pmtmr_ioport = fadt->xpm_timer_block.address; /* * "X" fields are optional extensions to the original V1.0 * fields, so we must selectively expand V1.0 fields if the * corresponding X field is zero. */ if (!pmtmr_ioport) - pmtmr_ioport = fadt->V1_pm_tmr_blk; + pmtmr_ioport = fadt->pm_timer_block; } else { /* FADT rev. 1 */ - pmtmr_ioport = fadt->V1_pm_tmr_blk; + pmtmr_ioport = fadt->pm_timer_block; } if (pmtmr_ioport) printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index ef2fe474f107..aa6f96720984 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -76,7 +76,7 @@ const char *acpi_get_sysname(void) { #ifdef CONFIG_IA64_GENERIC unsigned long rsdp_phys; - struct acpi20_table_rsdp *rsdp; + struct acpi_table_rsdp *rsdp; struct acpi_table_xsdt *xsdt; struct acpi_table_header *hdr; @@ -87,8 +87,8 @@ const char *acpi_get_sysname(void) return "dig"; } - rsdp = (struct acpi20_table_rsdp *)__va(rsdp_phys); - if (strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1)) { + rsdp = (struct acpi_table_rsdp *)__va(rsdp_phys); + if (strncmp(rsdp->signature, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)) { printk(KERN_ERR "ACPI 2.0 RSDP signature incorrect, default to \"dig\"\n"); return "dig"; @@ -96,7 +96,7 @@ const char *acpi_get_sysname(void) xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_address); hdr = &xsdt->header; - if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1)) { + if (strncmp(hdr->signature, ACPI_SIG_XSDT, sizeof(ACPI_SIG_XSDT) - 1)) { printk(KERN_ERR "ACPI 2.0 XSDT signature incorrect, default to \"dig\"\n"); return "dig"; diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c index d4dd8f4b6b8d..65979f1fb353 100644 --- a/arch/ia64/sn/kernel/io_common.c +++ b/arch/ia64/sn/kernel/io_common.c @@ -25,7 +25,6 @@ #include "xtalk/xwidgetdev.h" #include #include -#include extern void sn_init_cpei_timer(void); extern void register_sn_procfs(void); @@ -37,7 +36,6 @@ extern void sn_legacy_pci_window_fixup(struct pci_controller *, u64, u64); extern void sn_io_acpi_init(void); extern void sn_io_init(void); - static struct list_head sn_sysdata_list; /* sysdata list struct */ @@ -50,6 +48,15 @@ int sn_ioif_inited; /* SN I/O infrastructure initialized? */ struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */ +int sn_acpi_base_support() +{ + struct acpi_table_header *header; + (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header); + if (header && header->oem_revision >= 0x20101) + return 1; + return 0; +} + /* * Hooks and struct for unsupported pci providers */ @@ -286,7 +293,7 @@ void sn_pci_fixup_slot(struct pci_dev *dev) list_add_tail(&pcidev_info->pdi_list, &(SN_PLATFORM_DATA(dev->bus)->pcidev_info)); - if (SN_ACPI_BASE_SUPPORT()) + if (sn_acpi_base_support()) sn_acpi_slot_fixup(dev, pcidev_info); else sn_more_slot_fixup(dev, pcidev_info); @@ -498,7 +505,7 @@ void __devinit sn_pci_fixup_bus(struct pci_bus *bus) { - if (SN_ACPI_BASE_SUPPORT()) + if (sn_acpi_base_support()) sn_acpi_bus_fixup(bus); else sn_bus_fixup(bus); @@ -546,7 +553,7 @@ sn_io_early_init(void) printk(KERN_INFO "ACPI DSDT OEM Rev 0x%x\n", acpi_gbl_DSDT->oem_revision); - if (SN_ACPI_BASE_SUPPORT()) + if (sn_acpi_base_support()) sn_io_acpi_init(); else sn_io_init(); diff --git a/arch/ia64/sn/kernel/iomv.c b/arch/ia64/sn/kernel/iomv.c index 4aa4f301d56d..b1a47da118b1 100644 --- a/arch/ia64/sn/kernel/iomv.c +++ b/arch/ia64/sn/kernel/iomv.c @@ -1,4 +1,4 @@ -/* +/* * 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. @@ -16,7 +16,6 @@ #include #include #include -#include #define IS_LEGACY_VGA_IOPORT(p) \ (((p) >= 0x3b0 && (p) <= 0x3bb) || ((p) >= 0x3c0 && (p) <= 0x3df)) @@ -26,9 +25,12 @@ * @port: port to convert * * Legacy in/out instructions are converted to ld/st instructions - * on IA64. This routine will convert a port number into a valid + * on IA64. This routine will convert a port number into a valid * SN i/o address. Used by sn_in*() and sn_out*(). */ + +extern int sn_acpi_base_support(); + void *sn_io_addr(unsigned long port) { if (!IS_RUNNING_ON_SIMULATOR()) { @@ -37,7 +39,7 @@ void *sn_io_addr(unsigned long port) /* On sn2, legacy I/O ports don't point at anything */ if (port < (64 * 1024)) return NULL; - if (SN_ACPI_BASE_SUPPORT()) + if (sn_acpi_base_support()) return (__ia64_mk_io_addr(port)); else return ((void *)(port | __IA64_UNCACHED_OFFSET)); diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 5cc76d0d331f..335cc91c49b7 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -498,7 +498,7 @@ static unsigned long get_cmos_time(void) { unsigned int year, mon, day, hour, min, sec; unsigned long flags; - unsigned extyear = 0; + unsigned century = 0; spin_lock_irqsave(&rtc_lock, flags); @@ -510,9 +510,9 @@ static unsigned long get_cmos_time(void) mon = CMOS_READ(RTC_MONTH); year = CMOS_READ(RTC_YEAR); #ifdef CONFIG_ACPI - if (acpi_fadt.revision >= FADT2_REVISION_ID && - acpi_fadt.century) - extyear = CMOS_READ(acpi_fadt.century); + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) + century = CMOS_READ(acpi_gbl_FADT.century); #endif } while (sec != CMOS_READ(RTC_SECONDS)); @@ -530,10 +530,10 @@ static unsigned long get_cmos_time(void) BCD_TO_BIN(mon); BCD_TO_BIN(year); - if (extyear) { - BCD_TO_BIN(extyear); - year += extyear; - printk(KERN_INFO "Extended CMOS year: %d\n", extyear); + if (century) { + BCD_TO_BIN(century); + year += century * 100; + printk(KERN_INFO "Extended CMOS year: %d\n", century * 100); } else { /* * x86-64 systems only exists since 2002. @@ -954,7 +954,7 @@ __cpuinit int unsynchronized_tsc(void) if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) { #ifdef CONFIG_ACPI /* But TSC doesn't tick in C3 so don't use it there */ - if (acpi_fadt.length > 0 && acpi_fadt.plvl3_lat < 1000) + if (acpi_gbl_FADT.header.length > 0 && acpi_gbl_FADT.C3latency < 1000) return 1; #endif return 0; diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index 396140bbbe57..31ad70a6e22e 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -26,7 +26,7 @@ * Pontus Fuchs - Helper functions, cleanup * Johann Wiesner - Small compile fixes * John Belmonte - ACPI code for Toshiba laptop was a good starting point. - * Éric Burghard - LED display support for W1N + * �ic Burghard - LED display support for W1N * */ @@ -1128,7 +1128,6 @@ static int asus_model_match(char *model) static int asus_hotk_get_info(void) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *model = NULL; int bsts_result; char *string = NULL; @@ -1142,11 +1141,9 @@ static int asus_hotk_get_info(void) * HID), this bit will be moved. A global variable asus_info contains * the DSDT header. */ - status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt); + status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info); if (ACPI_FAILURE(status)) printk(KERN_WARNING " Couldn't get the DSDT table header\n"); - else - asus_info = dsdt.pointer; /* We have to write 0 on init this far for all ASUS models */ if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { @@ -1358,8 +1355,6 @@ static void __exit asus_acpi_exit(void) acpi_bus_unregister_driver(&asus_hotk_driver); remove_proc_entry(PROC_ASUS, acpi_root_dir); - kfree(asus_info); - return; } diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index f9c972b26f4f..bdc169bc054a 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -44,7 +44,7 @@ struct acpi_blacklist_item { char oem_id[7]; char oem_table_id[9]; u32 oem_revision; - acpi_table_type table; + char *table; enum acpi_blacklist_predicates oem_revision_predicate; char *reason; u32 is_critical_error; @@ -56,18 +56,18 @@ struct acpi_blacklist_item { */ static struct acpi_blacklist_item acpi_blacklist[] __initdata = { /* Compaq Presario 1700 */ - {"PTLTD ", " DSDT ", 0x06040000, ACPI_DSDT, less_than_or_equal, + {"PTLTD ", " DSDT ", 0x06040000, ACPI_SIG_DSDT, less_than_or_equal, "Multiple problems", 1}, /* Sony FX120, FX140, FX150? */ - {"SONY ", "U0 ", 0x20010313, ACPI_DSDT, less_than_or_equal, + {"SONY ", "U0 ", 0x20010313, ACPI_SIG_DSDT, less_than_or_equal, "ACPI driver problem", 1}, /* Compaq Presario 800, Insyde BIOS */ - {"INT440", "SYSFexxx", 0x00001001, ACPI_DSDT, less_than_or_equal, + {"INT440", "SYSFexxx", 0x00001001, ACPI_SIG_DSDT, less_than_or_equal, "Does not use _REG to protect EC OpRegions", 1}, /* IBM 600E - _ADR should return 7, but it returns 1 */ - {"IBM ", "TP600E ", 0x00000105, ACPI_DSDT, less_than_or_equal, + {"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal, "Incorrect _ADR", 1}, - {"ASUS\0\0", "P2B-S ", 0, ACPI_DSDT, all_versions, + {"ASUS\0\0", "P2B-S ", 0, ACPI_SIG_DSDT, all_versions, "Bogus PCI routing", 1}, {""} @@ -106,8 +106,7 @@ int __init acpi_blacklisted(void) struct acpi_table_header *table_header; while (acpi_blacklist[i].oem_id[0] != '\0') { - if (acpi_get_table_header_early - (acpi_blacklist[i].table, &table_header)) { + if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) { i++; continue; } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 766332e45592..cb807c43e59b 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -44,9 +44,6 @@ ACPI_MODULE_NAME("acpi_bus") extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger); #endif -struct fadt_descriptor acpi_fadt; -EXPORT_SYMBOL(acpi_fadt); - struct acpi_device *acpi_root; struct proc_dir_entry *acpi_root_dir; EXPORT_SYMBOL(acpi_root_dir); @@ -582,11 +579,12 @@ static int __init acpi_bus_init_irq(void) return 0; } +acpi_native_uint acpi_gbl_permanent_mmap; + + void __init acpi_early_init(void) { acpi_status status = AE_OK; - struct acpi_buffer buffer = { sizeof(acpi_fadt), &acpi_fadt }; - if (acpi_disabled) return; @@ -597,6 +595,15 @@ void __init acpi_early_init(void) if (!acpi_strict) acpi_gbl_enable_interpreter_slack = TRUE; + acpi_gbl_permanent_mmap = 1; + + status = acpi_reallocate_root_table(); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX + "Unable to reallocate ACPI tables\n"); + goto error0; + } + status = acpi_initialize_subsystem(); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX @@ -611,14 +618,6 @@ void __init acpi_early_init(void) goto error0; } - /* - * Get a separate copy of the FADT for use by other drivers. - */ - status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &buffer); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Unable to get the FADT\n"); - goto error0; - } #ifdef CONFIG_X86 if (!acpi_ioapic) { extern acpi_interrupt_flags acpi_sci_flags; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index cbdf031f3c09..7a1f2baff646 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -872,9 +872,7 @@ static int __init acpi_ec_get_real_ecdt(void) acpi_status status; struct acpi_table_ecdt *ecdt_ptr; - status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING, - (struct acpi_table_header **) - &ecdt_ptr); + status = acpi_get_table("ECDT", 1, (struct acpi_table_header **)&ecdt_ptr); if (ACPI_FAILURE(status)) return -ENODEV; diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c index 2e17ec75af03..b61107b05262 100644 --- a/drivers/acpi/motherboard.c +++ b/drivers/acpi/motherboard.c @@ -134,41 +134,41 @@ static void __init acpi_request_region (struct acpi_generic_address *addr, if (!addr->address || !length) return; - if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) + if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO) request_region(addr->address, length, desc); - else if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) request_mem_region(addr->address, length, desc); } static void __init acpi_reserve_resources(void) { - acpi_request_region(&acpi_gbl_FADT->xpm1a_evt_blk, - acpi_gbl_FADT->pm1_evt_len, "ACPI PM1a_EVT_BLK"); + acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, + acpi_gbl_FADT.pm1_event_length, "ACPI PM1a_EVT_BLK"); - acpi_request_region(&acpi_gbl_FADT->xpm1b_evt_blk, - acpi_gbl_FADT->pm1_evt_len, "ACPI PM1b_EVT_BLK"); + acpi_request_region(&acpi_gbl_FADT.xpm1b_event_block, + acpi_gbl_FADT.pm1_event_length, "ACPI PM1b_EVT_BLK"); - acpi_request_region(&acpi_gbl_FADT->xpm1a_cnt_blk, - acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1a_CNT_BLK"); + acpi_request_region(&acpi_gbl_FADT.xpm1a_control_block, + acpi_gbl_FADT.pm1_control_length, "ACPI PM1a_CNT_BLK"); - acpi_request_region(&acpi_gbl_FADT->xpm1b_cnt_blk, - acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1b_CNT_BLK"); + acpi_request_region(&acpi_gbl_FADT.xpm1b_control_block, + acpi_gbl_FADT.pm1_control_length, "ACPI PM1b_CNT_BLK"); - if (acpi_gbl_FADT->pm_tm_len == 4) - acpi_request_region(&acpi_gbl_FADT->xpm_tmr_blk, 4, "ACPI PM_TMR"); + if (acpi_gbl_FADT.pm_timer_length == 4) + acpi_request_region(&acpi_gbl_FADT.xpm_timer_block, 4, "ACPI PM_TMR"); - acpi_request_region(&acpi_gbl_FADT->xpm2_cnt_blk, - acpi_gbl_FADT->pm2_cnt_len, "ACPI PM2_CNT_BLK"); + acpi_request_region(&acpi_gbl_FADT.xpm2_control_block, + acpi_gbl_FADT.pm2_control_length, "ACPI PM2_CNT_BLK"); /* Length of GPE blocks must be a non-negative multiple of 2 */ - if (!(acpi_gbl_FADT->gpe0_blk_len & 0x1)) - acpi_request_region(&acpi_gbl_FADT->xgpe0_blk, - acpi_gbl_FADT->gpe0_blk_len, "ACPI GPE0_BLK"); + if (!(acpi_gbl_FADT.gpe0_block_length & 0x1)) + acpi_request_region(&acpi_gbl_FADT.xgpe0_block, + acpi_gbl_FADT.gpe0_block_length, "ACPI GPE0_BLK"); - if (!(acpi_gbl_FADT->gpe1_blk_len & 0x1)) - acpi_request_region(&acpi_gbl_FADT->xgpe1_blk, - acpi_gbl_FADT->gpe1_blk_len, "ACPI GPE1_BLK"); + if (!(acpi_gbl_FADT.gpe1_block_length & 0x1)) + acpi_request_region(&acpi_gbl_FADT.xgpe1_block, + acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK"); } static int __init acpi_motherboard_init(void) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 57ae1e5cde0a..c1c2100fe133 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -136,53 +137,43 @@ void acpi_os_vprintf(const char *fmt, va_list args) #endif } -acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr) +acpi_physical_address __init acpi_os_get_root_pointer(void) { if (efi_enabled) { - addr->pointer_type = ACPI_PHYSICAL_POINTER; if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) - addr->pointer.physical = efi.acpi20; + return efi.acpi20; else if (efi.acpi != EFI_INVALID_TABLE_ADDR) - addr->pointer.physical = efi.acpi; + return efi.acpi; else { printk(KERN_ERR PREFIX "System description tables not found\n"); - return AE_NOT_FOUND; + return 0; } - } else { - if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) { - printk(KERN_ERR PREFIX - "System description tables not found\n"); - return AE_NOT_FOUND; - } - } - - return AE_OK; + } else + return acpi_find_rsdp(); } -acpi_status -acpi_os_map_memory(acpi_physical_address phys, acpi_size size, - void __iomem ** virt) +void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size) { if (phys > ULONG_MAX) { printk(KERN_ERR PREFIX "Cannot map memory that high\n"); - return AE_BAD_PARAMETER; + return 0; } - /* - * ioremap checks to ensure this is in reserved space - */ - *virt = ioremap((unsigned long)phys, size); - - if (!*virt) - return AE_NO_MEMORY; - - return AE_OK; + if (acpi_gbl_permanent_mmap) + /* + * ioremap checks to ensure this is in reserved space + */ + return ioremap((unsigned long)phys, size); + else + return __acpi_map_table((unsigned long)phys, size); } EXPORT_SYMBOL_GPL(acpi_os_map_memory); void acpi_os_unmap_memory(void __iomem * virt, acpi_size size) { - iounmap(virt); + if (acpi_gbl_permanent_mmap) { + iounmap(virt); + } } EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 5f9496d59ed6..4d552f7caa91 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -431,7 +431,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr) * Check to see if we have bus mastering arbitration control. This * is required for proper C3 usage (to maintain cache coherency). */ - if (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len) { + if (acpi_fadt.pm2_control_block && acpi_fadt.pm2_control_length) { pr->flags.bm_control = 1; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Bus mastering arbitration control present\n")); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 3f30af21574e..9fa3d3965bb3 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -160,7 +160,7 @@ static inline u32 ticks_elapsed(u32 t1, u32 t2) { if (t2 >= t1) return (t2 - t1); - else if (!acpi_fadt.tmr_val_ext) + else if (!(acpi_fadt.flags & ACPI_FADT_32BIT_TIMER)) return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF); else return ((0xFFFFFFFF - t1) + t2); @@ -236,7 +236,7 @@ static void acpi_cstate_enter(struct acpi_processor_cx *cstate) /* Dummy wait op - must do something useless after P_LVL2 read because chipsets cannot guarantee that STPCLK# signal gets asserted in time to freeze execution properly. */ - unused = inl(acpi_fadt.xpm_tmr_blk.address); + unused = inl(acpi_fadt.xpm_timer_block.address); } } @@ -338,7 +338,7 @@ static void acpi_processor_idle(void) * detection phase, to work cleanly with logical CPU hotplug. */ if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && - !pr->flags.has_cst && !acpi_fadt.plvl2_up) + !pr->flags.has_cst && !(acpi_fadt.flags & ACPI_FADT_C2_MP_SUPPORTED)) cx = &pr->power.states[ACPI_STATE_C1]; #endif @@ -384,11 +384,11 @@ static void acpi_processor_idle(void) case ACPI_STATE_C2: /* Get start time (ticks) */ - t1 = inl(acpi_fadt.xpm_tmr_blk.address); + t1 = inl(acpi_fadt.xpm_timer_block.address); /* Invoke C2 */ acpi_cstate_enter(cx); /* Get end time (ticks) */ - t2 = inl(acpi_fadt.xpm_tmr_blk.address); + t2 = inl(acpi_fadt.xpm_timer_block.address); #ifdef CONFIG_GENERIC_TIME /* TSC halts in C2, so notify users */ @@ -420,11 +420,11 @@ static void acpi_processor_idle(void) } /* Get start time (ticks) */ - t1 = inl(acpi_fadt.xpm_tmr_blk.address); + t1 = inl(acpi_fadt.xpm_timer_block.address); /* Invoke C3 */ acpi_cstate_enter(cx); /* Get end time (ticks) */ - t2 = inl(acpi_fadt.xpm_tmr_blk.address); + t2 = inl(acpi_fadt.xpm_timer_block.address); if (pr->flags.bm_check) { /* Enable bus master arbitration */ atomic_dec(&c3_cpu_count); @@ -457,7 +457,7 @@ static void acpi_processor_idle(void) #ifdef CONFIG_HOTPLUG_CPU /* Don't do promotion/demotion */ if ((cx->type == ACPI_STATE_C1) && (num_online_cpus() > 1) && - !pr->flags.has_cst && !acpi_fadt.plvl2_up) { + !pr->flags.has_cst && !(acpi_fadt.flags & ACPI_FADT_C2_MP_SUPPORTED)) { next_state = cx; goto end; } @@ -627,7 +627,8 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) * Check for P_LVL2_UP flag before entering C2 and above on * an SMP system. */ - if ((num_online_cpus() > 1) && !acpi_fadt.plvl2_up) + if ((num_online_cpus() > 1) && + !(acpi_fadt.flags & ACPI_FADT_C2_MP_SUPPORTED)) return -ENODEV; #endif @@ -636,8 +637,8 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) pr->power.states[ACPI_STATE_C3].address = pr->pblk + 5; /* determine latencies from FADT */ - pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat; - pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat; + pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.C2latency; + pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.C3latency; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "lvl2[0x%08x] lvl3[0x%08x]\n", @@ -883,7 +884,7 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, * WBINVD should be set in fadt, for C3 state to be * supported on when bm_check is not required. */ - if (acpi_fadt.wb_invd != 1) { + if (!(acpi_fadt.flags & ACPI_FADT_WBINVD)) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cache invalidation should work properly" " for C3 to be enabled on SMP systems\n")); @@ -1164,9 +1165,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, if (!pr) return -EINVAL; - if (acpi_fadt.cst_cnt && !nocst) { + if (acpi_fadt.cst_control && !nocst) { status = - acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8); + acpi_os_write_port(acpi_fadt.smi_command, acpi_fadt.cst_control, 8); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Notifying BIOS of _CST ability failed")); diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index cbb6f0814ce2..aabb98832ba6 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -352,31 +352,24 @@ int acpi_processor_notify_smm(struct module *calling_module) is_done = -EIO; - /* Can't write pstate_cnt to smi_cmd if either value is zero */ - if ((!acpi_fadt.smi_cmd) || (!acpi_fadt.pstate_cnt)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_cnt\n")); + /* Can't write pstate_control to smi_command if either value is zero */ + if ((!acpi_fadt.smi_command) || (!acpi_fadt.pstate_control)) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n")); module_put(calling_module); return 0; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n", - acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd)); + "Writing pstate_control [0x%x] to smi_command [0x%x]\n", + acpi_fadt.pstate_control, acpi_fadt.smi_command)); - /* FADT v1 doesn't support pstate_cnt, many BIOS vendors use - * it anyway, so we need to support it... */ - if (acpi_fadt_is_v1) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Using v1.0 FADT reserved value for pstate_cnt\n")); - } - - status = acpi_os_write_port(acpi_fadt.smi_cmd, - (u32) acpi_fadt.pstate_cnt, 8); + status = acpi_os_write_port(acpi_fadt.smi_command, + (u32) acpi_fadt.pstate_control, 8); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "Failed to write pstate_cnt [0x%x] to " - "smi_cmd [0x%x]", acpi_fadt.pstate_cnt, - acpi_fadt.smi_cmd)); + "Failed to write pstate_control [0x%x] to " + "smi_command [0x%x]", acpi_fadt.pstate_control, + acpi_fadt.smi_command)); module_put(calling_module); return status; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 283d87522c5d..b1692b18c9d7 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1333,7 +1333,7 @@ static int acpi_bus_scan_fixed(struct acpi_device *root) /* * Enumerate all fixed-feature devices. */ - if (acpi_fadt.pwr_button == 0) { + if ((acpi_fadt.flags & ACPI_FADT_POWER_BUTTON) == 0) { result = acpi_add_single_object(&device, acpi_root, NULL, ACPI_BUS_TYPE_POWER_BUTTON); @@ -1341,7 +1341,7 @@ static int acpi_bus_scan_fixed(struct acpi_device *root) result = acpi_start_single_object(device); } - if (acpi_fadt.sleep_button == 0) { + if ((acpi_fadt.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { result = acpi_add_single_object(&device, acpi_root, NULL, ACPI_BUS_TYPE_SLEEP_BUTTON); diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index 34962578039d..ccc11b33d89c 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -73,7 +73,7 @@ acpi_system_write_sleep(struct file *file, static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) { u32 sec, min, hr; - u32 day, mo, yr; + u32 day, mo, yr, cent = 0; unsigned char rtc_control = 0; unsigned long flags; @@ -87,20 +87,19 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) rtc_control = CMOS_READ(RTC_CONTROL); /* If we ever get an FACP with proper values... */ - if (acpi_gbl_FADT->day_alrm) + if (acpi_gbl_FADT.day_alarm) /* ACPI spec: only low 6 its should be cared */ - day = CMOS_READ(acpi_gbl_FADT->day_alrm) & 0x3F; + day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F; else day = CMOS_READ(RTC_DAY_OF_MONTH); - if (acpi_gbl_FADT->mon_alrm) - mo = CMOS_READ(acpi_gbl_FADT->mon_alrm); + if (acpi_gbl_FADT.month_alarm) + mo = CMOS_READ(acpi_gbl_FADT.month_alarm); else mo = CMOS_READ(RTC_MONTH); - if (acpi_gbl_FADT->century) - yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + - CMOS_READ(RTC_YEAR); - else - yr = CMOS_READ(RTC_YEAR); + if (acpi_gbl_FADT.century) + cent = CMOS_READ(acpi_gbl_FADT.century); + + yr = CMOS_READ(RTC_YEAR); spin_unlock_irqrestore(&rtc_lock, flags); @@ -111,10 +110,11 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) BCD_TO_BIN(day); BCD_TO_BIN(mo); BCD_TO_BIN(yr); + BCD_TO_BIN(cent); } /* we're trusting the FADT (see above) */ - if (!acpi_gbl_FADT->century) + if (!acpi_gbl_FADT.century) /* If we're not trusting the FADT, we should at least make it * right for _this_ century... ehm, what is _this_ century? * @@ -134,6 +134,8 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) * */ yr += 2000; + else + yr += cent * 100; seq_printf(seq, "%4.4u-", yr); (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo); @@ -317,12 +319,12 @@ acpi_system_write_alarm(struct file *file, * offsets into the CMOS RAM here -- which for some reason are pointing * to the RTC area of memory. */ - if (acpi_gbl_FADT->day_alrm) - CMOS_WRITE(day, acpi_gbl_FADT->day_alrm); - if (acpi_gbl_FADT->mon_alrm) - CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm); - if (acpi_gbl_FADT->century) - CMOS_WRITE(yr / 100, acpi_gbl_FADT->century); + if (acpi_gbl_FADT.day_alarm) + CMOS_WRITE(day, acpi_gbl_FADT.day_alarm); + if (acpi_gbl_FADT.month_alarm) + CMOS_WRITE(mo, acpi_gbl_FADT.month_alarm); + if (acpi_gbl_FADT.century) + CMOS_WRITE(yr / 100, acpi_gbl_FADT.century); /* enable the rtc alarm interrupt */ rtc_control |= RTC_AIE; CMOS_WRITE(rtc_control, RTC_CONTROL); diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index d86dcb3c2366..2d425d845821 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -39,7 +39,6 @@ ACPI_MODULE_NAME("acpi_system") #define ACPI_SYSTEM_FILE_EVENT "event" #define ACPI_SYSTEM_FILE_DSDT "dsdt" #define ACPI_SYSTEM_FILE_FADT "fadt" -extern struct fadt_descriptor acpi_fadt; /* -------------------------------------------------------------------------- FS Interface (/proc) @@ -76,17 +75,16 @@ acpi_system_read_dsdt(struct file *file, char __user * buffer, size_t count, loff_t * ppos) { acpi_status status = AE_OK; - struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_table_header *dsdt = NULL; ssize_t res; - status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt); + status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt); if (ACPI_FAILURE(status)) return -ENODEV; res = simple_read_from_buffer(buffer, count, ppos, - dsdt.pointer, dsdt.length); - kfree(dsdt.pointer); + dsdt, dsdt->length); return res; } @@ -103,17 +101,16 @@ acpi_system_read_fadt(struct file *file, char __user * buffer, size_t count, loff_t * ppos) { acpi_status status = AE_OK; - struct acpi_buffer fadt = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_table_header *fadt = NULL; ssize_t res; - status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &fadt); + status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt); if (ACPI_FAILURE(status)) return -ENODEV; res = simple_read_from_buffer(buffer, count, ppos, - fadt.pointer, fadt.length); - kfree(fadt.pointer); + fadt, fadt->length); return res; } diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index ffa30c9fccbf..5bb143151169 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -74,6 +74,7 @@ static unsigned long sdt_pa; /* Physical Address */ static unsigned long sdt_count; /* Table count */ static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES] __initdata; +static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; void acpi_table_print(struct acpi_table_header *header, unsigned long phys_addr) { @@ -284,12 +285,12 @@ acpi_get_table_header_early(enum acpi_table_id id, struct fadt_descriptor *fadt = (struct fadt_descriptor *)*header; - if (fadt->revision == 3 && fadt->Xdsdt) { + if (fadt->header.revision == 3 && fadt->Xdsdt) { *header = (void *)__acpi_map_table(fadt->Xdsdt, sizeof(struct acpi_table_header)); - } else if (fadt->V1_dsdt) { - *header = (void *)__acpi_map_table(fadt->V1_dsdt, + } else if (fadt->dsdt) { + *header = (void *)__acpi_map_table(fadt->dsdt, sizeof(struct acpi_table_header)); } else @@ -410,12 +411,11 @@ static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp) /* First check XSDT (but only on ACPI 2.0-compatible systems) */ - if ((rsdp->revision >= 2) && - (((struct acpi20_table_rsdp *)rsdp)->xsdt_address)) { + if ((rsdp->revision >= 2) && rsdp->xsdt_physical_address) { struct acpi_table_xsdt *mapped_xsdt = NULL; - sdt_pa = ((struct acpi20_table_rsdp *)rsdp)->xsdt_address; + sdt_pa = rsdp->xsdt_physical_address; /* map in just the header */ header = (struct acpi_table_header *) @@ -457,16 +457,16 @@ static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp) } for (i = 0; i < sdt_count; i++) - sdt_entry[i].pa = (unsigned long)mapped_xsdt->entry[i]; + sdt_entry[i].pa = (unsigned long)mapped_xsdt->table_offset_entry[i]; } /* Then check RSDT */ - else if (rsdp->rsdt_address) { + else if (rsdp->rsdt_physical_address) { struct acpi_table_rsdt *mapped_rsdt = NULL; - sdt_pa = rsdp->rsdt_address; + sdt_pa = rsdp->rsdt_physical_address; /* map in just the header */ header = (struct acpi_table_header *) @@ -507,7 +507,7 @@ static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp) } for (i = 0; i < sdt_count; i++) - sdt_entry[i].pa = (unsigned long)mapped_rsdt->entry[i]; + sdt_entry[i].pa = (unsigned long)mapped_rsdt->table_offset_entry[i]; } else { @@ -599,13 +599,10 @@ int __init acpi_table_init(void) if (rsdp->revision < 2) result = - acpi_table_compute_checksum(rsdp, - sizeof(struct acpi_table_rsdp)); + acpi_table_compute_checksum(rsdp, ACPI_RSDP_REV0_SIZE); else result = - acpi_table_compute_checksum(rsdp, - ((struct acpi20_table_rsdp *) - rsdp)->length); + acpi_table_compute_checksum(rsdp, rsdp->length); if (result) { printk(KERN_WARNING " >>> ERROR: Invalid checksum\n"); @@ -617,5 +614,7 @@ int __init acpi_table_init(void) if (acpi_table_get_sdt(rsdp)) return -ENODEV; + acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); + return 0; } diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile index aa4c69594d97..f08f1f310274 100644 --- a/drivers/acpi/tables/Makefile +++ b/drivers/acpi/tables/Makefile @@ -2,7 +2,6 @@ # Makefile for all Linux ACPI interpreter subdirectories # -obj-y := tbconvrt.o tbget.o tbrsdt.o tbxface.o \ - tbgetall.o tbinstal.o tbutils.o tbxfroot.o +obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index 8e44f83a64e2..6d13737f3f89 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c @@ -545,7 +545,7 @@ acpi_tb_get_root_table_entry(u8 * table_entry, * ******************************************************************************/ -acpi_status +acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags) { struct acpi_table_rsdp *rsdp; diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 13e8d6626dd4..94544a60640d 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -78,7 +78,7 @@ static acpi_status acpi_tb_load_namespace(void); * ******************************************************************************/ -acpi_status +acpi_status __init acpi_initialize_tables(struct acpi_table_desc *initial_table_array, u32 initial_table_count, u8 allow_resize) { @@ -132,8 +132,6 @@ acpi_initialize_tables(struct acpi_table_desc *initial_table_array, return_ACPI_STATUS(status); } -ACPI_EXPORT_SYMBOL(acpi_initialize_tables) - /******************************************************************************* * * FUNCTION: acpi_reallocate_root_table @@ -365,6 +363,10 @@ acpi_get_table(char *signature, *out_table = acpi_gbl_root_table_list.tables[i].pointer; } + if (!acpi_gbl_permanent_mmap) { + acpi_gbl_root_table_list.tables[i].pointer = 0; + } + return (status); } diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h index 82d42b82594a..bd0fe7c6b384 100644 --- a/include/acpi/acglobal.h +++ b/include/acpi/acglobal.h @@ -147,6 +147,8 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE); */ ACPI_EXTERN struct acpi_internal_rsdt acpi_gbl_root_table_list; ACPI_EXTERN struct acpi_table_fadt acpi_gbl_FADT; +#define acpi_fadt acpi_gbl_FADT +extern acpi_native_uint acpi_gbl_permanent_mmap; /* * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index fdd10953b2b6..aef0e55253a9 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -59,7 +59,6 @@ acpi_evaluate_reference(acpi_handle handle, #define ACPI_BUS_FILE_ROOT "acpi" extern struct proc_dir_entry *acpi_root_dir; -extern struct fadt_descriptor acpi_fadt; enum acpi_bus_removal_type { ACPI_BUS_REMOVAL_NORMAL = 0, diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index aed49a5d5838..6f63b3bbc3fb 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -236,6 +236,9 @@ struct acpi_table_fadt { struct acpi_generic_address xgpe1_block; /* 64-bit Extended General Purpose Event 1 Reg Blk address */ }; +#define fadt_descriptor acpi_table_fadt +#define sci_int sci_interrupt + /* FADT flags */ #define ACPI_FADT_WBINVD (1) /* 00: The wbinvd instruction works properly */ @@ -289,6 +292,8 @@ enum acpi_prefered_pm_profiles { /* * Get the remaining ACPI tables */ +/* + Don't include any new tables definitions for now. #include - +*/ #endif /* __ACTBL_H__ */ diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h deleted file mode 100644 index 67efe6cad27b..000000000000 --- a/include/acpi/actbl2.h +++ /dev/null @@ -1,49 +0,0 @@ -/****************************************************************************** - * - * Name: actbl2.h - ACPI Specification Revision 2.0 Tables - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2006, R. Byron Moore - * 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 at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * 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 MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. - */ - -#ifndef __ACTBL2_H__ -#define __ACTBL2_H__ - -/* Code moved to both actbl.h and actbl1.h */ - -#endif /* __ACTBL2_H__ */ diff --git a/include/acpi/actbl71.h b/include/acpi/actbl71.h deleted file mode 100644 index 10ac05bb36bc..000000000000 --- a/include/acpi/actbl71.h +++ /dev/null @@ -1,134 +0,0 @@ -/****************************************************************************** - * - * Name: actbl71.h - IA-64 Extensions to the ACPI Spec Rev. 0.71 - * This file includes tables specific to this - * specification revision. - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2003, R. Byron Moore - * - * 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 __ACTBL71_H__ -#define __ACTBL71_H__ - -/* 0.71 FADT address_space data item bitmasks defines */ -/* If the associated bit is zero then it is in memory space else in io space */ - -#define SMI_CMD_ADDRESS_SPACE 0x01 -#define PM1_BLK_ADDRESS_SPACE 0x02 -#define PM2_CNT_BLK_ADDRESS_SPACE 0x04 -#define PM_TMR_BLK_ADDRESS_SPACE 0x08 -#define GPE0_BLK_ADDRESS_SPACE 0x10 -#define GPE1_BLK_ADDRESS_SPACE 0x20 - -/* Only for clarity in declarations */ - -typedef u64 IO_ADDRESS; - -#pragma pack(1) -struct { /* Root System Descriptor Pointer */ - NATIVE_CHAR signature[8]; /* contains "RSD PTR " */ - u8 checksum; /* to make sum of struct == 0 */ - NATIVE_CHAR oem_id[6]; /* OEM identification */ - u8 reserved; /* Must be 0 for 1.0, 2 for 2.0 */ - u64 rsdt_physical_address; /* 64-bit physical address of RSDT */ -}; - -/*****************************************/ -/* IA64 Extensions to ACPI Spec Rev 0.71 */ -/* for the Root System Description Table */ -/*****************************************/ -struct { - struct acpi_table_header header; /* Table header */ - u32 reserved_pad; /* IA64 alignment, must be 0 */ - u64 table_offset_entry[1]; /* Array of pointers to other */ - /* tables' headers */ -}; - -/*******************************************/ -/* IA64 Extensions to ACPI Spec Rev 0.71 */ -/* for the Firmware ACPI Control Structure */ -/*******************************************/ -struct { - NATIVE_CHAR signature[4]; /* signature "FACS" */ - u32 length; /* length of structure, in bytes */ - u32 hardware_signature; /* hardware configuration signature */ - u32 reserved4; /* must be 0 */ - u64 firmware_waking_vector; /* ACPI OS waking vector */ - u64 global_lock; /* Global Lock */ - u32 S4bios_f:1; /* Indicates if S4BIOS support is present */ - u32 reserved1:31; /* must be 0 */ - u8 reserved3[28]; /* reserved - must be zero */ -}; - -/******************************************/ -/* IA64 Extensions to ACPI Spec Rev 0.71 */ -/* for the Fixed ACPI Description Table */ -/******************************************/ -struct { - struct acpi_table_header header; /* table header */ - u32 reserved_pad; /* IA64 alignment, must be 0 */ - u64 firmware_ctrl; /* 64-bit Physical address of FACS */ - u64 dsdt; /* 64-bit Physical address of DSDT */ - u8 model; /* System Interrupt Model */ - u8 address_space; /* Address Space Bitmask */ - u16 sci_int; /* System vector of SCI interrupt */ - u8 acpi_enable; /* value to write to smi_cmd to enable ACPI */ - u8 acpi_disable; /* value to write to smi_cmd to disable ACPI */ - u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ - u8 reserved2; /* reserved - must be zero */ - u64 smi_cmd; /* Port address of SMI command port */ - u64 pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ - u64 pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ - u64 pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ - u64 pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ - u64 pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ - u64 pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ - u64 gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ - u64 gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ - u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ - u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ - u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ - u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ - u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ - u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ - u8 gpe1_base; /* offset in gpe model where gpe1 events start */ - u8 reserved3; /* reserved */ - u16 plvl2_lat; /* worst case HW latency to enter/exit C2 state */ - u16 plvl3_lat; /* worst case HW latency to enter/exit C3 state */ - u8 day_alrm; /* index to day-of-month alarm in RTC CMOS RAM */ - u8 mon_alrm; /* index to month-of-year alarm in RTC CMOS RAM */ - u8 century; /* index to century in RTC CMOS RAM */ - u8 reserved4; /* reserved */ - u32 flush_cash:1; /* PAL_FLUSH_CACHE is correctly supported */ - u32 reserved5:1; /* reserved - must be zero */ - u32 proc_c1:1; /* all processors support C1 state */ - u32 plvl2_up:1; /* C2 state works on MP system */ - u32 pwr_button:1; /* Power button is handled as a generic feature */ - u32 sleep_button:1; /* Sleep button is handled as a generic feature, or not present */ - u32 fixed_rTC:1; /* RTC wakeup stat not in fixed register space */ - u32 rtcs4:1; /* RTC wakeup stat not possible from S4 */ - u32 tmr_val_ext:1; /* tmr_val is 32 bits */ - u32 dock_cap:1; /* Supports Docking */ - u32 reserved6:22; /* reserved - must be zero */ -}; - -#pragma pack() - -#endif /* __ACTBL71_H__ */ diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h index 7cfad93edf10..0fb0c016db73 100644 --- a/include/asm-i386/acpi.h +++ b/include/asm-i386/acpi.h @@ -59,11 +59,11 @@ int __acpi_acquire_global_lock(unsigned int *lock); int __acpi_release_global_lock(unsigned int *lock); -#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ - ((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr)) +#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \ + ((Acq) = __acpi_acquire_global_lock(&facs->global_lock)) -#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ - ((Acq) = __acpi_release_global_lock((unsigned int *) GLptr)) +#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \ + ((Acq) = __acpi_release_global_lock(&facs->global_lock)) /* * Math helper asm macros diff --git a/include/asm-ia64/acpi.h b/include/asm-ia64/acpi.h index 09a5dd0e44a8..dba34d5a0920 100644 --- a/include/asm-ia64/acpi.h +++ b/include/asm-ia64/acpi.h @@ -82,11 +82,11 @@ ia64_acpi_release_global_lock (unsigned int *lock) return old & 0x1; } -#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ - ((Acq) = ia64_acpi_acquire_global_lock((unsigned int *) GLptr)) +#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \ + ((Acq) = ia64_acpi_acquire_global_lock(&facs->global_lock)) -#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ - ((Acq) = ia64_acpi_release_global_lock((unsigned int *) GLptr)) +#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \ + ((Acq) = ia64_acpi_release_global_lock(&facs->global_lock)) #define acpi_disabled 0 /* ACPI always enabled on IA64 */ #define acpi_noirq 0 /* ACPI always enabled on IA64 */ diff --git a/include/asm-ia64/sn/acpi.h b/include/asm-ia64/sn/acpi.h deleted file mode 100644 index 2850a7ef5e71..000000000000 --- a/include/asm-ia64/sn/acpi.h +++ /dev/null @@ -1,16 +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) 2006 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_ACPI_H -#define _ASM_IA64_SN_ACPI_H - -#include "acpi/acglobal.h" - -#define SN_ACPI_BASE_SUPPORT() (acpi_gbl_DSDT->oem_revision >= 0x20101) - -#endif /* _ASM_IA64_SN_ACPI_H */ diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h index 6b6fc6f8be7e..49f92f3cc32d 100644 --- a/include/asm-x86_64/acpi.h +++ b/include/asm-x86_64/acpi.h @@ -57,11 +57,11 @@ int __acpi_acquire_global_lock(unsigned int *lock); int __acpi_release_global_lock(unsigned int *lock); -#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ - ((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr)) +#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \ + ((Acq) = __acpi_acquire_global_lock(&facs->global_lock)) -#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ - ((Acq) = __acpi_release_global_lock((unsigned int *) GLptr)) +#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \ + ((Acq) = __acpi_release_global_lock(&facs->global_lock)) /* * Math helper asm macros diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 91f1f2363870..b3e8a268f6d6 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -53,57 +53,11 @@ enum acpi_irq_model_id { extern enum acpi_irq_model_id acpi_irq_model; - -/* Root System Description Pointer (RSDP) */ - -struct acpi_table_rsdp { - char signature[8]; - u8 checksum; - char oem_id[6]; - u8 revision; - u32 rsdt_address; -} __attribute__ ((packed)); - -struct acpi20_table_rsdp { - char signature[8]; - u8 checksum; - char oem_id[6]; - u8 revision; - u32 rsdt_address; - u32 length; - u64 xsdt_address; - u8 ext_checksum; - u8 reserved[3]; -} __attribute__ ((packed)); - typedef struct { u8 type; u8 length; } __attribute__ ((packed)) acpi_table_entry_header; -/* Root System Description Table (RSDT) */ - -struct acpi_table_rsdt { - struct acpi_table_header header; - u32 entry[8]; -} __attribute__ ((packed)); - -/* Extended System Description Table (XSDT) */ - -struct acpi_table_xsdt { - struct acpi_table_header header; - u64 entry[1]; -} __attribute__ ((packed)); - -/* Fixed ACPI Description Table (FADT) */ - -struct acpi_table_fadt { - struct acpi_table_header header; - u32 facs_addr; - u32 dsdt_addr; - /* ... */ -} __attribute__ ((packed)); - /* Multiple APIC Description Table (MADT) */ struct acpi_table_madt { -- cgit v1.2.3 From ceb6c46839021d5c7c338d48deac616944660124 Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Fri, 2 Feb 2007 19:48:22 +0300 Subject: ACPICA: Remove duplicate table manager Signed-off-by: Len Brown --- arch/i386/kernel/acpi/boot.c | 40 ++-- arch/i386/kernel/acpi/earlyquirk.c | 4 +- arch/i386/mach-es7000/es7000.h | 9 - arch/i386/mach-es7000/es7000plat.c | 53 +---- arch/i386/pci/mmconfig.c | 2 +- drivers/acpi/tables.c | 396 ++----------------------------------- include/linux/acpi.h | 7 +- 7 files changed, 50 insertions(+), 461 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 9adabc4dba70..543eac5da176 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -169,16 +169,16 @@ char *__acpi_map_table(unsigned long phys, unsigned long size) struct acpi_table_mcfg_config *pci_mmcfg_config; int pci_mmcfg_config_num; -int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) +int __init acpi_parse_mcfg(struct acpi_table_header *header) { struct acpi_table_mcfg *mcfg; unsigned long i; int config_size; - if (!phys_addr || !size) + if (!header) return -EINVAL; - mcfg = (struct acpi_table_mcfg *)__acpi_map_table(phys_addr, size); + mcfg = (struct acpi_table_mcfg *)header; if (!mcfg) { printk(KERN_WARNING PREFIX "Unable to map MCFG\n"); return -ENODEV; @@ -186,7 +186,7 @@ int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) /* how many config structures do we have */ pci_mmcfg_config_num = 0; - i = size - sizeof(struct acpi_table_mcfg); + i = header->length - sizeof(struct acpi_table_mcfg); while (i >= sizeof(struct acpi_table_mcfg_config)) { ++pci_mmcfg_config_num; i -= sizeof(struct acpi_table_mcfg_config); @@ -220,14 +220,14 @@ int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) #endif /* CONFIG_PCI_MMCONFIG */ #ifdef CONFIG_X86_LOCAL_APIC -static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size) +static int __init acpi_parse_madt(struct acpi_table_header *header) { struct acpi_table_madt *madt = NULL; - if (!phys_addr || !size || !cpu_has_apic) + if (!header|| !cpu_has_apic) return -EINVAL; - madt = (struct acpi_table_madt *)__acpi_map_table(phys_addr, size); + madt = (struct acpi_table_madt *)header; if (!madt) { printk(KERN_WARNING PREFIX "Unable to map MADT\n"); return -ENODEV; @@ -619,14 +619,14 @@ acpi_scan_rsdp(unsigned long start, unsigned long length) return 0; } -static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size) +static int __init acpi_parse_sbf(struct acpi_table_header *header) { struct acpi_table_sbf *sb; - if (!phys_addr || !size) + if (!header) return -EINVAL; - sb = (struct acpi_table_sbf *)__acpi_map_table(phys_addr, size); + sb = (struct acpi_table_sbf *)header; if (!sb) { printk(KERN_WARNING PREFIX "Unable to map SBF\n"); return -ENODEV; @@ -639,16 +639,16 @@ static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size) #ifdef CONFIG_HPET_TIMER -static int __init acpi_parse_hpet(unsigned long phys, unsigned long size) +static int __init acpi_parse_hpet(struct acpi_table_header *header) { struct acpi_table_hpet *hpet_tbl; struct resource *hpet_res; resource_size_t res_start; - if (!phys || !size) + if (!header) return -EINVAL; - hpet_tbl = (struct acpi_table_hpet *)__acpi_map_table(phys, size); + hpet_tbl = (struct acpi_table_hpet *)header; if (!hpet_tbl) { printk(KERN_WARNING PREFIX "Unable to map HPET\n"); return -ENODEV; @@ -707,11 +707,11 @@ static int __init acpi_parse_hpet(unsigned long phys, unsigned long size) extern u32 pmtmr_ioport; #endif -static int __init acpi_parse_fadt(unsigned long phys, unsigned long size) +static int __init acpi_parse_fadt(struct acpi_table_header *header) { struct fadt_descriptor *fadt = NULL; - fadt = (struct fadt_descriptor *)__acpi_map_table(phys, size); + fadt = (struct fadt_descriptor *)header; if (!fadt) { printk(KERN_WARNING PREFIX "Unable to map FADT\n"); return 0; @@ -901,7 +901,7 @@ static void __init acpi_process_madt(void) #ifdef CONFIG_X86_LOCAL_APIC int count, error; - count = acpi_table_parse(ACPI_APIC, acpi_parse_madt); + count = acpi_table_parse("APIC", acpi_parse_madt); if (count >= 1) { /* @@ -1197,7 +1197,7 @@ int __init acpi_boot_table_init(void) return error; } - acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); + acpi_table_parse("BOOT", acpi_parse_sbf); /* * blacklist may disable ACPI entirely @@ -1225,19 +1225,19 @@ int __init acpi_boot_init(void) if (acpi_disabled && !acpi_ht) return 1; - acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); + acpi_table_parse("BOOT", acpi_parse_sbf); /* * set sci_int and PM timer address */ - acpi_table_parse(ACPI_FADT, acpi_parse_fadt); + acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt); /* * Process the Multiple APIC Description Table (MADT), if present */ acpi_process_madt(); - acpi_table_parse(ACPI_HPET, acpi_parse_hpet); + acpi_table_parse("HPET", acpi_parse_hpet); return 0; } diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c index 4b60af7f91dd..4261c8501b7e 100644 --- a/arch/i386/kernel/acpi/earlyquirk.c +++ b/arch/i386/kernel/acpi/earlyquirk.c @@ -16,7 +16,7 @@ static int nvidia_hpet_detected __initdata; -static int __init nvidia_hpet_check(unsigned long phys, unsigned long size) +static int __init nvidia_hpet_check(struct acpi_table_header *header) { nvidia_hpet_detected = 1; return 0; @@ -30,7 +30,7 @@ static int __init check_bridge(int vendor, int device) is enabled. */ if (!acpi_use_timer_override && vendor == PCI_VENDOR_ID_NVIDIA) { nvidia_hpet_detected = 0; - acpi_table_parse(ACPI_HPET, nvidia_hpet_check); + acpi_table_parse("HPET", nvidia_hpet_check); if (nvidia_hpet_detected == 0) { acpi_skip_timer_override = 1; printk(KERN_INFO "Nvidia board " diff --git a/arch/i386/mach-es7000/es7000.h b/arch/i386/mach-es7000/es7000.h index 80566ca4a80a..c8d5aa132fa0 100644 --- a/arch/i386/mach-es7000/es7000.h +++ b/arch/i386/mach-es7000/es7000.h @@ -84,15 +84,6 @@ struct es7000_oem_table { }; #ifdef CONFIG_ACPI -struct acpi_table_sdt { - unsigned long pa; - unsigned long count; - struct { - unsigned long pa; - enum acpi_table_id id; - unsigned long size; - } entry[50]; -}; struct oem_table { struct acpi_table_header Header; diff --git a/arch/i386/mach-es7000/es7000plat.c b/arch/i386/mach-es7000/es7000plat.c index 3d0fc853516d..9be6ceabf042 100644 --- a/arch/i386/mach-es7000/es7000plat.c +++ b/arch/i386/mach-es7000/es7000plat.c @@ -160,51 +160,14 @@ parse_unisys_oem (char *oemptr) int __init find_unisys_acpi_oem_table(unsigned long *oem_addr) { - struct acpi_table_rsdp *rsdp = NULL; - unsigned long rsdp_phys = 0; - struct acpi_table_header *header = NULL; - int i; - struct acpi_table_sdt sdt; - - rsdp_phys = acpi_find_rsdp(); - rsdp = __va(rsdp_phys); - if (rsdp->rsdt_address) { - struct acpi_table_rsdt *mapped_rsdt = NULL; - sdt.pa = rsdp->rsdt_address; - - header = (struct acpi_table_header *) - __acpi_map_table(sdt.pa, sizeof(struct acpi_table_header)); - if (!header) - return -ENODEV; - - sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 3; - mapped_rsdt = (struct acpi_table_rsdt *) - __acpi_map_table(sdt.pa, header->length); - if (!mapped_rsdt) - return -ENODEV; - - header = &mapped_rsdt->header; - - for (i = 0; i < sdt.count; i++) - sdt.entry[i].pa = (unsigned long) mapped_rsdt->entry[i]; - }; - for (i = 0; i < sdt.count; i++) { - - header = (struct acpi_table_header *) - __acpi_map_table(sdt.entry[i].pa, - sizeof(struct acpi_table_header)); - if (!header) - continue; - if (!strncmp((char *) &header->signature, "OEM1", 4)) { - if (!strncmp((char *) &header->oem_id, "UNISYS", 6)) { - void *addr; - struct oem_table *t; - acpi_table_print(header, sdt.entry[i].pa); - t = (struct oem_table *) __acpi_map_table(sdt.entry[i].pa, header->length); - addr = (void *) __acpi_map_table(t->OEMTableAddr, t->OEMTableSize); - *oem_addr = (unsigned long) addr; - return 0; - } + struct acpi_table_header *header = NULL; + int i = 0; + while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) { + if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) { + struct oem_table *t = (struct oem_table *)header; + *oem_addr = (unsigned long)__acpi_map_table(t->OEMTableAddr, + t->OEMTableSize); + return 0; } } return -1; diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index e2616a266e13..80522e331e34 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c @@ -199,7 +199,7 @@ void __init pci_mmcfg_init(int type) if ((pci_probe & PCI_PROBE_MMCONF) == 0) return; - acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); + acpi_table_parse("MCFG", acpi_parse_mcfg); if ((pci_mmcfg_config_num == 0) || (pci_mmcfg_config == NULL) || (pci_mmcfg_config[0].base_address == 0)) diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 5bb143151169..962ff29fbf07 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -38,71 +38,11 @@ #define ACPI_MAX_TABLES 128 -static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { - [ACPI_TABLE_UNKNOWN] = "????", - [ACPI_APIC] = "APIC", - [ACPI_BOOT] = "BOOT", - [ACPI_DBGP] = "DBGP", - [ACPI_DSDT] = "DSDT", - [ACPI_ECDT] = "ECDT", - [ACPI_ETDT] = "ETDT", - [ACPI_FADT] = "FACP", - [ACPI_FACS] = "FACS", - [ACPI_OEMX] = "OEM", - [ACPI_PSDT] = "PSDT", - [ACPI_SBST] = "SBST", - [ACPI_SLIT] = "SLIT", - [ACPI_SPCR] = "SPCR", - [ACPI_SRAT] = "SRAT", - [ACPI_SSDT] = "SSDT", - [ACPI_SPMI] = "SPMI", - [ACPI_HPET] = "HPET", - [ACPI_MCFG] = "MCFG", -}; - static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" }; static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" }; -/* System Description Table (RSDT/XSDT) */ -struct acpi_table_sdt { - unsigned long pa; - enum acpi_table_id id; - unsigned long size; -} __attribute__ ((packed)); - -static unsigned long sdt_pa; /* Physical Address */ -static unsigned long sdt_count; /* Table count */ - -static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES] __initdata; static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; -void acpi_table_print(struct acpi_table_header *header, unsigned long phys_addr) -{ - char *name = NULL; - - if (!header) - return; - - /* Some table signatures aren't good table names */ - - if (!strncmp((char *)&header->signature, - acpi_table_signatures[ACPI_APIC], - sizeof(header->signature))) { - name = "MADT"; - } else if (!strncmp((char *)&header->signature, - acpi_table_signatures[ACPI_FADT], - sizeof(header->signature))) { - name = "FADT"; - } else - name = header->signature; - - printk(KERN_DEBUG PREFIX - "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", name, - header->revision, header->oem_id, header->oem_table_id, - header->oem_revision, header->asl_compiler_id, - header->asl_compiler_revision, (void *)phys_addr); -} - void acpi_table_print_madt_entry(acpi_table_entry_header * header) { if (!header) @@ -226,123 +166,32 @@ void acpi_table_print_madt_entry(acpi_table_entry_header * header) } } -static int -acpi_table_compute_checksum(void *table_pointer, unsigned long length) -{ - u8 *p = table_pointer; - unsigned long remains = length; - unsigned long sum = 0; - - if (!p || !length) - return -EINVAL; - - while (remains--) - sum += *p++; - - return (sum & 0xFF); -} - -/* - * acpi_get_table_header_early() - * for acpi_blacklisted(), acpi_table_get_sdt() - */ -int __init -acpi_get_table_header_early(enum acpi_table_id id, - struct acpi_table_header **header) -{ - unsigned int i; - enum acpi_table_id temp_id; - - /* DSDT is different from the rest */ - if (id == ACPI_DSDT) - temp_id = ACPI_FADT; - else - temp_id = id; - - /* Locate the table. */ - - for (i = 0; i < sdt_count; i++) { - if (sdt_entry[i].id != temp_id) - continue; - *header = (void *) - __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size); - if (!*header) { - printk(KERN_WARNING PREFIX "Unable to map %s\n", - acpi_table_signatures[temp_id]); - return -ENODEV; - } - break; - } - - if (!*header) { - printk(KERN_WARNING PREFIX "%s not present\n", - acpi_table_signatures[id]); - return -ENODEV; - } - - /* Map the DSDT header via the pointer in the FADT */ - if (id == ACPI_DSDT) { - struct fadt_descriptor *fadt = - (struct fadt_descriptor *)*header; - - if (fadt->header.revision == 3 && fadt->Xdsdt) { - *header = (void *)__acpi_map_table(fadt->Xdsdt, - sizeof(struct - acpi_table_header)); - } else if (fadt->dsdt) { - *header = (void *)__acpi_map_table(fadt->dsdt, - sizeof(struct - acpi_table_header)); - } else - *header = NULL; - - if (!*header) { - printk(KERN_WARNING PREFIX "Unable to map DSDT\n"); - return -ENODEV; - } - } - - return 0; -} int __init -acpi_table_parse_madt_family(enum acpi_table_id id, +acpi_table_parse_madt_family(char *id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler, unsigned int max_entries) { - void *madt = NULL; + struct acpi_table_header *madt = NULL; acpi_table_entry_header *entry; unsigned int count = 0; unsigned long madt_end; - unsigned int i; if (!handler) return -EINVAL; /* Locate the MADT (if exists). There should only be one. */ - for (i = 0; i < sdt_count; i++) { - if (sdt_entry[i].id != id) - continue; - madt = (void *) - __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size); - if (!madt) { - printk(KERN_WARNING PREFIX "Unable to map %s\n", - acpi_table_signatures[id]); - return -ENODEV; - } - break; - } + acpi_get_table(id, 0, &madt); if (!madt) { - printk(KERN_WARNING PREFIX "%s not present\n", - acpi_table_signatures[id]); + printk(KERN_WARNING PREFIX "%4.4s not present\n", id); return -ENODEV; } - madt_end = (unsigned long)madt + sdt_entry[i].size; + madt_end = (unsigned long)madt + madt->length; /* Parse all entries looking for a match. */ @@ -360,9 +209,8 @@ acpi_table_parse_madt_family(enum acpi_table_id id, ((unsigned long)entry + entry->length); } if (max_entries && count > max_entries) { - printk(KERN_WARNING PREFIX "[%s:0x%02x] ignored %i entries of " - "%i found\n", acpi_table_signatures[id], entry_id, - count - max_entries, count); + printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of " + "%i found\n", id, entry_id, count - max_entries, count); } return count; @@ -372,195 +220,24 @@ int __init acpi_table_parse_madt(enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries) { - return acpi_table_parse_madt_family(ACPI_APIC, + return acpi_table_parse_madt_family("APIC", sizeof(struct acpi_table_madt), id, handler, max_entries); } -int __init acpi_table_parse(enum acpi_table_id id, acpi_table_handler handler) +int __init acpi_table_parse(char *id, acpi_table_handler handler) { - int count = 0; - unsigned int i = 0; + struct acpi_table_header *table = NULL; if (!handler) return -EINVAL; - for (i = 0; i < sdt_count; i++) { - if (sdt_entry[i].id != id) - continue; - count++; - if (count == 1) - handler(sdt_entry[i].pa, sdt_entry[i].size); - - else - printk(KERN_WARNING PREFIX - "%d duplicate %s table ignored.\n", count, - acpi_table_signatures[id]); - } - - return count; -} - -static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp) -{ - struct acpi_table_header *header = NULL; - unsigned int i, id = 0; - - if (!rsdp) - return -EINVAL; - - /* First check XSDT (but only on ACPI 2.0-compatible systems) */ - - if ((rsdp->revision >= 2) && rsdp->xsdt_physical_address) { - - struct acpi_table_xsdt *mapped_xsdt = NULL; - - sdt_pa = rsdp->xsdt_physical_address; - - /* map in just the header */ - header = (struct acpi_table_header *) - __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header)); - - if (!header) { - printk(KERN_WARNING PREFIX - "Unable to map XSDT header\n"); - return -ENODEV; - } - - /* remap in the entire table before processing */ - mapped_xsdt = (struct acpi_table_xsdt *) - __acpi_map_table(sdt_pa, header->length); - if (!mapped_xsdt) { - printk(KERN_WARNING PREFIX "Unable to map XSDT\n"); - return -ENODEV; - } - header = &mapped_xsdt->header; - - if (strncmp(header->signature, "XSDT", 4)) { - printk(KERN_WARNING PREFIX - "XSDT signature incorrect\n"); - return -ENODEV; - } - - if (acpi_table_compute_checksum(header, header->length)) { - printk(KERN_WARNING PREFIX "Invalid XSDT checksum\n"); - return -ENODEV; - } - - sdt_count = - (header->length - sizeof(struct acpi_table_header)) >> 3; - if (sdt_count > ACPI_MAX_TABLES) { - printk(KERN_WARNING PREFIX - "Truncated %lu XSDT entries\n", - (sdt_count - ACPI_MAX_TABLES)); - sdt_count = ACPI_MAX_TABLES; - } - - for (i = 0; i < sdt_count; i++) - sdt_entry[i].pa = (unsigned long)mapped_xsdt->table_offset_entry[i]; - } - - /* Then check RSDT */ - - else if (rsdp->rsdt_physical_address) { - - struct acpi_table_rsdt *mapped_rsdt = NULL; - - sdt_pa = rsdp->rsdt_physical_address; - - /* map in just the header */ - header = (struct acpi_table_header *) - __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header)); - if (!header) { - printk(KERN_WARNING PREFIX - "Unable to map RSDT header\n"); - return -ENODEV; - } - - /* remap in the entire table before processing */ - mapped_rsdt = (struct acpi_table_rsdt *) - __acpi_map_table(sdt_pa, header->length); - if (!mapped_rsdt) { - printk(KERN_WARNING PREFIX "Unable to map RSDT\n"); - return -ENODEV; - } - header = &mapped_rsdt->header; - - if (strncmp(header->signature, "RSDT", 4)) { - printk(KERN_WARNING PREFIX - "RSDT signature incorrect\n"); - return -ENODEV; - } - - if (acpi_table_compute_checksum(header, header->length)) { - printk(KERN_WARNING PREFIX "Invalid RSDT checksum\n"); - return -ENODEV; - } - - sdt_count = - (header->length - sizeof(struct acpi_table_header)) >> 2; - if (sdt_count > ACPI_MAX_TABLES) { - printk(KERN_WARNING PREFIX - "Truncated %lu RSDT entries\n", - (sdt_count - ACPI_MAX_TABLES)); - sdt_count = ACPI_MAX_TABLES; - } - - for (i = 0; i < sdt_count; i++) - sdt_entry[i].pa = (unsigned long)mapped_rsdt->table_offset_entry[i]; - } - - else { - printk(KERN_WARNING PREFIX - "No System Description Table (RSDT/XSDT) specified in RSDP\n"); - return -ENODEV; - } - - acpi_table_print(header, sdt_pa); - - for (i = 0; i < sdt_count; i++) { - - /* map in just the header */ - header = (struct acpi_table_header *) - __acpi_map_table(sdt_entry[i].pa, - sizeof(struct acpi_table_header)); - if (!header) - continue; - - /* remap in the entire table before processing */ - header = (struct acpi_table_header *) - __acpi_map_table(sdt_entry[i].pa, header->length); - if (!header) - continue; - - acpi_table_print(header, sdt_entry[i].pa); - - if (acpi_table_compute_checksum(header, header->length)) { - printk(KERN_WARNING " >>> ERROR: Invalid checksum\n"); - continue; - } - - sdt_entry[i].size = header->length; - - for (id = 0; id < ACPI_TABLE_COUNT; id++) { - if (!strncmp((char *)&header->signature, - acpi_table_signatures[id], - sizeof(header->signature))) { - sdt_entry[i].id = id; - } - } - } - - /* - * The DSDT is *not* in the RSDT (why not? no idea.) but we want - * to print its info, because this is what people usually blacklist - * against. Unfortunately, we don't know the phys_addr, so just - * print 0. Maybe no one will notice. - */ - if (!acpi_get_table_header_early(ACPI_DSDT, &header)) - acpi_table_print(header, 0); - - return 0; + acpi_get_table(id, 0, &table); + if (table) { + handler(table); + return 1; + } else + return 0; } /* @@ -574,47 +251,6 @@ static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp) int __init acpi_table_init(void) { - struct acpi_table_rsdp *rsdp = NULL; - unsigned long rsdp_phys = 0; - int result = 0; - - /* Locate and map the Root System Description Table (RSDP) */ - - rsdp_phys = acpi_find_rsdp(); - if (!rsdp_phys) { - printk(KERN_ERR PREFIX "Unable to locate RSDP\n"); - return -ENODEV; - } - - rsdp = (struct acpi_table_rsdp *)__acpi_map_table(rsdp_phys, - sizeof(struct acpi_table_rsdp)); - if (!rsdp) { - printk(KERN_WARNING PREFIX "Unable to map RSDP\n"); - return -ENODEV; - } - - printk(KERN_DEBUG PREFIX - "RSDP (v%3.3d %6.6s ) @ 0x%p\n", - rsdp->revision, rsdp->oem_id, (void *)rsdp_phys); - - if (rsdp->revision < 2) - result = - acpi_table_compute_checksum(rsdp, ACPI_RSDP_REV0_SIZE); - else - result = - acpi_table_compute_checksum(rsdp, rsdp->length); - - if (result) { - printk(KERN_WARNING " >>> ERROR: Invalid checksum\n"); - return -ENODEV; - } - - /* Locate and map the System Description table (RSDT/XSDT) */ - - if (acpi_table_get_sdt(rsdp)) - return -ENODEV; - acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); - return 0; } diff --git a/include/linux/acpi.h b/include/linux/acpi.h index b3e8a268f6d6..88cb1fe22b48 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -340,7 +340,7 @@ enum acpi_table_id { ACPI_TABLE_COUNT }; -typedef int (*acpi_table_handler) (unsigned long phys_addr, unsigned long size); +typedef int (*acpi_table_handler) (struct acpi_table_header *header); extern acpi_table_handler acpi_table_ops[ACPI_TABLE_COUNT]; @@ -353,11 +353,10 @@ int acpi_boot_table_init (void); int acpi_numa_init (void); int acpi_table_init (void); -int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler); -int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header); +int acpi_table_parse (char *id, acpi_table_handler handler); int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); -int acpi_parse_mcfg (unsigned long phys_addr, unsigned long size); +int acpi_parse_mcfg (struct acpi_table_header *header); void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr); void acpi_table_print_madt_entry (acpi_table_entry_header *madt); void acpi_table_print_srat_entry (acpi_table_entry_header *srat); -- cgit v1.2.3 From ad363f80c386bc4701b1bc2cdf08ca9b96a9337b Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Fri, 2 Feb 2007 19:48:22 +0300 Subject: ACPICA: Remove duplicate table definitions. Signed-off-by: Len Brown --- arch/i386/kernel/acpi/boot.c | 29 +++++++++++----------- drivers/acpi/ec.c | 8 +++--- include/acpi/actbl.h | 5 ++-- include/linux/acpi.h | 59 -------------------------------------------- 4 files changed, 20 insertions(+), 81 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index cbbcf9c630bf..389a8a56d2b4 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -204,9 +204,9 @@ int __init acpi_parse_mcfg(struct acpi_table_header *header) return -ENOMEM; } - memcpy(pci_mmcfg_config, &mcfg->config, config_size); + memcpy(pci_mmcfg_config, &mcfg[1], config_size); for (i = 0; i < pci_mmcfg_config_num; ++i) { - if (mcfg->config[i].base_reserved) { + if (pci_mmcfg_config[i].base_reserved) { printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n"); kfree(pci_mmcfg_config); @@ -233,11 +233,11 @@ static int __init acpi_parse_madt(struct acpi_table_header *header) return -ENODEV; } - if (madt->lapic_address) { - acpi_lapic_addr = (u64) madt->lapic_address; + if (madt->address) { + acpi_lapic_addr = (u64) madt->address; printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n", - madt->lapic_address); + madt->address); } acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id); @@ -654,7 +654,7 @@ static int __init acpi_parse_hpet(struct acpi_table_header *header) return -ENODEV; } - if (hpet_tbl->addr.space_id != ACPI_SPACE_MEM) { + if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) { printk(KERN_WARNING PREFIX "HPET timers must be located in " "memory.\n"); return -1; @@ -667,29 +667,28 @@ static int __init acpi_parse_hpet(struct acpi_table_header *header) hpet_res->name = (void *)&hpet_res[1]; hpet_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE, - "HPET %u", hpet_tbl->number); + "HPET %u", hpet_tbl->sequence); hpet_res->end = (1 * 1024) - 1; } -#ifdef CONFIG_X86_64 - vxtime.hpet_address = hpet_tbl->addr.addrl | - ((long)hpet_tbl->addr.addrh << 32); +#ifdef CONFIG_X86_64 + vxtime.hpet_address = hpet_tbl->address.address; printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", - hpet_tbl->id, vxtime.hpet_address); + hpet_tbl->id, vxtime.hpet_address); res_start = vxtime.hpet_address; -#else /* X86 */ +#else /* X86 */ { extern unsigned long hpet_address; - hpet_address = hpet_tbl->addr.addrl; + hpet_address = hpet_tbl->address.address; printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", - hpet_tbl->id, hpet_address); + hpet_tbl->id, hpet_address); res_start = hpet_address; } -#endif /* X86 */ +#endif /* X86 */ if (hpet_res) { hpet_res->start = res_start; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 7a1f2baff646..710364e6c586 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -889,14 +889,14 @@ static int __init acpi_ec_get_real_ecdt(void) if (acpi_ec_mode == EC_INTR) { init_waitqueue_head(&ec_ecdt->wait); } - ec_ecdt->command_addr = ecdt_ptr->ec_control.address; - ec_ecdt->data_addr = ecdt_ptr->ec_data.address; - ec_ecdt->gpe = ecdt_ptr->gpe_bit; + ec_ecdt->command_addr = ecdt_ptr->control.address; + ec_ecdt->data_addr = ecdt_ptr->data.address; + ec_ecdt->gpe = ecdt_ptr->gpe; /* use the GL just to be safe */ ec_ecdt->global_lock = TRUE; ec_ecdt->uid = ecdt_ptr->uid; - status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle); + status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle); if (ACPI_FAILURE(status)) { goto error; } diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index c5d5ec3638ef..d6af14e1c7e8 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -289,8 +289,7 @@ enum acpi_prefered_pm_profiles { /* * Get the remaining ACPI tables */ -/* - Don't include any new tables definitions for now. + #include -*/ + #endif /* __ACTBL_H__ */ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 88cb1fe22b48..5a2b3633220e 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -60,15 +60,6 @@ typedef struct { /* Multiple APIC Description Table (MADT) */ -struct acpi_table_madt { - struct acpi_table_header header; - u32 lapic_address; - struct { - u32 pcat_compat:1; - u32 reserved:31; - } flags; -} __attribute__ ((packed)); - enum acpi_madt_entry_id { ACPI_MADT_LAPIC = 0, ACPI_MADT_IOAPIC, @@ -185,15 +176,6 @@ struct acpi_gen_regaddr { u32 addrh; } __attribute__ ((packed)); -struct acpi_table_hpet { - struct acpi_table_header header; - u32 id; - struct acpi_gen_regaddr addr; - u8 number; - u16 min_tick; - u8 page_protect; -} __attribute__ ((packed)); - /* * Simple Boot Flags * http://www.microsoft.com/whdc/hwdev/resources/specs/simp_bios.mspx @@ -218,12 +200,6 @@ struct acpi_table_sbf * http://www.microsoft.com/whdc/hwdev/platform/proc/SRAT.mspx */ -struct acpi_table_srat { - struct acpi_table_header header; - u32 table_revision; - u64 reserved; -} __attribute__ ((packed)); - enum acpi_srat_entry_id { ACPI_SRAT_PROCESSOR_AFFINITY = 0, ACPI_SRAT_MEMORY_AFFINITY, @@ -267,36 +243,6 @@ enum acpi_address_range_id { ACPI_ADDRESS_RANGE_COUNT }; -/* - * System Locality Information Table (SLIT) - * see http://devresource.hp.com/devresource/docs/techpapers/ia64/slit.pdf - */ - -struct acpi_table_slit { - struct acpi_table_header header; - u64 localities; - u8 entry[1]; /* real size = localities^2 */ -} __attribute__ ((packed)); - -/* Smart Battery Description Table (SBST) */ - -struct acpi_table_sbst { - struct acpi_table_header header; - u32 warning; /* Warn user */ - u32 low; /* Critical sleep */ - u32 critical; /* Critical shutdown */ -} __attribute__ ((packed)); - -/* Embedded Controller Boot Resources Table (ECDT) */ - -struct acpi_table_ecdt { - struct acpi_table_header header; - struct acpi_generic_address ec_control; - struct acpi_generic_address ec_data; - u32 uid; - u8 gpe_bit; - char ec_id[0]; -} __attribute__ ((packed)); /* PCI MMCONFIG */ @@ -309,11 +255,6 @@ struct acpi_table_mcfg_config { u8 end_bus_number; u8 reserved[4]; } __attribute__ ((packed)); -struct acpi_table_mcfg { - struct acpi_table_header header; - u8 reserved[8]; - struct acpi_table_mcfg_config config[0]; -} __attribute__ ((packed)); /* Table Handlers */ -- cgit v1.2.3 From 5f3b1a8b6737b09ce5df4ec9fad4ad271aecb5fb Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Fri, 2 Feb 2007 19:48:22 +0300 Subject: ACPICA: Remove duplicate table definitions (non-conflicting) Signed-off-by: Len Brown --- arch/i386/kernel/acpi/boot.c | 156 +++++++++++++++++++-------------------- arch/ia64/kernel/acpi.c | 172 +++++++++++++++++++++---------------------- drivers/acpi/bus.c | 11 +-- drivers/acpi/tables.c | 109 +++++++++++++-------------- include/linux/acpi.h | 106 +------------------------- 5 files changed, 224 insertions(+), 330 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 389a8a56d2b4..5fafbacdd4cb 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -66,7 +66,7 @@ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { return #define BAD_MADT_ENTRY(entry, end) ( \ (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ - ((acpi_table_entry_header *)entry)->length < sizeof(*entry)) + ((struct acpi_subtable_header *)entry)->length < sizeof(*entry)) #define PREFIX "ACPI: " @@ -79,7 +79,7 @@ int acpi_ioapic; int acpi_strict; EXPORT_SYMBOL(acpi_strict); -acpi_interrupt_flags acpi_sci_flags __initdata; +u8 acpi_sci_flags __initdata; int acpi_sci_override_gsi __initdata; int acpi_skip_timer_override __initdata; int acpi_use_timer_override __initdata; @@ -246,11 +246,11 @@ static int __init acpi_parse_madt(struct acpi_table_header *header) } static int __init -acpi_parse_lapic(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_lapic *processor = NULL; + struct acpi_madt_local_apic *processor = NULL; - processor = (struct acpi_table_lapic *)header; + processor = (struct acpi_madt_local_apic *)header; if (BAD_MADT_ENTRY(processor, end)) return -EINVAL; @@ -258,8 +258,8 @@ acpi_parse_lapic(acpi_table_entry_header * header, const unsigned long end) acpi_table_print_madt_entry(header); /* Record local apic id only when enabled */ - if (processor->flags.enabled) - x86_acpiid_to_apicid[processor->acpi_id] = processor->id; + if (processor->lapic_flags & ACPI_MADT_ENABLED) + x86_acpiid_to_apicid[processor->processor_id] = processor->id; /* * We need to register disabled CPU as well to permit @@ -269,18 +269,18 @@ acpi_parse_lapic(acpi_table_entry_header * header, const unsigned long end) * when we use CPU hotplug. */ mp_register_lapic(processor->id, /* APIC ID */ - processor->flags.enabled); /* Enabled? */ + processor->lapic_flags & ACPI_MADT_ENABLED); /* Enabled? */ return 0; } static int __init -acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header, +acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL; + struct acpi_madt_local_apic_override *lapic_addr_ovr = NULL; - lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr *)header; + lapic_addr_ovr = (struct acpi_madt_local_apic_override *)header; if (BAD_MADT_ENTRY(lapic_addr_ovr, end)) return -EINVAL; @@ -291,11 +291,11 @@ acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header, } static int __init -acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_lapic_nmi *lapic_nmi = NULL; + struct acpi_madt_local_apic_nmi *lapic_nmi = NULL; - lapic_nmi = (struct acpi_table_lapic_nmi *)header; + lapic_nmi = (struct acpi_madt_local_apic_nmi *)header; if (BAD_MADT_ENTRY(lapic_nmi, end)) return -EINVAL; @@ -313,11 +313,11 @@ acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end) #ifdef CONFIG_X86_IO_APIC static int __init -acpi_parse_ioapic(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_ioapic *ioapic = NULL; + struct acpi_madt_io_apic *ioapic = NULL; - ioapic = (struct acpi_table_ioapic *)header; + ioapic = (struct acpi_madt_io_apic *)header; if (BAD_MADT_ENTRY(ioapic, end)) return -EINVAL; @@ -342,11 +342,11 @@ static void __init acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger) polarity = 3; /* Command-line over-ride via acpi_sci= */ - if (acpi_sci_flags.trigger) - trigger = acpi_sci_flags.trigger; + if (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) + trigger = (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2; - if (acpi_sci_flags.polarity) - polarity = acpi_sci_flags.polarity; + if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK) + polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK; /* * mp_config_acpi_legacy_irqs() already setup IRQs < 16 @@ -364,44 +364,45 @@ static void __init acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger) } static int __init -acpi_parse_int_src_ovr(acpi_table_entry_header * header, +acpi_parse_int_src_ovr(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_int_src_ovr *intsrc = NULL; + struct acpi_madt_interrupt_override *intsrc = NULL; - intsrc = (struct acpi_table_int_src_ovr *)header; + intsrc = (struct acpi_madt_interrupt_override *)header; if (BAD_MADT_ENTRY(intsrc, end)) return -EINVAL; acpi_table_print_madt_entry(header); - if (intsrc->bus_irq == acpi_gbl_FADT.sci_interrupt) { + if (intsrc->source_irq == acpi_gbl_FADT.sci_interrupt) { acpi_sci_ioapic_setup(intsrc->global_irq, - intsrc->flags.polarity, - intsrc->flags.trigger); + intsrc->inti_flags & ACPI_MADT_POLARITY_MASK, + (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2); return 0; } if (acpi_skip_timer_override && - intsrc->bus_irq == 0 && intsrc->global_irq == 2) { + intsrc->source_irq == 0 && intsrc->global_irq == 2) { printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n"); return 0; } - mp_override_legacy_irq(intsrc->bus_irq, - intsrc->flags.polarity, - intsrc->flags.trigger, intsrc->global_irq); + mp_override_legacy_irq(intsrc->source_irq, + intsrc->inti_flags & ACPI_MADT_POLARITY_MASK, + (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2, + intsrc->global_irq); return 0; } static int __init -acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_nmi_src *nmi_src = NULL; + struct acpi_madt_nmi_source *nmi_src = NULL; - nmi_src = (struct acpi_table_nmi_src *)header; + nmi_src = (struct acpi_madt_nmi_source *)header; if (BAD_MADT_ENTRY(nmi_src, end)) return -EINVAL; @@ -417,7 +418,7 @@ acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end) /* * acpi_pic_sci_set_trigger() - * + * * use ELCR to set PIC-mode trigger type for SCI * * If a PIC-mode SCI is not recognized or gives spurious IRQ7's @@ -511,7 +512,7 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; - struct acpi_table_lapic *lapic; + struct acpi_madt_local_apic *lapic; cpumask_t tmp_map, new_map; u8 physid; int cpu; @@ -529,10 +530,10 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu) return -EINVAL; } - lapic = (struct acpi_table_lapic *)obj->buffer.pointer; + lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer; - if ((lapic->header.type != ACPI_MADT_LAPIC) || - (!lapic->flags.enabled)) { + if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC || + !(lapic->lapic_flags & ACPI_MADT_ENABLED)) { kfree(buffer.pointer); return -EINVAL; } @@ -544,7 +545,7 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu) buffer.pointer = NULL; tmp_map = cpu_present_map; - mp_register_lapic(physid, lapic->flags.enabled); + mp_register_lapic(physid, lapic->lapic_flags & ACPI_MADT_ENABLED); /* * If mp_register_lapic successfully generates a new logical cpu @@ -619,36 +620,30 @@ acpi_scan_rsdp(unsigned long start, unsigned long length) return 0; } -static int __init acpi_parse_sbf(struct acpi_table_header *header) +static int __init acpi_parse_sbf(struct acpi_table_header *table) { - struct acpi_table_sbf *sb; - - if (!header) - return -EINVAL; + struct acpi_table_boot *sb; - sb = (struct acpi_table_sbf *)header; + sb = (struct acpi_table_boot *)table; if (!sb) { printk(KERN_WARNING PREFIX "Unable to map SBF\n"); return -ENODEV; } - sbf_port = sb->sbf_cmos; /* Save CMOS port */ + sbf_port = sb->cmos_index; /* Save CMOS port */ return 0; } #ifdef CONFIG_HPET_TIMER -static int __init acpi_parse_hpet(struct acpi_table_header *header) +static int __init acpi_parse_hpet(struct acpi_table_header *table) { struct acpi_table_hpet *hpet_tbl; struct resource *hpet_res; resource_size_t res_start; - if (!header) - return -EINVAL; - - hpet_tbl = (struct acpi_table_hpet *)header; + hpet_tbl = (struct acpi_table_hpet *)table; if (!hpet_tbl) { printk(KERN_WARNING PREFIX "Unable to map HPET\n"); return -ENODEV; @@ -706,35 +701,28 @@ static int __init acpi_parse_hpet(struct acpi_table_header *header) extern u32 pmtmr_ioport; #endif -static int __init acpi_parse_fadt(struct acpi_table_header *header) +static int __init acpi_parse_fadt(struct acpi_table_header *table) { - struct acpi_table_fadt *fadt = NULL; - - fadt = (struct acpi_table_fadt *)header; - if (!fadt) { - printk(KERN_WARNING PREFIX "Unable to map FADT\n"); - return 0; - } #ifdef CONFIG_X86_PM_TIMER /* detect the location of the ACPI PM Timer */ - if (fadt->header.revision >= FADT2_REVISION_ID) { + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) { /* FADT rev. 2 */ - if (fadt->xpm_timer_block.space_id != + if (acpi_gbl_FADT.xpm_timer_block.space_id != ACPI_ADR_SPACE_SYSTEM_IO) return 0; - pmtmr_ioport = fadt->xpm_timer_block.address; + pmtmr_ioport = acpi_gbl_FADT.xpm_timer_block.address; /* * "X" fields are optional extensions to the original V1.0 * fields, so we must selectively expand V1.0 fields if the * corresponding X field is zero. */ if (!pmtmr_ioport) - pmtmr_ioport = fadt->pm_timer_block; + pmtmr_ioport = acpi_gbl_FADT.pm_timer_block; } else { /* FADT rev. 1 */ - pmtmr_ioport = fadt->pm_timer_block; + pmtmr_ioport = acpi_gbl_FADT.pm_timer_block; } if (pmtmr_ioport) printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", @@ -776,13 +764,13 @@ static int __init acpi_parse_madt_lapic_entries(void) if (!cpu_has_apic) return -ENODEV; - /* + /* * Note that the LAPIC address is obtained from the MADT (32-bit value) * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). */ count = - acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, + acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE, acpi_parse_lapic_addr_ovr, 0); if (count < 0) { printk(KERN_ERR PREFIX @@ -792,7 +780,7 @@ static int __init acpi_parse_madt_lapic_entries(void) mp_register_lapic_address(acpi_lapic_addr); - count = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic, + count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC, acpi_parse_lapic, MAX_APICS); if (!count) { printk(KERN_ERR PREFIX "No LAPIC entries present\n"); @@ -805,7 +793,7 @@ static int __init acpi_parse_madt_lapic_entries(void) } count = - acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0); + acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0); if (count < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); /* TBD: Cleanup to allow fallback to MPS */ @@ -834,7 +822,7 @@ static int __init acpi_parse_madt_ioapic_entries(void) return -ENODEV; } - if (!cpu_has_apic) + if (!cpu_has_apic) return -ENODEV; /* @@ -847,7 +835,7 @@ static int __init acpi_parse_madt_ioapic_entries(void) } count = - acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic, + acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic, MAX_IO_APICS); if (!count) { printk(KERN_ERR PREFIX "No IOAPIC entries present\n"); @@ -858,7 +846,7 @@ static int __init acpi_parse_madt_ioapic_entries(void) } count = - acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, + acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr, NR_IRQ_VECTORS); if (count < 0) { printk(KERN_ERR PREFIX @@ -878,7 +866,7 @@ static int __init acpi_parse_madt_ioapic_entries(void) mp_config_acpi_legacy_irqs(); count = - acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, + acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src, NR_IRQ_VECTORS); if (count < 0) { printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); @@ -900,7 +888,7 @@ static void __init acpi_process_madt(void) #ifdef CONFIG_X86_LOCAL_APIC int count, error; - count = acpi_table_parse("APIC", acpi_parse_madt); + count = acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt); if (count >= 1) { /* @@ -1187,7 +1175,7 @@ int __init acpi_boot_table_init(void) if (acpi_disabled && !acpi_ht) return 1; - /* + /* * Initialize the ACPI boot-time table parser. */ error = acpi_table_init(); @@ -1196,7 +1184,7 @@ int __init acpi_boot_table_init(void) return error; } - acpi_table_parse("BOOT", acpi_parse_sbf); + acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf); /* * blacklist may disable ACPI entirely @@ -1224,7 +1212,7 @@ int __init acpi_boot_init(void) if (acpi_disabled && !acpi_ht) return 1; - acpi_table_parse("BOOT", acpi_parse_sbf); + acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf); /* * set sci_int and PM timer address @@ -1236,7 +1224,7 @@ int __init acpi_boot_init(void) */ acpi_process_madt(); - acpi_table_parse("HPET", acpi_parse_hpet); + acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet); return 0; } @@ -1307,13 +1295,17 @@ static int __init setup_acpi_sci(char *s) if (!s) return -EINVAL; if (!strcmp(s, "edge")) - acpi_sci_flags.trigger = 1; + acpi_sci_flags = ACPI_MADT_TRIGGER_EDGE | + (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK); else if (!strcmp(s, "level")) - acpi_sci_flags.trigger = 3; + acpi_sci_flags = ACPI_MADT_TRIGGER_LEVEL | + (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK); else if (!strcmp(s, "high")) - acpi_sci_flags.polarity = 1; + acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_HIGH | + (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK); else if (!strcmp(s, "low")) - acpi_sci_flags.polarity = 3; + acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_LOW | + (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK); else return -EINVAL; return 0; diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index d37fb8e81898..4719e481d93b 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -55,7 +55,7 @@ #define BAD_MADT_ENTRY(entry, end) ( \ (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ - ((acpi_table_entry_header *)entry)->length < sizeof(*entry)) + ((struct acpi_subtable_header *)entry)->length < sizeof(*entry)) #define PREFIX "ACPI: " @@ -94,7 +94,7 @@ const char *acpi_get_sysname(void) return "dig"; } - xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_address); + xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_physical_address); hdr = &xsdt->header; if (strncmp(hdr->signature, ACPI_SIG_XSDT, sizeof(ACPI_SIG_XSDT) - 1)) { printk(KERN_ERR @@ -169,12 +169,12 @@ struct acpi_table_madt *acpi_madt __initdata; static u8 has_8259; static int __init -acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header, +acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_lapic_addr_ovr *lapic; + struct acpi_madt_local_apic_override *lapic; - lapic = (struct acpi_table_lapic_addr_ovr *)header; + lapic = (struct acpi_madt_local_apic_override *)header; if (BAD_MADT_ENTRY(lapic, end)) return -EINVAL; @@ -187,21 +187,20 @@ acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header, } static int __init -acpi_parse_lsapic(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_lsapic(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_lsapic *lsapic; + struct acpi_madt_local_sapic *lsapic; - lsapic = (struct acpi_table_lsapic *)header; + lsapic = (struct acpi_madt_local_sapic *)header; - if (BAD_MADT_ENTRY(lsapic, end)) - return -EINVAL; + /*Skip BAD_MADT_ENTRY check, as lsapic size could vary */ - if (lsapic->flags.enabled) { + if (lsapic->lapic_flags & ACPI_MADT_ENABLED) { #ifdef CONFIG_SMP smp_boot_data.cpu_phys_id[available_cpus] = (lsapic->id << 8) | lsapic->eid; #endif - ia64_acpiid_to_sapicid[lsapic->acpi_id] = + ia64_acpiid_to_sapicid[lsapic->processor_id] = (lsapic->id << 8) | lsapic->eid; ++available_cpus; } @@ -211,11 +210,11 @@ acpi_parse_lsapic(acpi_table_entry_header * header, const unsigned long end) } static int __init -acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_lapic_nmi *lacpi_nmi; + struct acpi_madt_local_apic_nmi *lacpi_nmi; - lacpi_nmi = (struct acpi_table_lapic_nmi *)header; + lacpi_nmi = (struct acpi_madt_local_apic_nmi *)header; if (BAD_MADT_ENTRY(lacpi_nmi, end)) return -EINVAL; @@ -225,11 +224,11 @@ acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end) } static int __init -acpi_parse_iosapic(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_iosapic(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_iosapic *iosapic; + struct acpi_madt_io_sapic *iosapic; - iosapic = (struct acpi_table_iosapic *)header; + iosapic = (struct acpi_madt_io_sapic *)header; if (BAD_MADT_ENTRY(iosapic, end)) return -EINVAL; @@ -240,13 +239,13 @@ acpi_parse_iosapic(acpi_table_entry_header * header, const unsigned long end) static unsigned int __initdata acpi_madt_rev; static int __init -acpi_parse_plat_int_src(acpi_table_entry_header * header, +acpi_parse_plat_int_src(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_plat_int_src *plintsrc; + struct acpi_madt_interrupt_source *plintsrc; int vector; - plintsrc = (struct acpi_table_plat_int_src *)header; + plintsrc = (struct acpi_madt_interrupt_source *)header; if (BAD_MADT_ENTRY(plintsrc, end)) return -EINVAL; @@ -257,19 +256,19 @@ acpi_parse_plat_int_src(acpi_table_entry_header * header, */ vector = iosapic_register_platform_intr(plintsrc->type, plintsrc->global_irq, - plintsrc->iosapic_vector, + plintsrc->io_sapic_vector, plintsrc->eid, plintsrc->id, - (plintsrc->flags.polarity == - 1) ? IOSAPIC_POL_HIGH : - IOSAPIC_POL_LOW, - (plintsrc->flags.trigger == - 1) ? IOSAPIC_EDGE : - IOSAPIC_LEVEL); + ((plintsrc->inti_flags & ACPI_MADT_POLARITY_MASK) == + ACPI_MADT_POLARITY_ACTIVE_HIGH) ? + IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, + ((plintsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) == + ACPI_MADT_TRIGGER_EDGE) ? + IOSAPIC_EDGE : IOSAPIC_LEVEL); platform_intr_list[plintsrc->type] = vector; if (acpi_madt_rev > 1) { - acpi_cpei_override = plintsrc->plint_flags.cpei_override_flag; + acpi_cpei_override = plintsrc->flags & ACPI_MADT_CPEI_OVERRIDE; } /* @@ -324,30 +323,32 @@ unsigned int get_cpei_target_cpu(void) } static int __init -acpi_parse_int_src_ovr(acpi_table_entry_header * header, +acpi_parse_int_src_ovr(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_int_src_ovr *p; + struct acpi_madt_interrupt_override *p; - p = (struct acpi_table_int_src_ovr *)header; + p = (struct acpi_madt_interrupt_override *)header; if (BAD_MADT_ENTRY(p, end)) return -EINVAL; - iosapic_override_isa_irq(p->bus_irq, p->global_irq, - (p->flags.polarity == - 1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, - (p->flags.trigger == - 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL); + iosapic_override_isa_irq(p->source_irq, p->global_irq, + ((p->inti_flags & ACPI_MADT_POLARITY_MASK) == + ACPI_MADT_POLARITY_ACTIVE_HIGH) ? + IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, + ((p->inti_flags & ACPI_MADT_TRIGGER_MASK) == + ACPI_MADT_TRIGGER_EDGE) ? + IOSAPIC_EDGE : IOSAPIC_LEVEL); return 0; } static int __init -acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end) +acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_nmi_src *nmi_src; + struct acpi_madt_nmi_source *nmi_src; - nmi_src = (struct acpi_table_nmi_src *)header; + nmi_src = (struct acpi_madt_nmi_source *)header; if (BAD_MADT_ENTRY(nmi_src, end)) return -EINVAL; @@ -371,12 +372,12 @@ static void __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) } } -static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size) +static int __init acpi_parse_madt(struct acpi_table_header *table) { - if (!phys_addr || !size) + if (!table) return -EINVAL; - acpi_madt = (struct acpi_table_madt *)__va(phys_addr); + acpi_madt = (struct acpi_table_madt *)table; acpi_madt_rev = acpi_madt->header.revision; @@ -384,14 +385,14 @@ static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size) #ifdef CONFIG_ITANIUM has_8259 = 1; /* Firmware on old Itanium systems is broken */ #else - has_8259 = acpi_madt->flags.pcat_compat; + has_8259 = acpi_madt->flags & ACPI_MADT_PCAT_COMPAT; #endif iosapic_system_init(has_8259); /* Get base address of IPI Message Block */ - if (acpi_madt->lapic_address) - ipi_base_addr = ioremap(acpi_madt->lapic_address, 0); + if (acpi_madt->address) + ipi_base_addr = ioremap(acpi_madt->address, 0); printk(KERN_INFO PREFIX "Local APIC address %p\n", ipi_base_addr); @@ -413,23 +414,24 @@ static u32 __devinitdata pxm_flag[PXM_FLAG_LEN]; #define pxm_bit_test(bit) (test_bit(bit,(void *)pxm_flag)) static struct acpi_table_slit __initdata *slit_table; -static int get_processor_proximity_domain(struct acpi_table_processor_affinity *pa) +static int get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa) { int pxm; - pxm = pa->proximity_domain; + pxm = pa->proximity_domain_lo; if (ia64_platform_is("sn2")) - pxm += pa->reserved[0] << 8; + pxm += pa->proximity_domain_hi[0] << 8; return pxm; } -static int get_memory_proximity_domain(struct acpi_table_memory_affinity *ma) +static int get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma) { int pxm; pxm = ma->proximity_domain; if (ia64_platform_is("sn2")) - pxm += ma->reserved1[0] << 8; + pxm += ma->reserved << 8; + return pxm; } @@ -442,7 +444,7 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit) u32 len; len = sizeof(struct acpi_table_header) + 8 - + slit->localities * slit->localities; + + slit->locality_count * slit->locality_count; if (slit->header.length != len) { printk(KERN_ERR "ACPI 2.0 SLIT: size mismatch: %d expected, %d actual\n", @@ -454,11 +456,11 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit) } void __init -acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa) +acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) { int pxm; - if (!pa->flags.enabled) + if (!(pa->flags & ACPI_SRAT_CPU_ENABLED)) return; pxm = get_processor_proximity_domain(pa); @@ -467,14 +469,14 @@ acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa) pxm_bit_set(pxm); node_cpuid[srat_num_cpus].phys_id = - (pa->apic_id << 8) | (pa->lsapic_eid); + (pa->apic_id << 8) | (pa->local_sapic_eid); /* nid should be overridden as logical node id later */ node_cpuid[srat_num_cpus].nid = pxm; srat_num_cpus++; } void __init -acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) +acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) { unsigned long paddr, size; int pxm; @@ -483,13 +485,11 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) pxm = get_memory_proximity_domain(ma); /* fill node memory chunk structure */ - paddr = ma->base_addr_hi; - paddr = (paddr << 32) | ma->base_addr_lo; - size = ma->length_hi; - size = (size << 32) | ma->length_lo; + paddr = ma->base_address; + size = ma->length; /* Ignore disabled entries */ - if (!ma->flags.enabled) + if (!(ma->flags & ACPI_SRAT_MEM_ENABLED)) return; /* record this node in proximity bitmap */ @@ -560,16 +560,16 @@ void __init acpi_numa_arch_fixup(void) if (!slit_table) return; memset(numa_slit, -1, sizeof(numa_slit)); - for (i = 0; i < slit_table->localities; i++) { + for (i = 0; i < slit_table->locality_count; i++) { if (!pxm_bit_test(i)) continue; node_from = pxm_to_node(i); - for (j = 0; j < slit_table->localities; j++) { + for (j = 0; j < slit_table->locality_count; j++) { if (!pxm_bit_test(j)) continue; node_to = pxm_to_node(j); node_distance(node_from, node_to) = - slit_table->entry[i * slit_table->localities + j]; + slit_table->entry[i * slit_table->locality_count + j]; } } @@ -614,15 +614,15 @@ void acpi_unregister_gsi(u32 gsi) EXPORT_SYMBOL(acpi_unregister_gsi); -static int __init acpi_parse_fadt(unsigned long phys_addr, unsigned long size) +static int __init acpi_parse_fadt(struct acpi_table_header *table) { struct acpi_table_header *fadt_header; struct acpi_table_fadt *fadt; - if (!phys_addr || !size) + if (!table) return -EINVAL; - fadt_header = (struct acpi_table_header *)__va(phys_addr); + fadt_header = (struct acpi_table_header *)table; if (fadt_header->revision != 3) return -ENODEV; /* Only deal with ACPI 2.0 FADT */ @@ -655,7 +655,7 @@ int __init acpi_boot_init(void) * information -- the successor to MPS tables. */ - if (acpi_table_parse(ACPI_APIC, acpi_parse_madt) < 1) { + if (acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt) < 1) { printk(KERN_ERR PREFIX "Can't find MADT\n"); goto skip_madt; } @@ -663,40 +663,40 @@ int __init acpi_boot_init(void) /* Local APIC */ if (acpi_table_parse_madt - (ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0) < 0) + (ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE, acpi_parse_lapic_addr_ovr, 0) < 0) printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); - if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic, NR_CPUS) + if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC, acpi_parse_lsapic, NR_CPUS) < 1) printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries\n"); - if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0) + if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0) < 0) printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); /* I/O APIC */ if (acpi_table_parse_madt - (ACPI_MADT_IOSAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1) + (ACPI_MADT_TYPE_IO_SAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1) printk(KERN_ERR PREFIX "Error parsing MADT - no IOSAPIC entries\n"); /* System-Level Interrupt Routing */ if (acpi_table_parse_madt - (ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src, + (ACPI_MADT_TYPE_INTERRUPT_SOURCE, acpi_parse_plat_int_src, ACPI_MAX_PLATFORM_INTERRUPTS) < 0) printk(KERN_ERR PREFIX "Error parsing platform interrupt source entry\n"); if (acpi_table_parse_madt - (ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, 0) < 0) + (ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr, 0) < 0) printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); - if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, 0) < 0) + if (acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src, 0) < 0) printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); skip_madt: @@ -706,7 +706,7 @@ int __init acpi_boot_init(void) * gets interrupts such as power and sleep buttons. If it's not * on a Legacy interrupt, it needs to be setup. */ - if (acpi_table_parse(ACPI_FADT, acpi_parse_fadt) < 1) + if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt) < 1) printk(KERN_ERR PREFIX "Can't find FADT\n"); #ifdef CONFIG_SMP @@ -839,7 +839,7 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; - struct acpi_table_lsapic *lsapic; + struct acpi_madt_local_sapic *lsapic; cpumask_t tmp_map; long physid; int cpu; @@ -851,16 +851,16 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu) return -EINVAL; obj = buffer.pointer; - if (obj->type != ACPI_TYPE_BUFFER || - obj->buffer.length < sizeof(*lsapic)) { + if (obj->type != ACPI_TYPE_BUFFER) + { kfree(buffer.pointer); return -EINVAL; } - lsapic = (struct acpi_table_lsapic *)obj->buffer.pointer; + lsapic = (struct acpi_madt_local_sapic *)obj->buffer.pointer; - if ((lsapic->header.type != ACPI_MADT_LSAPIC) || - (!lsapic->flags.enabled)) { + if ((lsapic->header.type != ACPI_MADT_TYPE_LOCAL_SAPIC) || + (!lsapic->lapic_flags & ACPI_MADT_ENABLED)) { kfree(buffer.pointer); return -EINVAL; } @@ -880,7 +880,7 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu) cpu_set(cpu, cpu_present_map); ia64_cpu_to_sapicid[cpu] = physid; - ia64_acpiid_to_sapicid[lsapic->acpi_id] = ia64_cpu_to_sapicid[cpu]; + ia64_acpiid_to_sapicid[lsapic->processor_id] = ia64_cpu_to_sapicid[cpu]; *pcpu = cpu; return (0); @@ -917,7 +917,7 @@ acpi_map_iosapic(acpi_handle handle, u32 depth, void *context, void **ret) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; - struct acpi_table_iosapic *iosapic; + struct acpi_madt_io_sapic *iosapic; unsigned int gsi_base; int pxm, node; @@ -935,9 +935,9 @@ acpi_map_iosapic(acpi_handle handle, u32 depth, void *context, void **ret) return AE_OK; } - iosapic = (struct acpi_table_iosapic *)obj->buffer.pointer; + iosapic = (struct acpi_madt_io_sapic *)obj->buffer.pointer; - if (iosapic->header.type != ACPI_MADT_IOSAPIC) { + if (iosapic->header.type != ACPI_MADT_TYPE_IO_SAPIC) { kfree(buffer.pointer); return AE_OK; } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 324b0991943e..15d677e6cee9 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -620,15 +620,16 @@ void __init acpi_early_init(void) #ifdef CONFIG_X86 if (!acpi_ioapic) { - extern acpi_interrupt_flags acpi_sci_flags; + extern u8 acpi_sci_flags; /* compatible (0) means level (3) */ - if (acpi_sci_flags.trigger == 0) - acpi_sci_flags.trigger = 3; - + if (!(acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)) { + acpi_sci_flags &= ~ACPI_MADT_TRIGGER_MASK; + acpi_sci_flags |= ACPI_MADT_TRIGGER_LEVEL; + } /* Set PIC-mode SCI trigger type */ acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt, - acpi_sci_flags.trigger); + (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2); } else { extern int acpi_sci_override_gsi; /* diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 962ff29fbf07..ba4cb200314a 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -43,90 +43,92 @@ static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" }; static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; -void acpi_table_print_madt_entry(acpi_table_entry_header * header) +void acpi_table_print_madt_entry(struct acpi_subtable_header * header) { if (!header) return; switch (header->type) { - case ACPI_MADT_LAPIC: + case ACPI_MADT_TYPE_LOCAL_APIC: { - struct acpi_table_lapic *p = - (struct acpi_table_lapic *)header; + struct acpi_madt_local_apic *p = + (struct acpi_madt_local_apic *)header; printk(KERN_INFO PREFIX "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n", - p->acpi_id, p->id, - p->flags.enabled ? "enabled" : "disabled"); + p->processor_id, p->id, + (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); } break; - case ACPI_MADT_IOAPIC: + case ACPI_MADT_TYPE_IO_APIC: { - struct acpi_table_ioapic *p = - (struct acpi_table_ioapic *)header; + struct acpi_madt_io_apic *p = + (struct acpi_madt_io_apic *)header; printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n", p->id, p->address, p->global_irq_base); } break; - case ACPI_MADT_INT_SRC_OVR: + case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: { - struct acpi_table_int_src_ovr *p = - (struct acpi_table_int_src_ovr *)header; + struct acpi_madt_interrupt_override *p = + (struct acpi_madt_interrupt_override *)header; printk(KERN_INFO PREFIX "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n", - p->bus, p->bus_irq, p->global_irq, - mps_inti_flags_polarity[p->flags.polarity], - mps_inti_flags_trigger[p->flags.trigger]); - if (p->flags.reserved) + p->bus, p->source_irq, p->global_irq, + mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], + mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]); + if (p->inti_flags & + ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)) printk(KERN_INFO PREFIX "INT_SRC_OVR unexpected reserved flags: 0x%x\n", - p->flags.reserved); + p->inti_flags & + ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)); } break; - case ACPI_MADT_NMI_SRC: + case ACPI_MADT_TYPE_NMI_SOURCE: { - struct acpi_table_nmi_src *p = - (struct acpi_table_nmi_src *)header; + struct acpi_madt_nmi_source *p = + (struct acpi_madt_nmi_source *)header; printk(KERN_INFO PREFIX "NMI_SRC (%s %s global_irq %d)\n", - mps_inti_flags_polarity[p->flags.polarity], - mps_inti_flags_trigger[p->flags.trigger], + mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], + mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], p->global_irq); } break; - case ACPI_MADT_LAPIC_NMI: + case ACPI_MADT_TYPE_LOCAL_APIC_NMI: { - struct acpi_table_lapic_nmi *p = - (struct acpi_table_lapic_nmi *)header; + struct acpi_madt_local_apic_nmi *p = + (struct acpi_madt_local_apic_nmi *)header; printk(KERN_INFO PREFIX "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n", - p->acpi_id, - mps_inti_flags_polarity[p->flags.polarity], - mps_inti_flags_trigger[p->flags.trigger], + p->processor_id, + mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ], + mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], p->lint); } break; - case ACPI_MADT_LAPIC_ADDR_OVR: + case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE: { - struct acpi_table_lapic_addr_ovr *p = - (struct acpi_table_lapic_addr_ovr *)header; + struct acpi_madt_local_apic_override *p = + (struct acpi_madt_local_apic_override *)header; printk(KERN_INFO PREFIX "LAPIC_ADDR_OVR (address[%p])\n", (void *)(unsigned long)p->address); } break; - case ACPI_MADT_IOSAPIC: + case ACPI_MADT_TYPE_IO_SAPIC: { - struct acpi_table_iosapic *p = - (struct acpi_table_iosapic *)header; + struct acpi_madt_io_sapic *p = + (struct acpi_madt_io_sapic *)header; printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n", p->id, (void *)(unsigned long)p->address, @@ -134,26 +136,26 @@ void acpi_table_print_madt_entry(acpi_table_entry_header * header) } break; - case ACPI_MADT_LSAPIC: + case ACPI_MADT_TYPE_LOCAL_SAPIC: { - struct acpi_table_lsapic *p = - (struct acpi_table_lsapic *)header; + struct acpi_madt_local_sapic *p = + (struct acpi_madt_local_sapic *)header; printk(KERN_INFO PREFIX "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n", - p->acpi_id, p->id, p->eid, - p->flags.enabled ? "enabled" : "disabled"); + p->processor_id, p->id, p->eid, + (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled"); } break; - case ACPI_MADT_PLAT_INT_SRC: + case ACPI_MADT_TYPE_INTERRUPT_SOURCE: { - struct acpi_table_plat_int_src *p = - (struct acpi_table_plat_int_src *)header; + struct acpi_madt_interrupt_source *p = + (struct acpi_madt_interrupt_source *)header; printk(KERN_INFO PREFIX "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", - mps_inti_flags_polarity[p->flags.polarity], - mps_inti_flags_trigger[p->flags.trigger], - p->type, p->id, p->eid, p->iosapic_vector, + mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], + mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], + p->type, p->id, p->eid, p->io_sapic_vector, p->global_irq); } break; @@ -175,7 +177,7 @@ acpi_table_parse_madt_family(char *id, unsigned int max_entries) { struct acpi_table_header *madt = NULL; - acpi_table_entry_header *entry; + struct acpi_subtable_header *entry; unsigned int count = 0; unsigned long madt_end; @@ -183,7 +185,6 @@ acpi_table_parse_madt_family(char *id, return -EINVAL; /* Locate the MADT (if exists). There should only be one. */ - acpi_get_table(id, 0, &madt); if (!madt) { @@ -195,17 +196,17 @@ acpi_table_parse_madt_family(char *id, /* Parse all entries looking for a match. */ - entry = (acpi_table_entry_header *) + entry = (struct acpi_subtable_header *) ((unsigned long)madt + madt_size); - while (((unsigned long)entry) + sizeof(acpi_table_entry_header) < + while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < madt_end) { if (entry->type == entry_id && (!max_entries || count++ < max_entries)) if (handler(entry, madt_end)) return -EINVAL; - entry = (acpi_table_entry_header *) + entry = (struct acpi_subtable_header *) ((unsigned long)entry + entry->length); } if (max_entries && count > max_entries) { @@ -217,10 +218,10 @@ acpi_table_parse_madt_family(char *id, } int __init -acpi_table_parse_madt(enum acpi_madt_entry_id id, +acpi_table_parse_madt(enum acpi_madt_type id, acpi_madt_entry_handler handler, unsigned int max_entries) { - return acpi_table_parse_madt_family("APIC", + return acpi_table_parse_madt_family(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), id, handler, max_entries); } @@ -228,7 +229,6 @@ acpi_table_parse_madt(enum acpi_madt_entry_id id, int __init acpi_table_parse(char *id, acpi_table_handler handler) { struct acpi_table_header *table = NULL; - if (!handler) return -EINVAL; @@ -245,10 +245,11 @@ int __init acpi_table_parse(char *id, acpi_table_handler handler) * * find RSDP, find and checksum SDT/XSDT. * checksum all tables, print SDT/XSDT - * + * * result: sdt_entry[] is initialized */ + int __init acpi_table_init(void) { acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 5a2b3633220e..fac7a7b1f5f9 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -58,106 +58,6 @@ typedef struct { u8 length; } __attribute__ ((packed)) acpi_table_entry_header; -/* Multiple APIC Description Table (MADT) */ - -enum acpi_madt_entry_id { - ACPI_MADT_LAPIC = 0, - ACPI_MADT_IOAPIC, - ACPI_MADT_INT_SRC_OVR, - ACPI_MADT_NMI_SRC, - ACPI_MADT_LAPIC_NMI, - ACPI_MADT_LAPIC_ADDR_OVR, - ACPI_MADT_IOSAPIC, - ACPI_MADT_LSAPIC, - ACPI_MADT_PLAT_INT_SRC, - ACPI_MADT_ENTRY_COUNT -}; - -typedef struct { - u16 polarity:2; - u16 trigger:2; - u16 reserved:12; -} __attribute__ ((packed)) acpi_interrupt_flags; - -struct acpi_table_lapic { - acpi_table_entry_header header; - u8 acpi_id; - u8 id; - struct { - u32 enabled:1; - u32 reserved:31; - } flags; -} __attribute__ ((packed)); - -struct acpi_table_ioapic { - acpi_table_entry_header header; - u8 id; - u8 reserved; - u32 address; - u32 global_irq_base; -} __attribute__ ((packed)); - -struct acpi_table_int_src_ovr { - acpi_table_entry_header header; - u8 bus; - u8 bus_irq; - u32 global_irq; - acpi_interrupt_flags flags; -} __attribute__ ((packed)); - -struct acpi_table_nmi_src { - acpi_table_entry_header header; - acpi_interrupt_flags flags; - u32 global_irq; -} __attribute__ ((packed)); - -struct acpi_table_lapic_nmi { - acpi_table_entry_header header; - u8 acpi_id; - acpi_interrupt_flags flags; - u8 lint; -} __attribute__ ((packed)); - -struct acpi_table_lapic_addr_ovr { - acpi_table_entry_header header; - u8 reserved[2]; - u64 address; -} __attribute__ ((packed)); - -struct acpi_table_iosapic { - acpi_table_entry_header header; - u8 id; - u8 reserved; - u32 global_irq_base; - u64 address; -} __attribute__ ((packed)); - -struct acpi_table_lsapic { - acpi_table_entry_header header; - u8 acpi_id; - u8 id; - u8 eid; - u8 reserved[3]; - struct { - u32 enabled:1; - u32 reserved:31; - } flags; -} __attribute__ ((packed)); - -struct acpi_table_plat_int_src { - acpi_table_entry_header header; - acpi_interrupt_flags flags; - u8 type; /* See acpi_interrupt_type */ - u8 id; - u8 eid; - u8 iosapic_vector; - u32 global_irq; - struct { - u32 cpei_override_flag:1; - u32 reserved:31; - } plint_flags; -} __attribute__ ((packed)); - enum acpi_interrupt_id { ACPI_INTERRUPT_PMI = 1, ACPI_INTERRUPT_INIT, @@ -285,7 +185,7 @@ typedef int (*acpi_table_handler) (struct acpi_table_header *header); extern acpi_table_handler acpi_table_ops[ACPI_TABLE_COUNT]; -typedef int (*acpi_madt_entry_handler) (acpi_table_entry_header *header, const unsigned long end); +typedef int (*acpi_madt_entry_handler) (struct acpi_subtable_header *header, const unsigned long end); char * __acpi_map_table (unsigned long phys_addr, unsigned long size); unsigned long acpi_find_rsdp (void); @@ -295,11 +195,11 @@ int acpi_numa_init (void); int acpi_table_init (void); int acpi_table_parse (char *id, acpi_table_handler handler); -int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); +int acpi_table_parse_madt (enum acpi_madt_type id, acpi_madt_entry_handler handler, unsigned int max_entries); int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); int acpi_parse_mcfg (struct acpi_table_header *header); void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr); -void acpi_table_print_madt_entry (acpi_table_entry_header *madt); +void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); void acpi_table_print_srat_entry (acpi_table_entry_header *srat); /* the following four functions are architecture-dependent */ -- cgit v1.2.3 From 15a58ed12142939d51076380e6e58af477ad96ec Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Fri, 2 Feb 2007 19:48:22 +0300 Subject: ACPICA: Remove duplicate table definitions (non-conflicting), cont Signed-off-by: Len Brown --- arch/i386/kernel/acpi/boot.c | 18 ++-- arch/i386/kernel/acpi/earlyquirk.c | 2 +- arch/i386/pci/mmconfig.c | 24 +++--- arch/x86_64/kernel/early-quirks.c | 4 +- arch/x86_64/mm/srat.c | 48 +++++------ arch/x86_64/pci/mmconfig.c | 29 +++---- drivers/acpi/blacklist.c | 2 +- drivers/acpi/ec.c | 3 +- drivers/acpi/numa.c | 77 +++++++++-------- drivers/char/ipmi/ipmi_si_intf.c | 18 ++-- drivers/char/tpm/tpm_bios.c | 8 +- drivers/firmware/pcdp.c | 2 +- drivers/pci/hotplug/acpiphp_glue.c | 10 +-- include/asm-i386/mach-es7000/mach_mpparse.h | 17 ++-- include/linux/acpi.h | 123 ++-------------------------- 15 files changed, 135 insertions(+), 250 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 5fafbacdd4cb..2147511ea78d 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -166,7 +166,7 @@ char *__acpi_map_table(unsigned long phys, unsigned long size) #ifdef CONFIG_PCI_MMCONFIG /* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ -struct acpi_table_mcfg_config *pci_mmcfg_config; +struct acpi_mcfg_allocation *pci_mmcfg_config; int pci_mmcfg_config_num; int __init acpi_parse_mcfg(struct acpi_table_header *header) @@ -179,17 +179,13 @@ int __init acpi_parse_mcfg(struct acpi_table_header *header) return -EINVAL; mcfg = (struct acpi_table_mcfg *)header; - if (!mcfg) { - printk(KERN_WARNING PREFIX "Unable to map MCFG\n"); - return -ENODEV; - } /* how many config structures do we have */ pci_mmcfg_config_num = 0; i = header->length - sizeof(struct acpi_table_mcfg); - while (i >= sizeof(struct acpi_table_mcfg_config)) { + while (i >= sizeof(struct acpi_mcfg_allocation)) { ++pci_mmcfg_config_num; - i -= sizeof(struct acpi_table_mcfg_config); + i -= sizeof(struct acpi_mcfg_allocation); }; if (pci_mmcfg_config_num == 0) { printk(KERN_ERR PREFIX "MMCONFIG has no entries\n"); @@ -206,7 +202,7 @@ int __init acpi_parse_mcfg(struct acpi_table_header *header) memcpy(pci_mmcfg_config, &mcfg[1], config_size); for (i = 0; i < pci_mmcfg_config_num; ++i) { - if (pci_mmcfg_config[i].base_reserved) { + if (pci_mmcfg_config[i].address > 0xFFFFFFFF) { printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n"); kfree(pci_mmcfg_config); @@ -220,14 +216,14 @@ int __init acpi_parse_mcfg(struct acpi_table_header *header) #endif /* CONFIG_PCI_MMCONFIG */ #ifdef CONFIG_X86_LOCAL_APIC -static int __init acpi_parse_madt(struct acpi_table_header *header) +static int __init acpi_parse_madt(struct acpi_table_header *table) { struct acpi_table_madt *madt = NULL; - if (!header|| !cpu_has_apic) + if (!cpu_has_apic) return -EINVAL; - madt = (struct acpi_table_madt *)header; + madt = (struct acpi_table_madt *)table; if (!madt) { printk(KERN_WARNING PREFIX "Unable to map MADT\n"); return -ENODEV; diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c index 4261c8501b7e..bf86f7662d8b 100644 --- a/arch/i386/kernel/acpi/earlyquirk.c +++ b/arch/i386/kernel/acpi/earlyquirk.c @@ -30,7 +30,7 @@ static int __init check_bridge(int vendor, int device) is enabled. */ if (!acpi_use_timer_override && vendor == PCI_VENDOR_ID_NVIDIA) { nvidia_hpet_detected = 0; - acpi_table_parse("HPET", nvidia_hpet_check); + acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check); if (nvidia_hpet_detected == 0) { acpi_skip_timer_override = 1; printk(KERN_INFO "Nvidia board " diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index 80522e331e34..5700220dcf5f 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c @@ -36,7 +36,7 @@ static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32); static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) { int cfg_num = -1; - struct acpi_table_mcfg_config *cfg; + struct acpi_mcfg_allocation *cfg; if (seg == 0 && bus < MAX_CHECK_BUS && test_bit(PCI_SLOT(devfn) + 32*bus, fallback_slots)) @@ -48,11 +48,11 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) break; } cfg = &pci_mmcfg_config[cfg_num]; - if (cfg->pci_segment_group_number != seg) + if (cfg->pci_segment != seg) continue; if ((cfg->start_bus_number <= bus) && (cfg->end_bus_number >= bus)) - return cfg->base_address; + return cfg->address; } /* Handle more broken MCFG tables on Asus etc. @@ -60,9 +60,9 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) this applies to all busses. */ cfg = &pci_mmcfg_config[0]; if (pci_mmcfg_config_num == 1 && - cfg->pci_segment_group_number == 0 && + cfg->pci_segment == 0 && (cfg->start_bus_number | cfg->end_bus_number) == 0) - return cfg->base_address; + return cfg->address; /* Fall back to type 0 */ return 0; @@ -125,7 +125,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus, unsigned long flags; u32 base; - if ((bus > 255) || (devfn > 255) || (reg > 4095)) + if ((bus > 255) || (devfn > 255) || (reg > 4095)) return -EINVAL; base = get_base_addr(seg, bus, devfn); @@ -199,19 +199,19 @@ void __init pci_mmcfg_init(int type) if ((pci_probe & PCI_PROBE_MMCONF) == 0) return; - acpi_table_parse("MCFG", acpi_parse_mcfg); + acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); if ((pci_mmcfg_config_num == 0) || (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].base_address == 0)) + (pci_mmcfg_config[0].address == 0)) return; /* Only do this check when type 1 works. If it doesn't work assume we run on a Mac and always use MCFG */ - if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].base_address, - pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN, + if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].address, + pci_mmcfg_config[0].address + MMCONFIG_APER_MIN, E820_RESERVED)) { - printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n", - pci_mmcfg_config[0].base_address); + printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not E820-reserved\n", + (unsigned long)pci_mmcfg_config[0].address); printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); return; } diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c index 49802f1bee94..bd30d138113f 100644 --- a/arch/x86_64/kernel/early-quirks.c +++ b/arch/x86_64/kernel/early-quirks.c @@ -32,7 +32,7 @@ static void via_bugs(void) static int nvidia_hpet_detected __initdata; -static int __init nvidia_hpet_check(unsigned long phys, unsigned long size) +static int __init nvidia_hpet_check(struct acpi_table_header *header) { nvidia_hpet_detected = 1; return 0; @@ -53,7 +53,7 @@ static void nvidia_bugs(void) return; nvidia_hpet_detected = 0; - acpi_table_parse(ACPI_HPET, nvidia_hpet_check); + acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check); if (nvidia_hpet_detected == 0) { acpi_skip_timer_override = 1; printk(KERN_INFO "Nvidia board " diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c index 1087e150a218..2efe215fc76a 100644 --- a/arch/x86_64/mm/srat.c +++ b/arch/x86_64/mm/srat.c @@ -101,7 +101,7 @@ static __init inline int srat_disabled(void) static __init int slit_valid(struct acpi_table_slit *slit) { int i, j; - int d = slit->localities; + int d = slit->locality_count; for (i = 0; i < d; i++) { for (j = 0; j < d; j++) { u8 val = slit->entry[d*i + j]; @@ -127,18 +127,18 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit) /* Callback for Proximity Domain -> LAPIC mapping */ void __init -acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa) +acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) { int pxm, node; if (srat_disabled()) return; - if (pa->header.length != sizeof(struct acpi_table_processor_affinity)) { + if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) { bad_srat(); return; } - if (pa->flags.enabled == 0) + if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) return; - pxm = pa->proximity_domain; + pxm = pa->proximity_domain_lo; node = setup_node(pxm); if (node < 0) { printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); @@ -254,21 +254,21 @@ static int reserve_hotadd(int node, unsigned long start, unsigned long end) /* Looks good */ if (nd->start == nd->end) { - nd->start = start; - nd->end = end; + nd->start = start; + nd->end = end; changed = 1; - } else { - if (nd->start == end) { - nd->start = start; + } else { + if (nd->start == end) { + nd->start = start; changed = 1; } - if (nd->end == start) { - nd->end = end; + if (nd->end == start) { + nd->end = end; changed = 1; } if (!changed) printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n"); - } + } ret = update_end_of_memory(nd->end); @@ -279,7 +279,7 @@ static int reserve_hotadd(int node, unsigned long start, unsigned long end) /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ void __init -acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) +acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) { struct bootnode *nd, oldnode; unsigned long start, end; @@ -288,16 +288,17 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) if (srat_disabled()) return; - if (ma->header.length != sizeof(struct acpi_table_memory_affinity)) { + if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) { bad_srat(); return; } - if (ma->flags.enabled == 0) + if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) return; - if (ma->flags.hot_pluggable && !save_add_info()) + + if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info()) return; - start = ma->base_addr_lo | ((u64)ma->base_addr_hi << 32); - end = start + (ma->length_lo | ((u64)ma->length_hi << 32)); + start = ma->base_address; + end = start + ma->length; pxm = ma->proximity_domain; node = setup_node(pxm); if (node < 0) { @@ -337,7 +338,8 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) push_node_boundaries(node, nd->start >> PAGE_SHIFT, nd->end >> PAGE_SHIFT); - if (ma->flags.hot_pluggable && (reserve_hotadd(node, start, end) < 0)) { + if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && + (reserve_hotadd(node, start, end) < 0)) { /* Ignore hotadd region. Undo damage */ printk(KERN_NOTICE "SRAT: Hotplug region ignored\n"); *nd = oldnode; @@ -394,7 +396,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) /* First clean up the node list */ for (i = 0; i < MAX_NUMNODES; i++) { - cutoff_node(i, start, end); + cutoff_node(i, start, end); if ((nodes[i].end - nodes[i].start) < NODE_MIN_SIZE) { unparse_node(i); node_set_offline(i); @@ -426,7 +428,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) if (!node_online(i)) setup_node_bootmem(i, nodes[i].start, nodes[i].end); - for (i = 0; i < NR_CPUS; i++) { + for (i = 0; i < NR_CPUS; i++) { if (cpu_to_node[i] == NUMA_NO_NODE) continue; if (!node_isset(cpu_to_node[i], nodes_parsed)) @@ -461,7 +463,7 @@ int __node_distance(int a, int b) if (!acpi_slit) return a == b ? 10 : 20; - index = acpi_slit->localities * node_to_pxm(a); + index = acpi_slit->locality_count * node_to_pxm(a); return acpi_slit->entry[index + node_to_pxm(b)]; } diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c index f8b6b2800a62..faabb6e87f12 100644 --- a/arch/x86_64/pci/mmconfig.c +++ b/arch/x86_64/pci/mmconfig.c @@ -1,6 +1,6 @@ /* * mmconfig.c - Low-level direct PCI config space access via MMCONFIG - * + * * This is an 64bit optimized version that always keeps the full mmconfig * space mapped. This allows lockless config space operation. */ @@ -25,7 +25,7 @@ static DECLARE_BITMAP(fallback_slots, 32*MAX_CHECK_BUS); /* Static virtual mapping of the MMCONFIG aperture */ struct mmcfg_virt { - struct acpi_table_mcfg_config *cfg; + struct acpi_mcfg_allocation *cfg; char __iomem *virt; }; static struct mmcfg_virt *pci_mmcfg_virt; @@ -33,14 +33,14 @@ static struct mmcfg_virt *pci_mmcfg_virt; static char __iomem *get_virt(unsigned int seg, unsigned bus) { int cfg_num = -1; - struct acpi_table_mcfg_config *cfg; + struct acpi_mcfg_allocation *cfg; while (1) { ++cfg_num; if (cfg_num >= pci_mmcfg_config_num) break; cfg = pci_mmcfg_virt[cfg_num].cfg; - if (cfg->pci_segment_group_number != seg) + if (cfg->pci_segment != seg) continue; if ((cfg->start_bus_number <= bus) && (cfg->end_bus_number >= bus)) @@ -52,7 +52,7 @@ static char __iomem *get_virt(unsigned int seg, unsigned bus) this applies to all busses. */ cfg = &pci_mmcfg_config[0]; if (pci_mmcfg_config_num == 1 && - cfg->pci_segment_group_number == 0 && + cfg->pci_segment == 0 && (cfg->start_bus_number | cfg->end_bus_number) == 0) return pci_mmcfg_virt[0].virt; @@ -170,19 +170,19 @@ void __init pci_mmcfg_init(int type) if ((pci_probe & PCI_PROBE_MMCONF) == 0) return; - acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); + acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); if ((pci_mmcfg_config_num == 0) || (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].base_address == 0)) + (pci_mmcfg_config[0].address == 0)) return; /* Only do this check when type 1 works. If it doesn't work assume we run on a Mac and always use MCFG */ - if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].base_address, - pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN, + if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].address, + pci_mmcfg_config[0].address + MMCONFIG_APER_MIN, E820_RESERVED)) { - printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n", - pci_mmcfg_config[0].base_address); + printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not E820-reserved\n", + (unsigned long)pci_mmcfg_config[0].address); printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); return; } @@ -194,15 +194,16 @@ void __init pci_mmcfg_init(int type) } for (i = 0; i < pci_mmcfg_config_num; ++i) { pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i]; - pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, + pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].address, MMCONFIG_APER_MAX); if (!pci_mmcfg_virt[i].virt) { printk(KERN_ERR "PCI: Cannot map mmconfig aperture for " "segment %d\n", - pci_mmcfg_config[i].pci_segment_group_number); + pci_mmcfg_config[i].pci_segment); return; } - printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address); + printk(KERN_INFO "PCI: Using MMCONFIG at %lx\n", + (unsigned long)pci_mmcfg_config[i].address); } unreachable_devices(); diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index bdc169bc054a..c8f4cac9d84d 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -79,7 +79,7 @@ static int __init blacklist_by_year(void) { int year = dmi_get_year(DMI_BIOS_DATE); /* Doesn't exist? Likely an old system */ - if (year == -1) + if (year == -1) return 1; /* 0? Likely a buggy new BIOS */ if (year == 0) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 710364e6c586..743ce27fa0bb 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -872,7 +872,8 @@ static int __init acpi_ec_get_real_ecdt(void) acpi_status status; struct acpi_table_ecdt *ecdt_ptr; - status = acpi_get_table("ECDT", 1, (struct acpi_table_header **)&ecdt_ptr); + status = acpi_get_table(ACPI_SIG_ECDT, 1, + (struct acpi_table_header **)&ecdt_ptr); if (ACPI_FAILURE(status)) return -ENODEV; diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index bd96a7045925..4a9faff4c01d 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -45,7 +45,7 @@ int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS] int __cpuinitdata node_to_pxm_map[MAX_NUMNODES] = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; -extern int __init acpi_table_parse_madt_family(enum acpi_table_id id, +extern int __init acpi_table_parse_madt_family(char *id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler, @@ -89,7 +89,7 @@ void __cpuinit acpi_unmap_pxm_to_node(int node) node_clear(node, nodes_found_map); } -void __init acpi_table_print_srat_entry(acpi_table_entry_header * header) +void __init acpi_table_print_srat_entry(struct acpi_subtable_header * header) { ACPI_FUNCTION_NAME("acpi_table_print_srat_entry"); @@ -99,36 +99,35 @@ void __init acpi_table_print_srat_entry(acpi_table_entry_header * header) switch (header->type) { - case ACPI_SRAT_PROCESSOR_AFFINITY: + case ACPI_SRAT_TYPE_CPU_AFFINITY: #ifdef ACPI_DEBUG_OUTPUT { - struct acpi_table_processor_affinity *p = - (struct acpi_table_processor_affinity *)header; + struct acpi_srat_cpu_affinity *p = + (struct acpi_srat_cpu_affinity *)header; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n", - p->apic_id, p->lsapic_eid, - p->proximity_domain, - p->flags. - enabled ? "enabled" : "disabled")); + p->apic_id, p->local_sapic_eid, + p->proximity_domain_lo, + (p->flags & ACPI_SRAT_CPU_ENABLED)? + "enabled" : "disabled")); } #endif /* ACPI_DEBUG_OUTPUT */ break; - case ACPI_SRAT_MEMORY_AFFINITY: + case ACPI_SRAT_TYPE_MEMORY_AFFINITY: #ifdef ACPI_DEBUG_OUTPUT { - struct acpi_table_memory_affinity *p = - (struct acpi_table_memory_affinity *)header; + struct acpi_srat_mem_affinity *p = + (struct acpi_srat_mem_affinity *)header; ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n", - p->base_addr_hi, p->base_addr_lo, - p->length_hi, p->length_lo, + "SRAT Memory (0x%lx length 0x%lx type 0x%x) in proximity domain %d %s%s\n", + (unsigned long)p->base_address, + (unsigned long)p->length, p->memory_type, p->proximity_domain, - p->flags. - enabled ? "enabled" : "disabled", - p->flags. - hot_pluggable ? " hot-pluggable" : - "")); + (p->flags & ACPI_SRAT_MEM_ENABLED)? + "enabled" : "disabled", + (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)? + " hot-pluggable" : "")); } #endif /* ACPI_DEBUG_OUTPUT */ break; @@ -141,18 +140,18 @@ void __init acpi_table_print_srat_entry(acpi_table_entry_header * header) } } -static int __init acpi_parse_slit(unsigned long phys_addr, unsigned long size) +static int __init acpi_parse_slit(struct acpi_table_header *table) { struct acpi_table_slit *slit; u32 localities; - if (!phys_addr || !size) + if (!table) return -EINVAL; - slit = (struct acpi_table_slit *)__va(phys_addr); + slit = (struct acpi_table_slit *)table; /* downcast just for %llu vs %lu for i386/ia64 */ - localities = (u32) slit->localities; + localities = (u32) slit->locality_count; acpi_numa_slit_init(slit); @@ -160,12 +159,12 @@ static int __init acpi_parse_slit(unsigned long phys_addr, unsigned long size) } static int __init -acpi_parse_processor_affinity(acpi_table_entry_header * header, +acpi_parse_processor_affinity(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_processor_affinity *processor_affinity; + struct acpi_srat_cpu_affinity *processor_affinity; - processor_affinity = (struct acpi_table_processor_affinity *)header; + processor_affinity = (struct acpi_srat_cpu_affinity *)header; if (!processor_affinity) return -EINVAL; @@ -178,12 +177,12 @@ acpi_parse_processor_affinity(acpi_table_entry_header * header, } static int __init -acpi_parse_memory_affinity(acpi_table_entry_header * header, +acpi_parse_memory_affinity(struct acpi_subtable_header * header, const unsigned long end) { - struct acpi_table_memory_affinity *memory_affinity; + struct acpi_srat_mem_affinity *memory_affinity; - memory_affinity = (struct acpi_table_memory_affinity *)header; + memory_affinity = (struct acpi_srat_mem_affinity *)header; if (!memory_affinity) return -EINVAL; @@ -195,23 +194,23 @@ acpi_parse_memory_affinity(acpi_table_entry_header * header, return 0; } -static int __init acpi_parse_srat(unsigned long phys_addr, unsigned long size) +static int __init acpi_parse_srat(struct acpi_table_header *table) { struct acpi_table_srat *srat; - if (!phys_addr || !size) + if (!table) return -EINVAL; - srat = (struct acpi_table_srat *)__va(phys_addr); + srat = (struct acpi_table_srat *)table; return 0; } int __init -acpi_table_parse_srat(enum acpi_srat_entry_id id, +acpi_table_parse_srat(enum acpi_srat_type id, acpi_madt_entry_handler handler, unsigned int max_entries) { - return acpi_table_parse_madt_family(ACPI_SRAT, + return acpi_table_parse_madt_family(ACPI_SIG_SRAT, sizeof(struct acpi_table_srat), id, handler, max_entries); } @@ -221,17 +220,17 @@ int __init acpi_numa_init(void) int result; /* SRAT: Static Resource Affinity Table */ - result = acpi_table_parse(ACPI_SRAT, acpi_parse_srat); + result = acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat); if (result > 0) { - result = acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY, + result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY, acpi_parse_processor_affinity, NR_CPUS); - result = acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific + result = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific } /* SLIT: System Locality Information Table */ - result = acpi_table_parse(ACPI_SLIT, acpi_parse_slit); + result = acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); acpi_numa_arch_fixup(); return 0; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index f1afd26a509f..a7b33d2f5991 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1802,7 +1802,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) return -ENODEV; } - if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) addr_space = IPMI_MEM_ADDR_SPACE; else addr_space = IPMI_IO_ADDR_SPACE; @@ -1848,19 +1848,19 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) info->irq_setup = NULL; } - if (spmi->addr.register_bit_width) { + if (spmi->addr.bit_width) { /* A (hopefully) properly formed register bit width. */ - info->io.regspacing = spmi->addr.register_bit_width / 8; + info->io.regspacing = spmi->addr.bit_width / 8; } else { info->io.regspacing = DEFAULT_REGSPACING; } info->io.regsize = info->io.regspacing; - info->io.regshift = spmi->addr.register_bit_offset; + info->io.regshift = spmi->addr.bit_offset; - if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { info->io_setup = mem_setup; info->io.addr_type = IPMI_IO_ADDR_SPACE; - } else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + } else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) { info->io_setup = port_setup; info->io.addr_type = IPMI_MEM_ADDR_SPACE; } else { @@ -1888,10 +1888,8 @@ static __devinit void acpi_find_bmc(void) return; for (i = 0; ; i++) { - status = acpi_get_firmware_table("SPMI", i+1, - ACPI_LOGICAL_ADDRESSING, - (struct acpi_table_header **) - &spmi); + status = acpi_get_table(ACPI_SIG_SPMI, i+1, + (struct acpi_table_header **)&spmi); if (status != AE_OK) return; diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index a611972024e6..7fca5f470beb 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -372,10 +372,8 @@ static int read_log(struct tpm_bios_log *log) } /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ - status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1, - ACPI_LOGICAL_ADDRESSING, - (struct acpi_table_header **) - &buff); + status = acpi_get_table(ACPI_SIG_TCPA, 1, + (struct acpi_table_header **)&buff); if (ACPI_FAILURE(status)) { printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n", @@ -409,7 +407,7 @@ static int read_log(struct tpm_bios_log *log) log->bios_event_log_end = log->bios_event_log + len; - acpi_os_map_memory(start, len, (void *) &virt); + virt = acpi_os_map_memory(start, len); memcpy(log->bios_event_log, virt, len); diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c index c2ad72fefd9d..2b4b76e8bd72 100644 --- a/drivers/firmware/pcdp.c +++ b/drivers/firmware/pcdp.c @@ -26,7 +26,7 @@ setup_serial_console(struct pcdp_uart *uart) static char options[64], *p = options; char parity; - mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY); + mmio = (uart->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY); p += sprintf(p, "console=uart,%s,0x%lx", mmio ? "mmio" : "io", uart->addr.address); if (uart->baud) { diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index bd1faebf61a0..fca978fb158e 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -773,13 +773,13 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base) goto out; table = obj->buffer.pointer; - switch (((acpi_table_entry_header *)table)->type) { - case ACPI_MADT_IOSAPIC: - *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base; + switch (((struct acpi_subtable_header *)table)->type) { + case ACPI_MADT_TYPE_IO_SAPIC: + *gsi_base = ((struct acpi_madt_io_sapic *)table)->global_irq_base; result = 0; break; - case ACPI_MADT_IOAPIC: - *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base; + case ACPI_MADT_TYPE_IO_APIC: + *gsi_base = ((struct acpi_madt_io_apic *)table)->global_irq_base; result = 0; break; default: diff --git a/include/asm-i386/mach-es7000/mach_mpparse.h b/include/asm-i386/mach-es7000/mach_mpparse.h index 99f66be240be..24990e546da3 100644 --- a/include/asm-i386/mach-es7000/mach_mpparse.h +++ b/include/asm-i386/mach-es7000/mach_mpparse.h @@ -3,13 +3,13 @@ #include -static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, +static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, struct mpc_config_translation *translation) { Dprintk("Bus #%d is %s\n", m->mpc_busid, name); } -static inline void mpc_oem_pci_bus(struct mpc_config_bus *m, +static inline void mpc_oem_pci_bus(struct mpc_config_bus *m, struct mpc_config_translation *translation) { } @@ -22,7 +22,7 @@ static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid) { if (mpc->mpc_oemptr) { - struct mp_config_oemtable *oem_table = + struct mp_config_oemtable *oem_table = (struct mp_config_oemtable *)mpc->mpc_oemptr; if (!strncmp(oem, "UNISYS", 6)) return parse_unisys_oem((char *)oem_table); @@ -31,12 +31,13 @@ static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, } #ifdef CONFIG_ACPI + static inline int es7000_check_dsdt(void) { - struct acpi_table_header *header = NULL; - if(!acpi_get_table_header_early(ACPI_DSDT, &header)) - acpi_table_print(header, 0); - if (!strncmp(header->oem_id, "UNISYS", 6)) + struct acpi_table_header header; + memcpy(&header, 0, sizeof(struct acpi_table_header)); + acpi_get_table_header(ACPI_SIG_DSDT, 0, &header); + if (!strncmp(header.oem_id, "UNISYS", 6)) return 1; return 0; } @@ -44,7 +45,7 @@ static inline int es7000_check_dsdt(void) /* Hook from generic ACPI tables.c */ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { - unsigned long oem_addr; + unsigned long oem_addr; if (!find_unisys_acpi_oem_table(&oem_addr)) { if (es7000_check_dsdt()) return parse_unisys_oem((char *)oem_addr); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index fac7a7b1f5f9..815f1fb4ce21 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -53,11 +53,6 @@ enum acpi_irq_model_id { extern enum acpi_irq_model_id acpi_irq_model; -typedef struct { - u8 type; - u8 length; -} __attribute__ ((packed)) acpi_table_entry_header; - enum acpi_interrupt_id { ACPI_INTERRUPT_PMI = 1, ACPI_INTERRUPT_INIT, @@ -67,74 +62,6 @@ enum acpi_interrupt_id { #define ACPI_SPACE_MEM 0 -struct acpi_gen_regaddr { - u8 space_id; - u8 bit_width; - u8 bit_offset; - u8 resv; - u32 addrl; - u32 addrh; -} __attribute__ ((packed)); - -/* - * Simple Boot Flags - * http://www.microsoft.com/whdc/hwdev/resources/specs/simp_bios.mspx - */ -struct acpi_table_sbf -{ - u8 sbf_signature[4]; - u32 sbf_len; - u8 sbf_revision; - u8 sbf_csum; - u8 sbf_oemid[6]; - u8 sbf_oemtable[8]; - u8 sbf_revdata[4]; - u8 sbf_creator[4]; - u8 sbf_crearev[4]; - u8 sbf_cmos; - u8 sbf_spare[3]; -} __attribute__ ((packed)); - -/* - * System Resource Affinity Table (SRAT) - * http://www.microsoft.com/whdc/hwdev/platform/proc/SRAT.mspx - */ - -enum acpi_srat_entry_id { - ACPI_SRAT_PROCESSOR_AFFINITY = 0, - ACPI_SRAT_MEMORY_AFFINITY, - ACPI_SRAT_ENTRY_COUNT -}; - -struct acpi_table_processor_affinity { - acpi_table_entry_header header; - u8 proximity_domain; - u8 apic_id; - struct { - u32 enabled:1; - u32 reserved:31; - } flags; - u8 lsapic_eid; - u8 reserved[7]; -} __attribute__ ((packed)); - -struct acpi_table_memory_affinity { - acpi_table_entry_header header; - u8 proximity_domain; - u8 reserved1[5]; - u32 base_addr_lo; - u32 base_addr_hi; - u32 length_lo; - u32 length_hi; - u32 memory_type; /* See acpi_address_range_id */ - struct { - u32 enabled:1; - u32 hot_pluggable:1; - u32 reserved:30; - } flags; - u64 reserved2; -} __attribute__ ((packed)); - enum acpi_address_range_id { ACPI_ADDRESS_RANGE_MEMORY = 1, ACPI_ADDRESS_RANGE_RESERVED = 2, @@ -144,46 +71,9 @@ enum acpi_address_range_id { }; -/* PCI MMCONFIG */ - -/* Defined in PCI Firmware Specification 3.0 */ -struct acpi_table_mcfg_config { - u32 base_address; - u32 base_reserved; - u16 pci_segment_group_number; - u8 start_bus_number; - u8 end_bus_number; - u8 reserved[4]; -} __attribute__ ((packed)); - /* Table Handlers */ -enum acpi_table_id { - ACPI_TABLE_UNKNOWN = 0, - ACPI_APIC, - ACPI_BOOT, - ACPI_DBGP, - ACPI_DSDT, - ACPI_ECDT, - ACPI_ETDT, - ACPI_FADT, - ACPI_FACS, - ACPI_OEMX, - ACPI_PSDT, - ACPI_SBST, - ACPI_SLIT, - ACPI_SPCR, - ACPI_SRAT, - ACPI_SSDT, - ACPI_SPMI, - ACPI_HPET, - ACPI_MCFG, - ACPI_TABLE_COUNT -}; - -typedef int (*acpi_table_handler) (struct acpi_table_header *header); - -extern acpi_table_handler acpi_table_ops[ACPI_TABLE_COUNT]; +typedef int (*acpi_table_handler) (struct acpi_table_header *table); typedef int (*acpi_madt_entry_handler) (struct acpi_subtable_header *header, const unsigned long end); @@ -196,11 +86,10 @@ int acpi_numa_init (void); int acpi_table_init (void); int acpi_table_parse (char *id, acpi_table_handler handler); int acpi_table_parse_madt (enum acpi_madt_type id, acpi_madt_entry_handler handler, unsigned int max_entries); -int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); +int acpi_table_parse_srat (enum acpi_srat_type id, acpi_madt_entry_handler handler, unsigned int max_entries); int acpi_parse_mcfg (struct acpi_table_header *header); -void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr); void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); -void acpi_table_print_srat_entry (acpi_table_entry_header *srat); +void acpi_table_print_srat_entry (struct acpi_subtable_header *srat); /* the following four functions are architecture-dependent */ #ifdef CONFIG_HAVE_ARCH_PARSE_SRAT @@ -211,8 +100,8 @@ void acpi_table_print_srat_entry (acpi_table_entry_header *srat); #define acpi_numa_arch_fixup() do {} while (0) #else void acpi_numa_slit_init (struct acpi_table_slit *slit); -void acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa); -void acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma); +void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa); +void acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma); void acpi_numa_arch_fixup(void); #endif @@ -227,7 +116,7 @@ int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base); extern int acpi_mp_config; -extern struct acpi_table_mcfg_config *pci_mmcfg_config; +extern struct acpi_mcfg_allocation *pci_mmcfg_config; extern int pci_mmcfg_config_num; extern int sbf_port; -- cgit v1.2.3 From f22ee4edf63e7480511112d9965c71e07be3f8b7 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 26 Dec 2006 15:11:23 +0100 Subject: mmc: replace host->card_busy As card_busy was only used to indicate if the host was exclusively claimed and not really used to identify a particular card, replacing it with just a boolean makes things a lot more easily understandable. Signed-off-by: Pierre Ossman --- drivers/mmc/mmc.c | 16 ++++++++-------- include/linux/mmc/host.h | 5 +++-- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 6f2a282e2b97..105f419d08cb 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -103,7 +103,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); - WARN_ON(host->card_busy == NULL); + WARN_ON(!host->claimed); mrq->cmd->error = 0; mrq->cmd->mrq = mrq; @@ -157,7 +157,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries { struct mmc_request mrq; - BUG_ON(host->card_busy == NULL); + BUG_ON(!host->claimed); memset(&mrq, 0, sizeof(struct mmc_request)); @@ -195,7 +195,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca, int i, err; - BUG_ON(host->card_busy == NULL); + BUG_ON(!host->claimed); BUG_ON(retries < 0); err = MMC_ERR_INVALID; @@ -320,14 +320,14 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card) spin_lock_irqsave(&host->lock, flags); while (1) { set_current_state(TASK_UNINTERRUPTIBLE); - if (host->card_busy == NULL) + if (!host->claimed) break; spin_unlock_irqrestore(&host->lock, flags); schedule(); spin_lock_irqsave(&host->lock, flags); } set_current_state(TASK_RUNNING); - host->card_busy = card; + host->claimed = 1; spin_unlock_irqrestore(&host->lock, flags); remove_wait_queue(&host->wq, &wait); @@ -353,10 +353,10 @@ void mmc_release_host(struct mmc_host *host) { unsigned long flags; - BUG_ON(host->card_busy == NULL); + BUG_ON(!host->claimed); spin_lock_irqsave(&host->lock, flags); - host->card_busy = NULL; + host->claimed = 0; spin_unlock_irqrestore(&host->lock, flags); wake_up(&host->wq); @@ -381,7 +381,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) int err; struct mmc_command cmd; - BUG_ON(host->card_busy == NULL); + BUG_ON(!host->claimed); if (host->card_selected == card) return MMC_ERR_NONE; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index c15ae1986b98..dc4c6e395198 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -106,8 +106,9 @@ struct mmc_host { struct list_head cards; /* devices attached to this host */ wait_queue_head_t wq; - spinlock_t lock; /* card_busy lock */ - struct mmc_card *card_busy; /* the MMC card claiming host */ + spinlock_t lock; /* claimed lock */ + unsigned int claimed:1; /* host exclusively claimed */ + struct mmc_card *card_selected; /* the selected MMC card */ struct delayed_work detect; -- cgit v1.2.3 From 11354d03afe9dd0d114e078057158baad4b4eee9 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 14 Jan 2007 01:41:45 +0100 Subject: mmc: let host be parent of cards Change the parent of cards to be a specific host (a class device), not the physical controller. This is particularly useful when the hardware has multiple slots, meaning multiple hosts. Signed-off-by: Pierre Ossman --- drivers/mmc/mmc_sysfs.c | 2 +- include/linux/mmc/host.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c index e334acd045bc..d32698b02d7f 100644 --- a/drivers/mmc/mmc_sysfs.c +++ b/drivers/mmc/mmc_sysfs.c @@ -199,7 +199,7 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host) memset(card, 0, sizeof(struct mmc_card)); card->host = host; device_initialize(&card->dev); - card->dev.parent = mmc_dev(host); + card->dev.parent = mmc_classdev(host); card->dev.bus = &mmc_bus_type; card->dev.release = mmc_release_card; } diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index dc4c6e395198..ae98d6766bdd 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -127,6 +127,7 @@ static inline void *mmc_priv(struct mmc_host *host) } #define mmc_dev(x) ((x)->parent) +#define mmc_classdev(x) (&(x)->class_dev) #define mmc_hostname(x) ((x)->class_dev.bus_id) extern int mmc_suspend_host(struct mmc_host *, pm_message_t); -- cgit v1.2.3 From 9e9dc5f29f2eb65153a15c4fdb12b4382e3a75b2 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sat, 27 Jan 2007 15:32:31 +0100 Subject: mmc: Power quirk for ENE controllers Support for these devices was broken for 2.6.18-rc1 and later by commit 146ad66eac836c0b976c98f428d73e1f6a75270d, which added voltage level support. This restores the previous behaviour for these devices by ensuring that when the voltage is changed, only one write to set the voltage is performed. It may be that both writes are needed if the voltage is being changed between two non-zero values or that it's safe to ensure that only one write is done if the hardware only supports one voltage; I don't know whether either is the case nor can I test since I have only the one SD reader (1524:0550), and it supports just the one voltage. Signed-off-by: Darren Salt Signed-off-by: Pierre Ossman --- drivers/mmc/sdhci.c | 22 +++++++++++++++++++--- include/linux/pci_ids.h | 1 + 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index c2d13d7e9911..175a9427b9ba 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -37,6 +37,7 @@ static unsigned int debug_quirks = 0; #define SDHCI_QUIRK_FORCE_DMA (1<<1) /* Controller doesn't like some resets when there is no card inserted. */ #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) +#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) static const struct pci_device_id pci_ids[] __devinitdata = { { @@ -65,6 +66,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .driver_data = SDHCI_QUIRK_FORCE_DMA, }, + { + .vendor = PCI_VENDOR_ID_ENE, + .device = PCI_DEVICE_ID_ENE_CB712_SD, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE, + }, + { /* Generic SD host controller */ PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) }, @@ -674,10 +683,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) if (host->power == power) return; - writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); - - if (power == (unsigned short)-1) + if (power == (unsigned short)-1) { + writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); goto out; + } + + /* + * Spec says that we should clear the power reg before setting + * a new value. Some controllers don't seem to like this though. + */ + if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) + writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); pwr = SDHCI_POWER_ON; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3d1d21035dec..d37f46aaaea1 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1971,6 +1971,7 @@ #define PCI_DEVICE_ID_TOPIC_TP560 0x0000 #define PCI_VENDOR_ID_ENE 0x1524 +#define PCI_DEVICE_ID_ENE_CB712_SD 0x0550 #define PCI_DEVICE_ID_ENE_1211 0x1211 #define PCI_DEVICE_ID_ENE_1225 0x1225 #define PCI_DEVICE_ID_ENE_1410 0x1410 -- cgit v1.2.3 From fba68bd2dab1ac99af3c5a963ec9581cfa9f1725 Mon Sep 17 00:00:00 2001 From: Philip Langdale Date: Thu, 4 Jan 2007 06:57:32 -0800 Subject: mmc: Add support for SDHC cards Thanks to the generous donation of an SDHC card by John Gilmore, and the surprisingly enlightened decision by the SD Card Association to publish useful specs, I've been able to bash out support for SDHC. The changes are not too profound: i) Add a card flag indicating the card uses block level addressing and check it in the block driver. As we never took advantage of byte-level addressing, this simply involves skipping the block -> byte translation when sending commands. ii) The layout of the CSD is changed - a set of fields are discarded to make space for a larger C_SIZE. We did not reference any of the discarded fields except those related to the C_SIZE. iii) Read and write timeouts are fixed values and not calculated from CSD values. iv) Before invoking SEND_APP_OP_COND, we must invoke the new SEND_IF_COND to inform the card we support SDHC. Signed-off-by: Philipl Langdale Signed-off-by: Pierre Ossman --- drivers/mmc/mmc.c | 140 ++++++++++++++++++++++++++++++++++--------- drivers/mmc/mmc_block.c | 8 ++- include/linux/mmc/card.h | 3 + include/linux/mmc/mmc.h | 1 + include/linux/mmc/protocol.h | 13 +++- 5 files changed, 135 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 105f419d08cb..b48c277312de 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -289,7 +289,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, else limit_us = 100000; - if (timeout_us > limit_us) { + /* + * SDHC cards always use these fixed values. + */ + if (timeout_us > limit_us || mmc_card_blockaddr(card)) { data->timeout_ns = limit_us * 1000; data->timeout_clks = 0; } @@ -372,7 +375,7 @@ static inline void mmc_set_ios(struct mmc_host *host) mmc_hostname(host), ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, ios->vdd, ios->bus_width); - + host->ops->set_ios(host, ios); } @@ -588,34 +591,65 @@ static void mmc_decode_csd(struct mmc_card *card) if (mmc_card_sd(card)) { csd_struct = UNSTUFF_BITS(resp, 126, 2); - if (csd_struct != 0) { + + switch (csd_struct) { + case 0: + m = UNSTUFF_BITS(resp, 115, 4); + e = UNSTUFF_BITS(resp, 112, 3); + csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; + csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; + + m = UNSTUFF_BITS(resp, 99, 4); + e = UNSTUFF_BITS(resp, 96, 3); + csd->max_dtr = tran_exp[e] * tran_mant[m]; + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + e = UNSTUFF_BITS(resp, 47, 3); + m = UNSTUFF_BITS(resp, 62, 12); + csd->capacity = (1 + m) << (e + 2); + + csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); + csd->read_partial = UNSTUFF_BITS(resp, 79, 1); + csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); + csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); + csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); + csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); + csd->write_partial = UNSTUFF_BITS(resp, 21, 1); + break; + case 1: + /* + * This is a block-addressed SDHC card. Most + * interesting fields are unused and have fixed + * values. To avoid getting tripped by buggy cards, + * we assume those fixed values ourselves. + */ + mmc_card_set_blockaddr(card); + + csd->tacc_ns = 0; /* Unused */ + csd->tacc_clks = 0; /* Unused */ + + m = UNSTUFF_BITS(resp, 99, 4); + e = UNSTUFF_BITS(resp, 96, 3); + csd->max_dtr = tran_exp[e] * tran_mant[m]; + csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); + + m = UNSTUFF_BITS(resp, 48, 22); + csd->capacity = (1 + m) << 10; + + csd->read_blkbits = 9; + csd->read_partial = 0; + csd->write_misalign = 0; + csd->read_misalign = 0; + csd->r2w_factor = 4; /* Unused */ + csd->write_blkbits = 9; + csd->write_partial = 0; + break; + default: printk("%s: unrecognised CSD structure version %d\n", mmc_hostname(card->host), csd_struct); mmc_card_set_bad(card); return; } - - m = UNSTUFF_BITS(resp, 115, 4); - e = UNSTUFF_BITS(resp, 112, 3); - csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; - csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100; - - m = UNSTUFF_BITS(resp, 99, 4); - e = UNSTUFF_BITS(resp, 96, 3); - csd->max_dtr = tran_exp[e] * tran_mant[m]; - csd->cmdclass = UNSTUFF_BITS(resp, 84, 12); - - e = UNSTUFF_BITS(resp, 47, 3); - m = UNSTUFF_BITS(resp, 62, 12); - csd->capacity = (1 + m) << (e + 2); - - csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); - csd->read_partial = UNSTUFF_BITS(resp, 79, 1); - csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); - csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); - csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3); - csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); - csd->write_partial = UNSTUFF_BITS(resp, 21, 1); } else { /* * We only understand CSD structure v1.1 and v1.2. @@ -848,6 +882,41 @@ static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) return err; } +static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2) +{ + struct mmc_command cmd; + int err, sd2; + static const u8 test_pattern = 0xAA; + + /* + * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND + * before SD_APP_OP_COND. This command will harmlessly fail for + * SD 1.0 cards. + */ + cmd.opcode = SD_SEND_IF_COND; + cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; + cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err == MMC_ERR_NONE) { + if ((cmd.resp[0] & 0xFF) == test_pattern) { + sd2 = 1; + } else { + sd2 = 0; + err = MMC_ERR_FAILED; + } + } else { + /* + * Treat errors as SD 1.0 card. + */ + sd2 = 0; + err = MMC_ERR_NONE; + } + if (rsd2) + *rsd2 = sd2; + return err; +} + /* * Discover cards by requesting their CID. If this command * times out, it is not an error; there are no further cards @@ -1334,6 +1403,10 @@ static void mmc_setup(struct mmc_host *host) mmc_power_up(host); mmc_idle_cards(host); + err = mmc_send_if_cond(host, host->ocr_avail, NULL); + if (err != MMC_ERR_NONE) { + return; + } err = mmc_send_app_op_cond(host, 0, &ocr); /* @@ -1386,10 +1459,21 @@ static void mmc_setup(struct mmc_host *host) * all get the idea that they should be ready for CMD2. * (My SanDisk card seems to need this.) */ - if (host->mode == MMC_MODE_SD) - mmc_send_app_op_cond(host, host->ocr, NULL); - else + if (host->mode == MMC_MODE_SD) { + int err, sd2; + err = mmc_send_if_cond(host, host->ocr, &sd2); + if (err == MMC_ERR_NONE) { + /* + * If SD_SEND_IF_COND indicates an SD 2.0 + * compliant card and we should set bit 30 + * of the ocr to indicate that we can handle + * block-addressed SDHC cards. + */ + mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL); + } + } else { mmc_send_op_cond(host, host->ocr, NULL); + } mmc_discover_cards(host); diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 87713572293f..5a4eacac0bbe 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -237,7 +237,9 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.mrq.cmd = &brq.cmd; brq.mrq.data = &brq.data; - brq.cmd.arg = req->sector << 9; + brq.cmd.arg = req->sector; + if (!mmc_card_blockaddr(card)) + brq.cmd.arg <<= 9; brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; brq.data.blksz = 1 << md->block_bits; brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); @@ -494,6 +496,10 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) struct mmc_command cmd; int err; + /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */ + if (mmc_card_blockaddr(card)) + return 0; + mmc_card_claim_host(card); cmd.opcode = MMC_SET_BLOCKLEN; cmd.arg = 1 << md->block_bits; diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index d0e6a5497614..e45712acfac5 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -71,6 +71,7 @@ struct mmc_card { #define MMC_STATE_SDCARD (1<<3) /* is an SD card */ #define MMC_STATE_READONLY (1<<4) /* card is read-only */ #define MMC_STATE_HIGHSPEED (1<<5) /* card is in high speed mode */ +#define MMC_STATE_BLOCKADDR (1<<6) /* 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 */ @@ -87,6 +88,7 @@ struct mmc_card { #define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD) #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) #define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED) +#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR) #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) #define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD) @@ -94,6 +96,7 @@ struct mmc_card { #define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD) #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED) +#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR) #define mmc_card_name(c) ((c)->cid.prod_name) #define mmc_card_id(c) ((c)->dev.bus_id) diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index bcf24909d677..cdc54be804f1 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -43,6 +43,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_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) +#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) #define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE)) diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h index 2dce60c43f4b..c90b6768329d 100644 --- a/include/linux/mmc/protocol.h +++ b/include/linux/mmc/protocol.h @@ -79,9 +79,12 @@ #define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */ /* SD commands type argument response */ - /* class 8 */ + /* class 0 */ /* This is basically the same command as for MMC with some quirks. */ #define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ +#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */ + + /* class 10 */ #define SD_SWITCH 6 /* adtc [31:0] See below R1 */ /* Application commands */ @@ -114,6 +117,14 @@ * [3:0] Function group 1 */ +/* + * SD_SEND_IF_COND argument format: + * + * [31:12] Reserved (0) + * [11:8] Host Voltage Supply Flags + * [7:0] Check Pattern (0xAA) + */ + /* MMC status in R1 Type -- cgit v1.2.3 From 8e02f8581cd2f9c12a03be7641d5c2c427170feb Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Fri, 8 Dec 2006 16:50:51 +1100 Subject: tifm_sd: restructure initialization, removal and command handling In order to support correct suspend and resume several changes were needed: 1. Switch from work_struct to tasklet for command handling. When device suspend is called workqueues are already frozen and can not be used. 2. Separate host initialization code from driver's probe and don't rely on interrupts for host initialization. This, in turn, addresses two problems: a) Resume needs to re-initialize the host, but can not assume that device interrupts were already re-armed. b) Previously, probe will return successfully before really knowing the state of the host, as host interrupts were not armed in time. Now it uses polling to determine the real host state before returning. 3. Separate termination code from driver's remove. Termination may be caused by resume, if media changed type or became unavailable during suspend. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_7xx1.c | 3 +- drivers/misc/tifm_core.c | 11 +-- drivers/mmc/tifm_sd.c | 205 +++++++++++++++++++++++++---------------------- include/linux/tifm.h | 5 +- 4 files changed, 116 insertions(+), 108 deletions(-) (limited to 'include/linux') diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 2ab7add78f94..50c4cdabb654 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -201,11 +201,12 @@ static void tifm_7xx1_insert_media(struct work_struct *work) fm->max_sockets == 2); if (media_id) { ok_to_register = 0; - new_sock = tifm_alloc_device(fm, cnt); + new_sock = tifm_alloc_device(fm); if (new_sock) { new_sock->addr = tifm_7xx1_sock_addr(fm->addr, cnt); new_sock->media_id = media_id; + new_sock->socket_id = cnt; switch (media_id) { case 1: card_name = "xd"; diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index d61df5c3ac36..21eb0ab7c329 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -141,24 +141,17 @@ EXPORT_SYMBOL(tifm_remove_adapter); void tifm_free_device(struct device *dev) { struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); - if (fm_dev->wq) - destroy_workqueue(fm_dev->wq); kfree(fm_dev); } EXPORT_SYMBOL(tifm_free_device); -struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id) +struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm) { struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL); if (dev) { spin_lock_init(&dev->lock); - snprintf(dev->wq_name, KOBJ_NAME_LEN, "tifm%u:%u", fm->id, id); - dev->wq = create_singlethread_workqueue(dev->wq_name); - if (!dev->wq) { - kfree(dev); - return NULL; - } + dev->dev.parent = fm->dev; dev->dev.bus = &tifm_bus_type; dev->dev.release = tifm_free_device; diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index 5817a138a1e4..85a5974318b4 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c @@ -79,7 +79,6 @@ typedef enum { enum { FIFO_RDY = 0x0001, /* hardware dependent value */ - HOST_REG = 0x0002, EJECT = 0x0004, EJECT_DONE = 0x0008, CARD_BUSY = 0x0010, @@ -97,10 +96,10 @@ struct tifm_sd { unsigned int clk_div; unsigned long timeout_jiffies; + struct tasklet_struct finish_tasklet; struct timer_list timer; struct mmc_request *req; - struct work_struct cmd_handler; - wait_queue_head_t can_eject; + wait_queue_head_t notify; size_t written_blocks; size_t buffer_size; @@ -317,7 +316,7 @@ change_state: } break; case READY: - queue_work(sock->wq, &host->cmd_handler); + tasklet_schedule(&host->finish_tasklet); return; } @@ -345,8 +344,6 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, host_status = readl(sock->addr + SOCK_MMCSD_STATUS); writel(host_status, sock->addr + SOCK_MMCSD_STATUS); - if (!(host->flags & HOST_REG)) - queue_work(sock->wq, &host->cmd_handler); if (!host->req) goto done; @@ -517,9 +514,9 @@ err_out: mmc_request_done(mmc, mrq); } -static void tifm_sd_end_cmd(struct work_struct *work) +static void tifm_sd_end_cmd(unsigned long data) { - struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); + struct tifm_sd *host = (struct tifm_sd*)data; struct tifm_dev *sock = host->dev; struct mmc_host *mmc = tifm_get_drvdata(sock); struct mmc_request *mrq; @@ -616,9 +613,9 @@ err_out: mmc_request_done(mmc, mrq); } -static void tifm_sd_end_cmd_nodma(struct work_struct *work) +static void tifm_sd_end_cmd_nodma(unsigned long data) { - struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); + struct tifm_sd *host = (struct tifm_sd*)data; struct tifm_dev *sock = host->dev; struct mmc_host *mmc = tifm_get_drvdata(sock); struct mmc_request *mrq; @@ -666,11 +663,33 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work) mmc_request_done(mmc, mrq); } +static void tifm_sd_terminate(struct tifm_sd *host) +{ + struct tifm_dev *sock = host->dev; + unsigned long flags; + + writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); + mmiowb(); + spin_lock_irqsave(&sock->lock, flags); + host->flags |= EJECT; + if (host->req) { + writel(TIFM_FIFO_INT_SETALL, + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); + tasklet_schedule(&host->finish_tasklet); + } + spin_unlock_irqrestore(&sock->lock, flags); +} + static void tifm_sd_abort(unsigned long data) { + struct tifm_sd *host = (struct tifm_sd*)data; + printk(KERN_ERR DRIVER_NAME ": card failed to respond for a long period of time"); - tifm_eject(((struct tifm_sd*)data)->dev); + + tifm_sd_terminate(host); + tifm_eject(host->dev); } static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) @@ -739,7 +758,7 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) // allow removal. if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) { host->flags |= EJECT_DONE; - wake_up_all(&host->can_eject); + wake_up_all(&host->notify); } spin_unlock_irqrestore(&sock->lock, flags); @@ -767,21 +786,67 @@ static struct mmc_host_ops tifm_sd_ops = { .get_ro = tifm_sd_ro }; -static void tifm_sd_register_host(struct work_struct *work) +static int tifm_sd_initialize_host(struct tifm_sd *host) { - struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler); + int rc; + unsigned int host_status = 0; struct tifm_dev *sock = host->dev; - struct mmc_host *mmc = tifm_get_drvdata(sock); - unsigned long flags; - spin_lock_irqsave(&sock->lock, flags); - del_timer(&host->timer); - host->flags |= HOST_REG; - PREPARE_WORK(&host->cmd_handler, - no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd); - spin_unlock_irqrestore(&sock->lock, flags); - dev_dbg(&sock->dev, "adding host\n"); - mmc_add_host(mmc); + writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); + mmiowb(); + host->clk_div = 61; + host->clk_freq = 20000000; + writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL); + writel(host->clk_div | TIFM_MMCSD_POWER, + sock->addr + SOCK_MMCSD_CONFIG); + + /* wait up to 0.51 sec for reset */ + for (rc = 2; rc <= 256; rc <<= 1) { + if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) { + rc = 0; + break; + } + msleep(rc); + } + + if (rc) { + printk(KERN_ERR DRIVER_NAME + ": controller failed to reset\n"); + return -ENODEV; + } + + writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS); + writel(host->clk_div | TIFM_MMCSD_POWER, + sock->addr + SOCK_MMCSD_CONFIG); + writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); + + // command timeout fixed to 64 clocks for now + writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); + writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND); + + /* INAB should take much less than reset */ + for (rc = 1; rc <= 16; rc <<= 1) { + host_status = readl(sock->addr + SOCK_MMCSD_STATUS); + writel(host_status, sock->addr + SOCK_MMCSD_STATUS); + if (!(host_status & TIFM_MMCSD_ERRMASK) + && (host_status & TIFM_MMCSD_EOC)) { + rc = 0; + break; + } + msleep(rc); + } + + if (rc) { + printk(KERN_ERR DRIVER_NAME + ": card not ready - probe failed on initialization\n"); + return -ENODEV; + } + + writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK, + sock->addr + SOCK_MMCSD_INT_ENABLE); + mmiowb(); + + return 0; } static int tifm_sd_probe(struct tifm_dev *sock) @@ -801,77 +866,37 @@ static int tifm_sd_probe(struct tifm_dev *sock) return -ENOMEM; host = mmc_priv(mmc); - host->dev = sock; - host->clk_div = 61; - init_waitqueue_head(&host->can_eject); - INIT_WORK(&host->cmd_handler, tifm_sd_register_host); - setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host); - tifm_set_drvdata(sock, mmc); - sock->signal_irq = tifm_sd_signal_irq; - - host->clk_freq = 20000000; + host->dev = sock; host->timeout_jiffies = msecs_to_jiffies(1000); + init_waitqueue_head(&host->notify); + tasklet_init(&host->finish_tasklet, + no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd, + (unsigned long)host); + setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host); + tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request; mmc->ops = &tifm_sd_ops; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; mmc->f_min = 20000000 / 60; mmc->f_max = 24000000; mmc->max_hw_segs = 1; mmc->max_phys_segs = 1; mmc->max_sectors = 127; mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length + sock->signal_irq = tifm_sd_signal_irq; + rc = tifm_sd_initialize_host(host); - writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); - writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL); - writel(host->clk_div | TIFM_MMCSD_POWER, - sock->addr + SOCK_MMCSD_CONFIG); - - for (rc = 0; rc < 50; rc++) { - /* Wait for reset ack */ - if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) { - rc = 0; - break; - } - msleep(10); - } - - if (rc) { - printk(KERN_ERR DRIVER_NAME - ": card not ready - probe failed\n"); - mmc_free_host(mmc); - return -ENODEV; - } - - writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS); - writel(host->clk_div | TIFM_MMCSD_POWER, - sock->addr + SOCK_MMCSD_CONFIG); - writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); - writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK, - sock->addr + SOCK_MMCSD_INT_ENABLE); - - writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); // command timeout 64 clocks for now - writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND); - writel(host->clk_div | TIFM_MMCSD_POWER, - sock->addr + SOCK_MMCSD_CONFIG); - - mod_timer(&host->timer, jiffies + host->timeout_jiffies); + if (!rc) + rc = mmc_add_host(mmc); + if (rc) + goto out_free_mmc; return 0; -} - -static int tifm_sd_host_is_down(struct tifm_dev *sock) -{ - struct mmc_host *mmc = tifm_get_drvdata(sock); - struct tifm_sd *host = mmc_priv(mmc); - unsigned long flags; - int rc = 0; - - spin_lock_irqsave(&sock->lock, flags); - rc = (host->flags & EJECT_DONE); - spin_unlock_irqrestore(&sock->lock, flags); +out_free_mmc: + mmc_free_host(mmc); return rc; } @@ -879,27 +904,17 @@ static void tifm_sd_remove(struct tifm_dev *sock) { struct mmc_host *mmc = tifm_get_drvdata(sock); struct tifm_sd *host = mmc_priv(mmc); - unsigned long flags; del_timer_sync(&host->timer); - spin_lock_irqsave(&sock->lock, flags); - host->flags |= EJECT; - if (host->req) - queue_work(sock->wq, &host->cmd_handler); - spin_unlock_irqrestore(&sock->lock, flags); - wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock), - host->timeout_jiffies); - - if (host->flags & HOST_REG) - mmc_remove_host(mmc); + tifm_sd_terminate(host); + wait_event_timeout(host->notify, host->flags & EJECT_DONE, + host->timeout_jiffies); + tasklet_kill(&host->finish_tasklet); + mmc_remove_host(mmc); /* The meaning of the bit majority in this constant is unknown. */ writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), sock->addr + SOCK_CONTROL); - writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); - writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); - writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); tifm_set_drvdata(sock, NULL); mmc_free_host(mmc); diff --git a/include/linux/tifm.h b/include/linux/tifm.h index dfb8052eee5e..9caa28e2a63c 100644 --- a/include/linux/tifm.h +++ b/include/linux/tifm.h @@ -89,8 +89,7 @@ struct tifm_dev { char __iomem *addr; spinlock_t lock; tifm_media_id media_id; - char wq_name[KOBJ_NAME_LEN]; - struct workqueue_struct *wq; + unsigned int socket_id; unsigned int (*signal_irq)(struct tifm_dev *sock, unsigned int sock_irq_status); @@ -132,7 +131,7 @@ void tifm_free_device(struct device *dev); void tifm_free_adapter(struct tifm_adapter *fm); int tifm_add_adapter(struct tifm_adapter *fm); void tifm_remove_adapter(struct tifm_adapter *fm); -struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id); +struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm); int tifm_register_driver(struct tifm_driver *drv); void tifm_unregister_driver(struct tifm_driver *drv); void tifm_eject(struct tifm_dev *sock); -- cgit v1.2.3 From 50743f4cb1d655c7fbe25af58a9d0db6bf76d687 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Mon, 11 Dec 2006 01:55:30 +1100 Subject: Remove unused return value from signal_irq callback Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_7xx1.c | 4 ++-- drivers/mmc/tifm_sd.c | 5 ++--- include/linux/tifm.h | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 50c4cdabb654..375b56742f2b 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -13,7 +13,7 @@ #include #define DRIVER_NAME "tifm_7xx1" -#define DRIVER_VERSION "0.6" +#define DRIVER_VERSION "0.7" static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) { @@ -91,7 +91,7 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) if (fm->sockets[cnt]) { if (sock_irq_status && fm->sockets[cnt]->signal_irq) - sock_irq_status = fm->sockets[cnt]-> + fm->sockets[cnt]-> signal_irq(fm->sockets[cnt], sock_irq_status); diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index 37fe0c3ecb85..2adfe3467019 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c @@ -323,8 +323,8 @@ change_state: } /* Called from interrupt handler */ -static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, - unsigned int sock_irq_status) +static void tifm_sd_signal_irq(struct tifm_dev *sock, + unsigned int sock_irq_status) { struct tifm_sd *host; unsigned int host_status = 0, fifo_status = 0; @@ -395,7 +395,6 @@ done: dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n", host_status, fifo_status); spin_unlock(&sock->lock); - return sock_irq_status; } static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd) diff --git a/include/linux/tifm.h b/include/linux/tifm.h index 9caa28e2a63c..5b0baef4e61f 100644 --- a/include/linux/tifm.h +++ b/include/linux/tifm.h @@ -91,7 +91,7 @@ struct tifm_dev { tifm_media_id media_id; unsigned int socket_id; - unsigned int (*signal_irq)(struct tifm_dev *sock, + void (*signal_irq)(struct tifm_dev *sock, unsigned int sock_irq_status); struct tifm_driver *drv; -- cgit v1.2.3 From 6412d927313f08808d61b7efba8da43717d4e8d2 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Mon, 11 Dec 2006 01:55:33 +1100 Subject: tifm_7xx1: Merge media insert and media remove functions Hardware does not say whether card was inserted or removed when reporting socket events. Moreover, during suspend, media can be removed or switched to some other card type without notification. Therefore, for each socket in the change set the following is performed: 1. If there's active device in the socket it's unregistered 2. Media detection is performed 3. If detection recognizes supportable media, new device is registered This patch also alters some macros and variable names to enhance clarity. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_7xx1.c | 254 +++++++++++++++++++++++------------------------ include/linux/tifm.h | 19 ++-- 2 files changed, 134 insertions(+), 139 deletions(-) (limited to 'include/linux') diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 24b20a417a23..5ab81dd37857 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -21,47 +21,12 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) spin_lock_irqsave(&fm->lock, flags); if (!fm->inhibit_new_cards) { - fm->remove_mask |= 1 << sock->socket_id; - queue_work(fm->wq, &fm->media_remover); + fm->socket_change_set |= 1 << sock->socket_id; + queue_work(fm->wq, &fm->media_switcher); } spin_unlock_irqrestore(&fm->lock, flags); } -static void tifm_7xx1_remove_media(struct work_struct *work) -{ - struct tifm_adapter *fm = - container_of(work, struct tifm_adapter, media_remover); - unsigned long flags; - int cnt; - struct tifm_dev *sock; - - if (!class_device_get(&fm->cdev)) - return; - spin_lock_irqsave(&fm->lock, flags); - for (cnt = 0; cnt < fm->max_sockets; cnt++) { - if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) { - printk(KERN_INFO DRIVER_NAME - ": demand removing card from socket %d\n", cnt); - sock = fm->sockets[cnt]; - fm->sockets[cnt] = NULL; - fm->remove_mask &= ~(1 << cnt); - - writel(0x0e00, sock->addr + SOCK_CONTROL); - - writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, - fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, - fm->addr + FM_SET_INTERRUPT_ENABLE); - - spin_unlock_irqrestore(&fm->lock, flags); - device_unregister(&sock->dev); - spin_lock_irqsave(&fm->lock, flags); - } - } - spin_unlock_irqrestore(&fm->lock, flags); - class_device_put(&fm->cdev); -} - static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) { struct tifm_adapter *fm = dev_id; @@ -79,32 +44,27 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) if (irq_status & TIFM_IRQ_ENABLE) { writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - for (cnt = 0; cnt < fm->max_sockets; cnt++) { + for (cnt = 0; cnt < fm->num_sockets; cnt++) { sock = fm->sockets[cnt]; - sock_irq_status = (irq_status >> cnt) & - (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK); - - if (sock) { - if (sock_irq_status) - sock->signal_irq(sock, sock_irq_status); + sock_irq_status = (irq_status >> cnt) + & (TIFM_IRQ_FIFOMASK(1) + | TIFM_IRQ_CARDMASK(1)); - if (irq_status & (1 << cnt)) - fm->remove_mask |= 1 << cnt; - } else { - if (irq_status & (1 << cnt)) - fm->insert_mask |= 1 << cnt; - } + if (sock && sock_irq_status) + sock->signal_irq(sock, sock_irq_status); } + + fm->socket_change_set |= irq_status + & ((1 << fm->num_sockets) - 1); } writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); if (!fm->inhibit_new_cards) { - if (!fm->remove_mask && !fm->insert_mask) { + if (!fm->socket_change_set) { writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); } else { - queue_work(fm->wq, &fm->media_remover); - queue_work(fm->wq, &fm->media_inserter); + queue_work(fm->wq, &fm->media_switcher); } } @@ -163,84 +123,125 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num) return base_addr + ((sock_num + 1) << 10); } -static void tifm_7xx1_insert_media(struct work_struct *work) +static void tifm_7xx1_switch_media(struct work_struct *work) { struct tifm_adapter *fm = - container_of(work, struct tifm_adapter, media_inserter); + container_of(work, struct tifm_adapter, media_switcher); unsigned long flags; tifm_media_id media_id; char *card_name = "xx"; - int cnt, ok_to_register; - unsigned int insert_mask; - struct tifm_dev *new_sock = NULL; + int cnt; + struct tifm_dev *sock; + unsigned int socket_change_set; if (!class_device_get(&fm->cdev)) return; - spin_lock_irqsave(&fm->lock, flags); - insert_mask = fm->insert_mask; - fm->insert_mask = 0; - if (fm->inhibit_new_cards) { + + while (1) { + spin_lock_irqsave(&fm->lock, flags); + socket_change_set = fm->socket_change_set; + fm->socket_change_set = 0; + + dev_dbg(fm->dev, "checking media set %x\n", + socket_change_set); + + if (fm->inhibit_new_cards) + socket_change_set = (1 << fm->num_sockets) - 1; spin_unlock_irqrestore(&fm->lock, flags); - class_device_put(&fm->cdev); - return; - } - spin_unlock_irqrestore(&fm->lock, flags); - for (cnt = 0; cnt < fm->max_sockets; cnt++) { - if (!(insert_mask & (1 << cnt))) - continue; - - media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt), - fm->max_sockets == 2); - if (media_id) { - ok_to_register = 0; - new_sock = tifm_alloc_device(fm); - if (new_sock) { - new_sock->addr = tifm_7xx1_sock_addr(fm->addr, - cnt); - new_sock->media_id = media_id; - new_sock->socket_id = cnt; - switch (media_id) { - case 1: - card_name = "xd"; - break; - case 2: - card_name = "ms"; - break; - case 3: - card_name = "sd"; - break; - default: - break; - } - snprintf(new_sock->dev.bus_id, BUS_ID_SIZE, - "tifm_%s%u:%u", card_name, fm->id, cnt); + if (!socket_change_set) + break; + + spin_lock_irqsave(&fm->lock, flags); + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + if (!(socket_change_set & (1 << cnt))) + continue; + sock = fm->sockets[cnt]; + if (sock) { printk(KERN_INFO DRIVER_NAME - ": %s card detected in socket %d\n", - card_name, cnt); + ": demand removing card from socket %d\n", + cnt); + fm->sockets[cnt] = NULL; + spin_unlock_irqrestore(&fm->lock, flags); + device_unregister(&sock->dev); spin_lock_irqsave(&fm->lock, flags); - if (!fm->sockets[cnt]) { - fm->sockets[cnt] = new_sock; - ok_to_register = 1; + writel(0x0e00, + tifm_7xx1_sock_addr(fm->addr, cnt) + + SOCK_CONTROL); + } + if (fm->inhibit_new_cards) + continue; + + spin_unlock_irqrestore(&fm->lock, flags); + media_id = tifm_7xx1_toggle_sock_power( + tifm_7xx1_sock_addr(fm->addr, cnt), + fm->num_sockets == 2); + if (media_id) { + sock = tifm_alloc_device(fm); + if (sock) { + sock->addr = tifm_7xx1_sock_addr(fm->addr, + cnt); + sock->media_id = media_id; + sock->socket_id = cnt; + switch (media_id) { + case 1: + card_name = "xd"; + break; + case 2: + card_name = "ms"; + break; + case 3: + card_name = "sd"; + break; + default: + tifm_free_device(&sock->dev); + spin_lock_irqsave(&fm->lock, flags); + continue; + } + snprintf(sock->dev.bus_id, BUS_ID_SIZE, + "tifm_%s%u:%u", card_name, fm->id, cnt); + printk(KERN_INFO DRIVER_NAME + ": %s card detected in socket %d\n", + card_name, cnt); + if (!device_register(&sock->dev)) { + spin_lock_irqsave(&fm->lock, flags); + if (!fm->sockets[cnt]) { + fm->sockets[cnt] = sock; + sock = NULL; + } + spin_unlock_irqrestore(&fm->lock, flags); + } + if (sock) + tifm_free_device(&sock->dev); } + spin_lock_irqsave(&fm->lock, flags); + } + } + + if (!fm->inhibit_new_cards) { + writel(TIFM_IRQ_FIFOMASK(socket_change_set) + | TIFM_IRQ_CARDMASK(socket_change_set), + fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + writel(TIFM_IRQ_FIFOMASK(socket_change_set) + | TIFM_IRQ_CARDMASK(socket_change_set), + fm->addr + FM_SET_INTERRUPT_ENABLE); + writel(TIFM_IRQ_ENABLE, + fm->addr + FM_SET_INTERRUPT_ENABLE); + spin_unlock_irqrestore(&fm->lock, flags); + break; + } else { + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + if (fm->sockets[cnt]) + fm->socket_change_set |= 1 << cnt; + } + if (!fm->socket_change_set) { + spin_unlock_irqrestore(&fm->lock, flags); + break; + } else { spin_unlock_irqrestore(&fm->lock, flags); - if (!ok_to_register || - device_register(&new_sock->dev)) { - spin_lock_irqsave(&fm->lock, flags); - fm->sockets[cnt] = NULL; - spin_unlock_irqrestore(&fm->lock, - flags); - tifm_free_device(&new_sock->dev); - } } } - writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, - fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt, - fm->addr + FM_SET_INTERRUPT_ENABLE); } - - writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); class_device_put(&fm->cdev); } @@ -251,13 +252,12 @@ static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) spin_lock_irqsave(&fm->lock, flags); fm->inhibit_new_cards = 1; - fm->remove_mask = 0xf; - fm->insert_mask = 0; + fm->socket_change_set = 0xf; writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); spin_unlock_irqrestore(&fm->lock, flags); flush_workqueue(fm->wq); - tifm_7xx1_remove_media(&fm->media_remover); + tifm_7xx1_switch_media(&fm->media_switcher); pci_set_power_state(dev, PCI_D3hot); pci_disable_device(dev); @@ -279,9 +279,9 @@ static int tifm_7xx1_resume(struct pci_dev *dev) fm->inhibit_new_cards = 0; writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS); writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, + writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), fm->addr + FM_SET_INTERRUPT_ENABLE); - fm->insert_mask = 0xf; + fm->socket_change_set = 0xf; spin_unlock_irqrestore(&fm->lock, flags); return 0; } @@ -318,14 +318,13 @@ static int tifm_7xx1_probe(struct pci_dev *dev, } fm->dev = &dev->dev; - fm->max_sockets = (dev->device == 0x803B) ? 2 : 4; - fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets, + fm->num_sockets = (dev->device == 0x803B) ? 2 : 4; + fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets, GFP_KERNEL); if (!fm->sockets) goto err_out_free; - INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media); - INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media); + INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media); fm->eject = tifm_7xx1_eject; pci_set_drvdata(dev, fm); @@ -343,10 +342,10 @@ static int tifm_7xx1_probe(struct pci_dev *dev, goto err_out_irq; writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, + writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), fm->addr + FM_SET_INTERRUPT_ENABLE); - fm->insert_mask = 0xf; + fm->socket_change_set = 0xf; return 0; @@ -373,14 +372,13 @@ static void tifm_7xx1_remove(struct pci_dev *dev) spin_lock_irqsave(&fm->lock, flags); fm->inhibit_new_cards = 1; - fm->remove_mask = 0xf; - fm->insert_mask = 0; + fm->socket_change_set = 0xf; writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); spin_unlock_irqrestore(&fm->lock, flags); flush_workqueue(fm->wq); - tifm_7xx1_remove_media(&fm->media_remover); + tifm_7xx1_switch_media(&fm->media_switcher); writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); free_irq(dev->irq, fm); diff --git a/include/linux/tifm.h b/include/linux/tifm.h index 5b0baef4e61f..eaf9e1f48780 100644 --- a/include/linux/tifm.h +++ b/include/linux/tifm.h @@ -62,11 +62,10 @@ enum { #define TIFM_IRQ_ENABLE 0x80000000 -#define TIFM_IRQ_SOCKMASK 0x00000001 -#define TIFM_IRQ_CARDMASK 0x00000100 -#define TIFM_IRQ_FIFOMASK 0x00010000 +#define TIFM_IRQ_SOCKMASK(x) (x) +#define TIFM_IRQ_CARDMASK(x) ((x) << 8) +#define TIFM_IRQ_FIFOMASK(x) ((x) << 16) #define TIFM_IRQ_SETALL 0xffffffff -#define TIFM_IRQ_SETALLSOCK 0x0000000f #define TIFM_CTRL_LED 0x00000040 #define TIFM_CTRL_FAST_CLK 0x00000100 @@ -108,18 +107,16 @@ struct tifm_driver { struct tifm_adapter { char __iomem *addr; - unsigned int irq_status; - unsigned int insert_mask; - unsigned int remove_mask; spinlock_t lock; + unsigned int irq_status; + unsigned int socket_change_set; unsigned int id; - unsigned int max_sockets; + unsigned int num_sockets; + struct tifm_dev **sockets; char wq_name[KOBJ_NAME_LEN]; unsigned int inhibit_new_cards; struct workqueue_struct *wq; - struct work_struct media_inserter; - struct work_struct media_remover; - struct tifm_dev **sockets; + struct work_struct media_switcher; struct class_device cdev; struct device *dev; -- cgit v1.2.3 From 7146f0d3bd2bcd0100a5db54f4ba9edc1042fe01 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Mon, 18 Dec 2006 14:20:06 +1100 Subject: tifm_7xx1: switch from workqueue to kthread As there's only one work item (media_switcher) to handle and it's effectively serialized with itself, I found it more convenient to use kthread instead of workqueue. This also allows for a working implementation of suspend/resume, which were totally broken in the past version. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_7xx1.c | 151 ++++++++++++++++++++++++++++------------------- drivers/misc/tifm_core.c | 11 ++-- include/linux/tifm.h | 10 ++-- 3 files changed, 98 insertions(+), 74 deletions(-) (limited to 'include/linux') diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 5ab81dd37857..d3e8ff46c237 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -11,6 +11,7 @@ #include #include +#include #define DRIVER_NAME "tifm_7xx1" #define DRIVER_VERSION "0.7" @@ -20,10 +21,8 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) unsigned long flags; spin_lock_irqsave(&fm->lock, flags); - if (!fm->inhibit_new_cards) { - fm->socket_change_set |= 1 << sock->socket_id; - queue_work(fm->wq, &fm->media_switcher); - } + fm->socket_change_set |= 1 << sock->socket_id; + wake_up_all(&fm->change_set_notify); spin_unlock_irqrestore(&fm->lock, flags); } @@ -59,14 +58,10 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) } writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); - if (!fm->inhibit_new_cards) { - if (!fm->socket_change_set) { - writel(TIFM_IRQ_ENABLE, - fm->addr + FM_SET_INTERRUPT_ENABLE); - } else { - queue_work(fm->wq, &fm->media_switcher); - } - } + if (!fm->socket_change_set) + writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); + else + wake_up_all(&fm->change_set_notify); spin_unlock(&fm->lock); return IRQ_HANDLED; @@ -123,21 +118,22 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num) return base_addr + ((sock_num + 1) << 10); } -static void tifm_7xx1_switch_media(struct work_struct *work) +static int tifm_7xx1_switch_media(void *data) { - struct tifm_adapter *fm = - container_of(work, struct tifm_adapter, media_switcher); + struct tifm_adapter *fm = data; unsigned long flags; tifm_media_id media_id; char *card_name = "xx"; - int cnt; + int cnt, rc; struct tifm_dev *sock; unsigned int socket_change_set; - if (!class_device_get(&fm->cdev)) - return; - while (1) { + rc = wait_event_interruptible(fm->change_set_notify, + fm->socket_change_set); + if (rc == -ERESTARTSYS) + try_to_freeze(); + spin_lock_irqsave(&fm->lock, flags); socket_change_set = fm->socket_change_set; fm->socket_change_set = 0; @@ -145,12 +141,12 @@ static void tifm_7xx1_switch_media(struct work_struct *work) dev_dbg(fm->dev, "checking media set %x\n", socket_change_set); - if (fm->inhibit_new_cards) + if (kthread_should_stop()) socket_change_set = (1 << fm->num_sockets) - 1; spin_unlock_irqrestore(&fm->lock, flags); if (!socket_change_set) - break; + continue; spin_lock_irqsave(&fm->lock, flags); for (cnt = 0; cnt < fm->num_sockets; cnt++) { @@ -169,7 +165,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work) tifm_7xx1_sock_addr(fm->addr, cnt) + SOCK_CONTROL); } - if (fm->inhibit_new_cards) + if (kthread_should_stop()) continue; spin_unlock_irqrestore(&fm->lock, flags); @@ -218,7 +214,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work) } } - if (!fm->inhibit_new_cards) { + if (!kthread_should_stop()) { writel(TIFM_IRQ_FIFOMASK(socket_change_set) | TIFM_IRQ_CARDMASK(socket_change_set), fm->addr + FM_CLEAR_INTERRUPT_ENABLE); @@ -228,7 +224,6 @@ static void tifm_7xx1_switch_media(struct work_struct *work) writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); spin_unlock_irqrestore(&fm->lock, flags); - break; } else { for (cnt = 0; cnt < fm->num_sockets; cnt++) { if (fm->sockets[cnt]) @@ -236,56 +231,93 @@ static void tifm_7xx1_switch_media(struct work_struct *work) } if (!fm->socket_change_set) { spin_unlock_irqrestore(&fm->lock, flags); - break; + return 0; } else { spin_unlock_irqrestore(&fm->lock, flags); } } } - class_device_put(&fm->cdev); + return 0; } +#ifdef CONFIG_PM + static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state) { - struct tifm_adapter *fm = pci_get_drvdata(dev); - unsigned long flags; + dev_dbg(&dev->dev, "suspending host\n"); - spin_lock_irqsave(&fm->lock, flags); - fm->inhibit_new_cards = 1; - fm->socket_change_set = 0xf; - writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - spin_unlock_irqrestore(&fm->lock, flags); - flush_workqueue(fm->wq); - - tifm_7xx1_switch_media(&fm->media_switcher); - - pci_set_power_state(dev, PCI_D3hot); - pci_disable_device(dev); - pci_save_state(dev); + pci_save_state(dev); + pci_enable_wake(dev, pci_choose_state(dev, state), 0); + pci_disable_device(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); return 0; } static int tifm_7xx1_resume(struct pci_dev *dev) { struct tifm_adapter *fm = pci_get_drvdata(dev); + int cnt, rc; unsigned long flags; + tifm_media_id new_ids[fm->num_sockets]; + pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); - pci_enable_device(dev); - pci_set_power_state(dev, PCI_D0); - pci_set_master(dev); + rc = pci_enable_device(dev); + if (rc) + return rc; + pci_set_master(dev); + + dev_dbg(&dev->dev, "resuming host\n"); + for (cnt = 0; cnt < fm->num_sockets; cnt++) + new_ids[cnt] = tifm_7xx1_toggle_sock_power( + tifm_7xx1_sock_addr(fm->addr, cnt), + fm->num_sockets == 2); spin_lock_irqsave(&fm->lock, flags); - fm->inhibit_new_cards = 0; - writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS); - writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + fm->socket_change_set = 0; + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + if (fm->sockets[cnt]) { + if (fm->sockets[cnt]->media_id == new_ids[cnt]) + fm->socket_change_set |= 1 << cnt; + + fm->sockets[cnt]->media_id = new_ids[cnt]; + } + } + writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), - fm->addr + FM_SET_INTERRUPT_ENABLE); - fm->socket_change_set = 0xf; + fm->addr + FM_SET_INTERRUPT_ENABLE); + if (!fm->socket_change_set) { + spin_unlock_irqrestore(&fm->lock, flags); + return 0; + } else { + fm->socket_change_set = 0; + spin_unlock_irqrestore(&fm->lock, flags); + } + + wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ); + + spin_lock_irqsave(&fm->lock, flags); + writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set) + | TIFM_IRQ_CARDMASK(fm->socket_change_set), + fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set) + | TIFM_IRQ_CARDMASK(fm->socket_change_set), + fm->addr + FM_SET_INTERRUPT_ENABLE); + writel(TIFM_IRQ_ENABLE, + fm->addr + FM_SET_INTERRUPT_ENABLE); + fm->socket_change_set = 0; + spin_unlock_irqrestore(&fm->lock, flags); return 0; } +#else + +#define tifm_7xx1_suspend NULL +#define tifm_7xx1_resume NULL + +#endif /* CONFIG_PM */ + static int tifm_7xx1_probe(struct pci_dev *dev, const struct pci_device_id *dev_id) { @@ -324,7 +356,6 @@ static int tifm_7xx1_probe(struct pci_dev *dev, if (!fm->sockets) goto err_out_free; - INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media); fm->eject = tifm_7xx1_eject; pci_set_drvdata(dev, fm); @@ -337,16 +368,15 @@ static int tifm_7xx1_probe(struct pci_dev *dev, if (rc) goto err_out_unmap; - rc = tifm_add_adapter(fm); + init_waitqueue_head(&fm->change_set_notify); + rc = tifm_add_adapter(fm, tifm_7xx1_switch_media); if (rc) goto err_out_irq; writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), fm->addr + FM_SET_INTERRUPT_ENABLE); - - fm->socket_change_set = 0xf; - + wake_up_process(fm->media_switcher); return 0; err_out_irq: @@ -370,18 +400,15 @@ static void tifm_7xx1_remove(struct pci_dev *dev) struct tifm_adapter *fm = pci_get_drvdata(dev); unsigned long flags; + writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + mmiowb(); + free_irq(dev->irq, fm); + spin_lock_irqsave(&fm->lock, flags); - fm->inhibit_new_cards = 1; - fm->socket_change_set = 0xf; - writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); + fm->socket_change_set = (1 << fm->num_sockets) - 1; spin_unlock_irqrestore(&fm->lock, flags); - flush_workqueue(fm->wq); - - tifm_7xx1_switch_media(&fm->media_switcher); - - writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - free_irq(dev->irq, fm); + kthread_stop(fm->media_switcher); tifm_remove_adapter(fm); diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index 3eaf2c985b7d..4d62dab2ada3 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -71,8 +71,6 @@ static void tifm_free(struct class_device *cdev) struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev); kfree(fm->sockets); - if (fm->wq) - destroy_workqueue(fm->wq); kfree(fm); } @@ -101,7 +99,8 @@ void tifm_free_adapter(struct tifm_adapter *fm) } EXPORT_SYMBOL(tifm_free_adapter); -int tifm_add_adapter(struct tifm_adapter *fm) +int tifm_add_adapter(struct tifm_adapter *fm, + int (*mediathreadfn)(void *data)) { int rc; @@ -113,10 +112,10 @@ int tifm_add_adapter(struct tifm_adapter *fm) spin_unlock(&tifm_adapter_lock); if (!rc) { snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id); - strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN); + fm->media_switcher = kthread_create(mediathreadfn, + fm, "tifm/%u", fm->id); - fm->wq = create_singlethread_workqueue(fm->wq_name); - if (fm->wq) + if (!IS_ERR(fm->media_switcher)) return class_device_add(&fm->cdev); spin_lock(&tifm_adapter_lock); diff --git a/include/linux/tifm.h b/include/linux/tifm.h index eaf9e1f48780..e5a8295f9fbc 100644 --- a/include/linux/tifm.h +++ b/include/linux/tifm.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include /* Host registers (relative to pci base address): */ enum { @@ -110,13 +110,11 @@ struct tifm_adapter { spinlock_t lock; unsigned int irq_status; unsigned int socket_change_set; + wait_queue_head_t change_set_notify; unsigned int id; unsigned int num_sockets; struct tifm_dev **sockets; - char wq_name[KOBJ_NAME_LEN]; - unsigned int inhibit_new_cards; - struct workqueue_struct *wq; - struct work_struct media_switcher; + struct task_struct *media_switcher; struct class_device cdev; struct device *dev; @@ -126,7 +124,7 @@ struct tifm_adapter { struct tifm_adapter *tifm_alloc_adapter(void); void tifm_free_device(struct device *dev); void tifm_free_adapter(struct tifm_adapter *fm); -int tifm_add_adapter(struct tifm_adapter *fm); +int tifm_add_adapter(struct tifm_adapter *fm, int (*mediathreadfn)(void *data)); void tifm_remove_adapter(struct tifm_adapter *fm); struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm); int tifm_register_driver(struct tifm_driver *drv); -- cgit v1.2.3 From b5ad6761533c3f7e97c93b2333a0f88490d44f36 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Mon, 11 Dec 2006 01:55:35 +1100 Subject: tifm_7xx1: recognize device 0xac8f as supported This patch also adds symbolic defines for supported pci ids. Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_7xx1.c | 13 ++++++++----- include/linux/pci_ids.h | 3 +++ 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index d3e8ff46c237..ea6ad9f2d245 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -350,7 +350,8 @@ static int tifm_7xx1_probe(struct pci_dev *dev, } fm->dev = &dev->dev; - fm->num_sockets = (dev->device == 0x803B) ? 2 : 4; + fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM) + ? 4 : 2; fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets, GFP_KERNEL); if (!fm->sockets) @@ -423,10 +424,12 @@ static void tifm_7xx1_remove(struct pci_dev *dev) } static struct pci_device_id tifm_7xx1_pci_tbl [] = { - { PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - 0 }, /* xx21 - the one I have */ - { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - 0 }, /* xx12 - should be also supported */ + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */ + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX20_FM, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, { } }; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index d37f46aaaea1..ccd706f876ec 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -735,9 +735,11 @@ #define PCI_DEVICE_ID_TI_TVP4020 0x3d07 #define PCI_DEVICE_ID_TI_4450 0x8011 #define PCI_DEVICE_ID_TI_XX21_XX11 0x8031 +#define PCI_DEVICE_ID_TI_XX21_XX11_FM 0x8033 #define PCI_DEVICE_ID_TI_XX21_XX11_SD 0x8034 #define PCI_DEVICE_ID_TI_X515 0x8036 #define PCI_DEVICE_ID_TI_XX12 0x8039 +#define PCI_DEVICE_ID_TI_XX12_FM 0x803b #define PCI_DEVICE_ID_TI_1130 0xac12 #define PCI_DEVICE_ID_TI_1031 0xac13 #define PCI_DEVICE_ID_TI_1131 0xac15 @@ -765,6 +767,7 @@ #define PCI_DEVICE_ID_TI_1510 0xac56 #define PCI_DEVICE_ID_TI_X620 0xac8d #define PCI_DEVICE_ID_TI_X420 0xac8e +#define PCI_DEVICE_ID_TI_XX20_FM 0xac8f #define PCI_VENDOR_ID_SONY 0x104d -- cgit v1.2.3 From 41d78f7405659b55e082c5f0b3d1b625e75e1294 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Mon, 11 Dec 2006 01:55:37 +1100 Subject: tifm_core: add suspend/resume infrastructure for tifm devices Signed-off-by: Alex Dubov Signed-off-by: Pierre Ossman --- drivers/misc/tifm_core.c | 35 ++++++++++++++++++++++++++++++++++- include/linux/tifm.h | 3 +++ 2 files changed, 37 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index 4d62dab2ada3..6b10ebe9d936 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -14,7 +14,7 @@ #include #define DRIVER_NAME "tifm_core" -#define DRIVER_VERSION "0.6" +#define DRIVER_VERSION "0.7" static DEFINE_IDR(tifm_adapter_idr); static DEFINE_SPINLOCK(tifm_adapter_lock); @@ -60,10 +60,41 @@ static int tifm_uevent(struct device *dev, char **envp, int num_envp, return 0; } +#ifdef CONFIG_PM + +static int tifm_device_suspend(struct device *dev, pm_message_t state) +{ + struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); + struct tifm_driver *drv = fm_dev->drv; + + if (drv && drv->suspend) + return drv->suspend(fm_dev, state); + return 0; +} + +static int tifm_device_resume(struct device *dev) +{ + struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); + struct tifm_driver *drv = fm_dev->drv; + + if (drv && drv->resume) + return drv->resume(fm_dev); + return 0; +} + +#else + +#define tifm_device_suspend NULL +#define tifm_device_resume NULL + +#endif /* CONFIG_PM */ + static struct bus_type tifm_bus_type = { .name = "tifm", .match = tifm_match, .uevent = tifm_uevent, + .suspend = tifm_device_suspend, + .resume = tifm_device_resume }; static void tifm_free(struct class_device *cdev) @@ -233,6 +264,8 @@ int tifm_register_driver(struct tifm_driver *drv) drv->driver.bus = &tifm_bus_type; drv->driver.probe = tifm_device_probe; drv->driver.remove = tifm_device_remove; + drv->driver.suspend = tifm_device_suspend; + drv->driver.resume = tifm_device_resume; return driver_register(&drv->driver); } diff --git a/include/linux/tifm.h b/include/linux/tifm.h index e5a8295f9fbc..3deb0a6c1370 100644 --- a/include/linux/tifm.h +++ b/include/linux/tifm.h @@ -101,6 +101,9 @@ struct tifm_driver { tifm_media_id *id_table; int (*probe)(struct tifm_dev *dev); void (*remove)(struct tifm_dev *dev); + int (*suspend)(struct tifm_dev *dev, + pm_message_t state); + int (*resume)(struct tifm_dev *dev); struct device_driver driver; }; -- cgit v1.2.3 From fe4a3c7a20f14d86022a8132adbf6ddb98e7197c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 21 Nov 2006 17:54:23 +0100 Subject: mmc: Allow host drivers to specify a max block size Most controllers have an upper limit on the block size. Allow the host drivers to specify this and make sure we avoid hitting this limit. Signed-off-by: Pierre Ossman --- drivers/mmc/at91_mci.c | 2 ++ drivers/mmc/au1xmmc.c | 2 ++ drivers/mmc/imxmmc.c | 1 + drivers/mmc/mmc.c | 4 ++++ drivers/mmc/mmci.c | 5 +++++ drivers/mmc/omap.c | 1 + drivers/mmc/pxamci.c | 5 +++++ drivers/mmc/sdhci.c | 24 ++++++++++++++---------- drivers/mmc/sdhci.h | 1 - drivers/mmc/tifm_sd.c | 4 +++- drivers/mmc/wbsd.c | 6 ++++++ include/linux/mmc/host.h | 1 + 12 files changed, 44 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index aa152f31851e..e28850dec9ed 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -823,6 +823,8 @@ static int __init at91_mci_probe(struct platform_device *pdev) mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; mmc->caps = MMC_CAP_BYTEBLOCK; + mmc->max_blk_size = 4095; + host = mmc_priv(mmc); host->mmc = mmc; host->buffer = NULL; diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c index 6d6fe6e6d415..74e6ac0c7f71 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/au1xmmc.c @@ -922,6 +922,8 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev) mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE; mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT; + mmc->max_blk_size = 2048; + mmc->ocr_avail = AU1XMMC_OCR; host = mmc_priv(mmc); diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index bfb9ff693208..2107f8a8605e 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -960,6 +960,7 @@ static int imxmci_probe(struct platform_device *pdev) mmc->max_phys_segs = 64; mmc->max_sectors = 64; /* default 1 << (PAGE_CACHE_SHIFT - 9) */ mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */ + mmc->max_blk_size = 2048; host = mmc_priv(mmc); host->mmc = mmc; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index b48c277312de..9bda3fddad17 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -108,6 +108,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mrq->cmd->error = 0; mrq->cmd->mrq = mrq; if (mrq->data) { + BUG_ON(mrq->data->blksz > host->max_blk_size); + mrq->cmd->data = mrq->data; mrq->data->error = 0; mrq->data->mrq = mrq; @@ -1605,6 +1607,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->max_phys_segs = 1; host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9); host->max_seg_size = PAGE_CACHE_SIZE; + + host->max_blk_size = 512; } return host; diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index ccfe6561be24..5d48e0081894 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -534,6 +534,11 @@ static int mmci_probe(struct amba_device *dev, void *id) */ mmc->max_seg_size = mmc->max_sectors << 9; + /* + * Block size can be up to 2048 bytes, but must be a power of two. + */ + mmc->max_blk_size = 2048; + spin_lock_init(&host->lock); writel(0, host->base + MMCIMASK0); diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c index d30540b27614..fa69a0dc5969 100644 --- a/drivers/mmc/omap.c +++ b/drivers/mmc/omap.c @@ -1099,6 +1099,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev) */ mmc->max_phys_segs = 32; mmc->max_hw_segs = 32; + mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */ mmc->max_sectors = 256; /* NBLK max 11-bits, OMAP also limited by DMA */ mmc->max_seg_size = mmc->max_sectors * 512; diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index 6073d998b11f..9fc9aed1a5ef 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -450,6 +450,11 @@ static int pxamci_probe(struct platform_device *pdev) */ mmc->max_seg_size = PAGE_SIZE; + /* + * Block length register is 10 bits. + */ + mmc->max_blk_size = 1023; + host = mmc_priv(mmc); host->mmc = mmc; host->dma = -1; diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 175a9427b9ba..155aafe69bf4 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -381,7 +381,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) /* Sanity checks */ BUG_ON(data->blksz * data->blocks > 524288); - BUG_ON(data->blksz > host->max_block); + BUG_ON(data->blksz > host->mmc->max_blk_size); BUG_ON(data->blocks > 65535); /* timeout in us */ @@ -1290,15 +1290,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) if (caps & SDHCI_TIMEOUT_CLK_UNIT) host->timeout_clk *= 1000; - host->max_block = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; - if (host->max_block >= 3) { - printk(KERN_ERR "%s: Invalid maximum block size.\n", - host->slot_descr); - ret = -ENODEV; - goto unmap; - } - host->max_block = 512 << host->max_block; - /* * Set host parameters. */ @@ -1352,6 +1343,19 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) */ mmc->max_seg_size = mmc->max_sectors * 512; + /* + * Maximum block size. This varies from controller to controller and + * is specified in the capabilities register. + */ + mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; + if (mmc->max_blk_size >= 3) { + printk(KERN_ERR "%s: Invalid maximum block size.\n", + host->slot_descr); + ret = -ENODEV; + goto unmap; + } + mmc->max_blk_size = 512 << mmc->max_blk_size; + /* * Init tasklets. */ diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h index f9d1a0a6f03a..bc6bf7e7757d 100644 --- a/drivers/mmc/sdhci.h +++ b/drivers/mmc/sdhci.h @@ -174,7 +174,6 @@ struct sdhci_host { unsigned int max_clk; /* Max possible freq (MHz) */ unsigned int timeout_clk; /* Timeout freq (KHz) */ - unsigned int max_block; /* Max block size (bytes) */ unsigned int clock; /* Current clock (MHz) */ unsigned short power; /* Current voltage */ diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index ce19b045ca6a..bdfad15371b8 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c @@ -886,7 +886,9 @@ static int tifm_sd_probe(struct tifm_dev *sock) mmc->max_hw_segs = 1; mmc->max_phys_segs = 1; mmc->max_sectors = 127; - mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length + //2k maximum hw block length + mmc->max_seg_size = mmc->max_sectors << 11; + mmc->max_blk_size = 2048; sock->signal_irq = tifm_sd_signal_irq; rc = tifm_sd_initialize_host(host); diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 7a282672f8e9..5711beecb4e8 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1354,6 +1354,12 @@ static int __devinit wbsd_alloc_mmc(struct device *dev) */ mmc->max_seg_size = mmc->max_sectors * 512; + /* + * Maximum block size. We have 12 bits (= 4095) but have to subtract + * space for CRC. So the maximum is 4095 - 4*2 = 4087. + */ + mmc->max_blk_size = 4087; + dev_set_drvdata(dev, mmc); return 0; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index ae98d6766bdd..2da0c918a8cc 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -94,6 +94,7 @@ struct mmc_host { unsigned short max_phys_segs; /* see blk_queue_max_phys_segments */ unsigned short max_sectors; /* see blk_queue_max_sectors */ unsigned short unused; + unsigned int max_blk_size; /* maximum size of one mmc block */ /* private data */ struct mmc_ios ios; /* current io bus settings */ -- cgit v1.2.3 From 55db890a838c7b37256241b1fc53d6344aa79cc0 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 21 Nov 2006 17:55:45 +0100 Subject: mmc: Allow host drivers to specify max block count Many controllers have an upper limit on the number of blocks that can be transferred in one request. Allow the host drivers to specify this and make sure we avoid hitting this limit. Also change the max_sectors field to avoid confusion. This makes it map less directly to the block layer limits, but as they didn't apply directly on MMC cards anyway, this isn't a great loss. Signed-off-by: Pierre Ossman --- drivers/mmc/at91_mci.c | 1 + drivers/mmc/au1xmmc.c | 1 + drivers/mmc/imxmmc.c | 3 ++- drivers/mmc/mmc.c | 6 +++++- drivers/mmc/mmc_block.c | 4 +++- drivers/mmc/mmc_queue.c | 2 +- drivers/mmc/mmci.c | 10 +++++++--- drivers/mmc/omap.c | 5 +++-- drivers/mmc/pxamci.c | 5 +++++ drivers/mmc/sdhci.c | 13 +++++++++---- drivers/mmc/tifm_sd.c | 9 ++++++--- drivers/mmc/wbsd.c | 15 ++++++++++----- include/linux/mmc/host.h | 3 ++- 13 files changed, 55 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index e28850dec9ed..2ce50f38e3c7 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -824,6 +824,7 @@ static int __init at91_mci_probe(struct platform_device *pdev) mmc->caps = MMC_CAP_BYTEBLOCK; mmc->max_blk_size = 4095; + mmc->max_blk_count = mmc->max_req_size; host = mmc_priv(mmc); host->mmc = mmc; diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c index 74e6ac0c7f71..b834be261ab7 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/au1xmmc.c @@ -923,6 +923,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev) mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT; mmc->max_blk_size = 2048; + mmc->max_blk_count = 512; mmc->ocr_avail = AU1XMMC_OCR; diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index 2107f8a8605e..b060d4bfba29 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -958,9 +958,10 @@ static int imxmci_probe(struct platform_device *pdev) /* MMC core transfer sizes tunable parameters */ mmc->max_hw_segs = 64; mmc->max_phys_segs = 64; - mmc->max_sectors = 64; /* default 1 << (PAGE_CACHE_SHIFT - 9) */ mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */ + mmc->max_req_size = 64*512; /* default PAGE_CACHE_SIZE */ mmc->max_blk_size = 2048; + mmc->max_blk_count = 65535; host = mmc_priv(mmc); host->mmc = mmc; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 9bda3fddad17..fb04bdd26c36 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -109,6 +109,9 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) mrq->cmd->mrq = mrq; if (mrq->data) { BUG_ON(mrq->data->blksz > host->max_blk_size); + BUG_ON(mrq->data->blocks > host->max_blk_count); + BUG_ON(mrq->data->blocks * mrq->data->blksz > + host->max_req_size); mrq->cmd->data = mrq->data; mrq->data->error = 0; @@ -1605,10 +1608,11 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) */ host->max_hw_segs = 1; host->max_phys_segs = 1; - host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9); host->max_seg_size = PAGE_CACHE_SIZE; + host->max_req_size = PAGE_CACHE_SIZE; host->max_blk_size = 512; + host->max_blk_count = PAGE_CACHE_SIZE / 512; } return host; diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 5a4eacac0bbe..19ccfed8a54f 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -242,10 +242,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.cmd.arg <<= 9; brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; brq.data.blksz = 1 << md->block_bits; - brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; brq.stop.flags = 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; mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ); diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c index 3e35a43819fb..c27e42645cdb 100644 --- a/drivers/mmc/mmc_queue.c +++ b/drivers/mmc/mmc_queue.c @@ -147,7 +147,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock blk_queue_prep_rq(mq->queue, mmc_prep_request); blk_queue_bounce_limit(mq->queue, limit); - blk_queue_max_sectors(mq->queue, host->max_sectors); + blk_queue_max_sectors(mq->queue, host->max_req_size / 512); blk_queue_max_phys_segments(mq->queue, host->max_phys_segs); blk_queue_max_hw_segments(mq->queue, host->max_hw_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 5d48e0081894..5941dd951e82 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -524,21 +524,25 @@ static int mmci_probe(struct amba_device *dev, void *id) /* * Since we only have a 16-bit data length register, we must * ensure that we don't exceed 2^16-1 bytes in a single request. - * Choose 64 (512-byte) sectors as the limit. */ - mmc->max_sectors = 64; + mmc->max_req_size = 65535; /* * Set the maximum segment size. Since we aren't doing DMA * (yet) we are only limited by the data length register. */ - mmc->max_seg_size = mmc->max_sectors << 9; + mmc->max_seg_size = mmc->max_req_size; /* * Block size can be up to 2048 bytes, but must be a power of two. */ mmc->max_blk_size = 2048; + /* + * No limit on the number of blocks transferred. + */ + mmc->max_blk_count = mmc->max_req_size; + spin_lock_init(&host->lock); writel(0, host->base + MMCIMASK0); diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c index fa69a0dc5969..1e96a2f65022 100644 --- a/drivers/mmc/omap.c +++ b/drivers/mmc/omap.c @@ -1100,8 +1100,9 @@ static int __init mmc_omap_probe(struct platform_device *pdev) mmc->max_phys_segs = 32; mmc->max_hw_segs = 32; mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */ - mmc->max_sectors = 256; /* NBLK max 11-bits, OMAP also limited by DMA */ - mmc->max_seg_size = mmc->max_sectors * 512; + mmc->max_blk_count = 2048; /* NBLK is 11 bits (+1) */ + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_req_size; if (host->power_pin >= 0) { if ((ret = omap_request_gpio(host->power_pin)) != 0) { diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index 9fc9aed1a5ef..9774fc68b61a 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -455,6 +455,11 @@ static int pxamci_probe(struct platform_device *pdev) */ mmc->max_blk_size = 1023; + /* + * Block count register is 16 bits. + */ + mmc->max_blk_count = 65535; + host = mmc_priv(mmc); host->mmc = mmc; host->dma = -1; diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 155aafe69bf4..99f1db92295b 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -1333,15 +1333,15 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) /* * Maximum number of sectors in one transfer. Limited by DMA boundary - * size (512KiB), which means (512 KiB/512=) 1024 entries. + * size (512KiB). */ - mmc->max_sectors = 1024; + mmc->max_req_size = 524288; /* * Maximum segment size. Could be one segment with the maximum number - * of sectors. + * of bytes. */ - mmc->max_seg_size = mmc->max_sectors * 512; + mmc->max_seg_size = mmc->max_req_size; /* * Maximum block size. This varies from controller to controller and @@ -1356,6 +1356,11 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) } mmc->max_blk_size = 512 << mmc->max_blk_size; + /* + * Maximum block count. + */ + mmc->max_blk_count = 65535; + /* * Init tasklets. */ diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index bdfad15371b8..7e607b75f4bc 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c @@ -885,10 +885,13 @@ static int tifm_sd_probe(struct tifm_dev *sock) mmc->f_max = 24000000; mmc->max_hw_segs = 1; mmc->max_phys_segs = 1; - mmc->max_sectors = 127; - //2k maximum hw block length - mmc->max_seg_size = mmc->max_sectors << 11; + // limited by DMA counter - it's safer to stick with + // block counter has 11 bits though + mmc->max_blk_count = 256; + // 2k maximum hw block length mmc->max_blk_size = 2048; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_req_size; sock->signal_irq = tifm_sd_signal_irq; rc = tifm_sd_initialize_host(host); diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 5711beecb4e8..cf16e44c0301 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1343,16 +1343,15 @@ static int __devinit wbsd_alloc_mmc(struct device *dev) mmc->max_phys_segs = 128; /* - * Maximum number of sectors in one transfer. Also limited by 64kB - * buffer. + * Maximum request size. Also limited by 64KiB buffer. */ - mmc->max_sectors = 128; + mmc->max_req_size = 65536; /* * Maximum segment size. Could be one segment with the maximum number - * of segments. + * of bytes. */ - mmc->max_seg_size = mmc->max_sectors * 512; + mmc->max_seg_size = mmc->max_req_size; /* * Maximum block size. We have 12 bits (= 4095) but have to subtract @@ -1360,6 +1359,12 @@ static int __devinit wbsd_alloc_mmc(struct device *dev) */ mmc->max_blk_size = 4087; + /* + * Maximum block count. There is no real limit so the maximum + * request size will be the only restriction. + */ + mmc->max_blk_count = mmc->max_req_size; + dev_set_drvdata(dev, mmc); return 0; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 2da0c918a8cc..913e5752569f 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -92,9 +92,10 @@ struct mmc_host { unsigned int max_seg_size; /* see blk_queue_max_segment_size */ unsigned short max_hw_segs; /* see blk_queue_max_hw_segments */ unsigned short max_phys_segs; /* see blk_queue_max_phys_segments */ - unsigned short max_sectors; /* see blk_queue_max_sectors */ unsigned short unused; + unsigned int max_req_size; /* maximum number of bytes in one req */ unsigned int max_blk_size; /* maximum size of one mmc block */ + unsigned int max_blk_count; /* maximum number of blocks in one req */ /* private data */ struct mmc_ios ios; /* current io bus settings */ -- cgit v1.2.3 From 5556feae1c4e1cf2021b5fb2ef99973125de2250 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 11 Jan 2007 16:51:17 +0200 Subject: hid: quirk for multi-input devices with unneeded output reports Add new quirk HID_QUIRK_SKIP_OUTPUT_REPORTS to skip output reports when enumerating reports on a hid-input device. Add this quirk and HID_QUIRK_MULTI_INPUT to 0810:0001. PantherLord Twin USB Joystick, 0810:0001 has separate input reports for 2 distinct game controllers in the same interface, so it needs HID_QUIRK_MULTI_INPUT. However, the device also contains one output report per controller which is used to control the force feedback function, and we do not want those to appear as separate input devices as well. The simplest approach seems to be to add a quirk to skip output reports on 0810:0001, and allow the force feedback driver to handle those. Signed-off-by: Anssi Hannula Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 6 +++++- drivers/usb/input/hid-core.c | 5 +++++ include/linux/hid.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index c7a6833f6821..33b1126f5e5d 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -816,6 +816,7 @@ int hidinput_connect(struct hid_device *hid) struct hid_input *hidinput = NULL; struct input_dev *input_dev; int i, j, k; + int max_report_type = HID_OUTPUT_REPORT; INIT_LIST_HEAD(&hid->inputs); @@ -828,7 +829,10 @@ int hidinput_connect(struct hid_device *hid) if (i == hid->maxcollection) return -1; - for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) + if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS) + max_report_type = HID_INPUT_REPORT; + + for (k = HID_INPUT_REPORT; k <= max_report_type; k++) list_for_each_entry(report, &hid->report_enum[k].report_list, list) { if (!report->maxfield) diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 2971182bbdf6..1fa42f400176 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -792,6 +792,9 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_IMATION 0x0718 #define USB_DEVICE_ID_DISC_STAKKA 0xd000 +#define USB_VENDOR_ID_PANTHERLORD 0x0810 +#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001 + /* * Alphabetically sorted blacklist by quirk type. */ @@ -969,6 +972,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, + { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, + { 0, 0 } }; diff --git a/include/linux/hid.h b/include/linux/hid.h index 342b4e639acb..523b8341e791 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -264,6 +264,7 @@ struct hid_item { #define HID_QUIRK_INVERT_HWHEEL 0x00004000 #define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00008000 #define HID_QUIRK_BAD_RELATIVE_KEYS 0x00010000 +#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00020000 /* * This is the global environment of the parser. This information is -- cgit v1.2.3 From 20eb12790670985c8e30821218993bd260387b89 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 11 Jan 2007 16:51:18 +0200 Subject: hid: force feedback driver for PantherLord USB/PS2 2in1 Adapter Add a force feedback driver for PantherLord USB/PS2 2in1 Adapter, 0810:0001. The device identifies itself as "Twin USB Joystick". Signed-off-by: Anssi Hannula Signed-off-by: Jiri Kosina --- drivers/usb/input/Kconfig | 8 +++ drivers/usb/input/Makefile | 3 + drivers/usb/input/hid-ff.c | 3 + drivers/usb/input/hid-plff.c | 129 +++++++++++++++++++++++++++++++++++++++++++ include/linux/hid.h | 1 + 5 files changed, 144 insertions(+) create mode 100644 drivers/usb/input/hid-plff.c (limited to 'include/linux') diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index c7d887540d8d..aa6a620c162f 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -69,6 +69,14 @@ config LOGITECH_FF Note: if you say N here, this device will still be supported, but without force feedback. +config PANTHERLORD_FF + bool "PantherLord USB/PS2 2in1 Adapter support" + depends on HID_FF + select INPUT_FF_MEMLESS if USB_HID + help + Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want + to enable force feedback support for it. + config THRUSTMASTER_FF bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)" depends on HID_FF && EXPERIMENTAL diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 1a24b5bfa05f..a06024e5cd56 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -17,6 +17,9 @@ endif ifeq ($(CONFIG_LOGITECH_FF),y) usbhid-objs += hid-lgff.o endif +ifeq ($(CONFIG_PANTHERLORD_FF),y) + usbhid-objs += hid-plff.o +endif ifeq ($(CONFIG_THRUSTMASTER_FF),y) usbhid-objs += hid-tmff.o endif diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index 59ed65e7a621..5d145058a5cb 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -58,6 +58,9 @@ static struct hid_ff_initializer inits[] = { { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */ { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */ #endif +#ifdef CONFIG_PANTHERLORD_FF + { 0x810, 0x0001, hid_plff_init }, +#endif #ifdef CONFIG_THRUSTMASTER_FF { 0x44f, 0xb304, hid_tmff_init }, #endif diff --git a/drivers/usb/input/hid-plff.c b/drivers/usb/input/hid-plff.c new file mode 100644 index 000000000000..76d2e6e14db4 --- /dev/null +++ b/drivers/usb/input/hid-plff.c @@ -0,0 +1,129 @@ +/* + * Force feedback support for PantherLord USB/PS2 2in1 Adapter devices + * + * Copyright (c) 2007 Anssi Hannula + */ + +/* + * 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 + */ + + +/* #define DEBUG */ + +#define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg) + +#include +#include +#include +#include "usbhid.h" + +struct plff_device { + struct hid_report *report; +}; + +static int hid_plff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = dev->private; + struct plff_device *plff = data; + int left, right; + + left = effect->u.rumble.strong_magnitude; + right = effect->u.rumble.weak_magnitude; + debug("called with 0x%04x 0x%04x", left, right); + + left = left * 0x7f / 0xffff; + right = right * 0x7f / 0xffff; + + plff->report->field[0]->value[2] = left; + plff->report->field[0]->value[3] = right; + debug("running with 0x%02x 0x%02x", left, right); + usbhid_submit_report(hid, plff->report, USB_DIR_OUT); + + return 0; +} + +int hid_plff_init(struct hid_device *hid) +{ + struct plff_device *plff; + struct hid_report *report; + struct hid_input *hidinput; + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct list_head *report_ptr = report_list; + struct input_dev *dev; + int error; + + /* The device contains 2 output reports (one for each + HID_QUIRK_MULTI_INPUT device), both containing 1 field, which + contains 4 ff00.0002 usages and 4 16bit absolute values. + + The 2 input reports also contain a field which contains + 8 ff00.0001 usages and 8 boolean values. Their meaning is + currently unknown. */ + + if (list_empty(report_list)) { + printk(KERN_ERR "hid-plff: no output reports found\n"); + return -ENODEV; + } + + list_for_each_entry(hidinput, &hid->inputs, list) { + + report_ptr = report_ptr->next; + + if (report_ptr == report_list) { + printk(KERN_ERR "hid-plff: required output report is missing\n"); + return -ENODEV; + } + + report = list_entry(report_ptr, struct hid_report, list); + if (report->maxfield < 1) { + printk(KERN_ERR "hid-plff: no fields in the report\n"); + return -ENODEV; + } + + if (report->field[0]->report_count < 4) { + printk(KERN_ERR "hid-plff: not enough values in the field\n"); + return -ENODEV; + } + + plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL); + if (!plff) + return -ENOMEM; + + dev = hidinput->input; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, plff, hid_plff_play); + if (error) { + kfree(plff); + return error; + } + + plff->report = report; + plff->report->field[0]->value[0] = 0x00; + plff->report->field[0]->value[1] = 0x00; + plff->report->field[0]->value[2] = 0x00; + plff->report->field[0]->value[3] = 0x00; + usbhid_submit_report(hid, plff->report, USB_DIR_OUT); + } + + printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 " + "2in1 Adapters by Anssi Hannula \n"); + + return 0; +} diff --git a/include/linux/hid.h b/include/linux/hid.h index 523b8341e791..18d0f2ce817f 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -504,6 +504,7 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size); int hid_ff_init(struct hid_device *hid); int hid_lgff_init(struct hid_device *hid); +int hid_plff_init(struct hid_device *hid); int hid_tmff_init(struct hid_device *hid); int hid_zpff_init(struct hid_device *hid); #ifdef CONFIG_HID_PID -- cgit v1.2.3 From c080d89ad91e98fec0e8fc5f448a1ad899bd85c7 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 25 Jan 2007 11:43:31 +0100 Subject: HID: hid debug from hid-debug.h to hid layer hid-debug.h contains a lot of code, and should not therefore be a header. This patch moves the code to generic hid layer as .c source, and introduces CONFIG_HID_DEBUG to conditionally compile it, instead of playing with #define DEBUG and including hid-debug.h. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 14 + drivers/hid/Makefile | 8 +- drivers/hid/hid-core.c | 2 +- drivers/hid/hid-debug.c | 765 +++++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-input.c | 7 +- drivers/usb/input/hid-core.c | 1 + include/linux/hid-debug.h | 749 +----------------------------------------- include/linux/hid.h | 10 - 8 files changed, 809 insertions(+), 747 deletions(-) create mode 100644 drivers/hid/hid-debug.c (limited to 'include/linux') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index ec796ad087df..850788f4dd2e 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -22,5 +22,19 @@ config HID If unsure, say Y +config HID_DEBUG + bool "HID debugging support" + depends on HID + ---help--- + This option lets the HID layer output diagnostics about its internal + state, resolve HID usages, dump HID fields, etc. Individual HID drivers + use this debugging facility to output information about individual HID + devices, etc. + + This feature is useful for those who are either debugging the HID parser + or any HID hardware device. + + If unsure, say N + endmenu diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 6432392110bf..84c823eb5ad5 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -6,10 +6,14 @@ hid-objs := hid-core.o hid-input.o # Optional parts of multipart objects. - -obj-$(CONFIG_HID) += hid.o +ifeq ($(CONFIG_HID_DEBUG),y) +hid-objs += hid-debug.o +endif ifeq ($(CONFIG_INPUT_DEBUG),y) EXTRA_CFLAGS += -DDEBUG endif + +obj-$(CONFIG_HID) += hid.o + diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 49f18f5b2514..0796f64b3c54 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -28,11 +28,11 @@ #include #include -#undef DEBUG #undef DEBUG_DATA #include #include +#include /* * Version Information diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c new file mode 100644 index 000000000000..d6abe3494c04 --- /dev/null +++ b/drivers/hid/hid-debug.c @@ -0,0 +1,765 @@ +/* + * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $ + * + * (c) 1999 Andreas Gal + * (c) 2000-2001 Vojtech Pavlik + * (c) 2007 Jiri Kosina + * + * Some debug stuff for the HID parser. + */ + +/* + * 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 + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +//#include +#include + +struct hid_usage_entry { + unsigned page; + unsigned usage; + char *description; +}; + +static const struct hid_usage_entry hid_usage_table[] = { + { 0, 0, "Undefined" }, + { 1, 0, "GenericDesktop" }, + {0, 0x01, "Pointer"}, + {0, 0x02, "Mouse"}, + {0, 0x04, "Joystick"}, + {0, 0x05, "GamePad"}, + {0, 0x06, "Keyboard"}, + {0, 0x07, "Keypad"}, + {0, 0x08, "MultiAxis"}, + {0, 0x30, "X"}, + {0, 0x31, "Y"}, + {0, 0x32, "Z"}, + {0, 0x33, "Rx"}, + {0, 0x34, "Ry"}, + {0, 0x35, "Rz"}, + {0, 0x36, "Slider"}, + {0, 0x37, "Dial"}, + {0, 0x38, "Wheel"}, + {0, 0x39, "HatSwitch"}, + {0, 0x3a, "CountedBuffer"}, + {0, 0x3b, "ByteCount"}, + {0, 0x3c, "MotionWakeup"}, + {0, 0x3d, "Start"}, + {0, 0x3e, "Select"}, + {0, 0x40, "Vx"}, + {0, 0x41, "Vy"}, + {0, 0x42, "Vz"}, + {0, 0x43, "Vbrx"}, + {0, 0x44, "Vbry"}, + {0, 0x45, "Vbrz"}, + {0, 0x46, "Vno"}, + {0, 0x80, "SystemControl"}, + {0, 0x81, "SystemPowerDown"}, + {0, 0x82, "SystemSleep"}, + {0, 0x83, "SystemWakeUp"}, + {0, 0x84, "SystemContextMenu"}, + {0, 0x85, "SystemMainMenu"}, + {0, 0x86, "SystemAppMenu"}, + {0, 0x87, "SystemMenuHelp"}, + {0, 0x88, "SystemMenuExit"}, + {0, 0x89, "SystemMenuSelect"}, + {0, 0x8a, "SystemMenuRight"}, + {0, 0x8b, "SystemMenuLeft"}, + {0, 0x8c, "SystemMenuUp"}, + {0, 0x8d, "SystemMenuDown"}, + {0, 0x90, "D-PadUp"}, + {0, 0x91, "D-PadDown"}, + {0, 0x92, "D-PadRight"}, + {0, 0x93, "D-PadLeft"}, + { 2, 0, "Simulation" }, + {0, 0xb0, "Aileron"}, + {0, 0xb1, "AileronTrim"}, + {0, 0xb2, "Anti-Torque"}, + {0, 0xb3, "Autopilot"}, + {0, 0xb4, "Chaff"}, + {0, 0xb5, "Collective"}, + {0, 0xb6, "DiveBrake"}, + {0, 0xb7, "ElectronicCountermeasures"}, + {0, 0xb8, "Elevator"}, + {0, 0xb9, "ElevatorTrim"}, + {0, 0xba, "Rudder"}, + {0, 0xbb, "Throttle"}, + {0, 0xbc, "FlightCommunications"}, + {0, 0xbd, "FlareRelease"}, + {0, 0xbe, "LandingGear"}, + {0, 0xbf, "ToeBrake"}, + { 7, 0, "Keyboard" }, + { 8, 0, "LED" }, + {0, 0x01, "NumLock"}, + {0, 0x02, "CapsLock"}, + {0, 0x03, "ScrollLock"}, + {0, 0x04, "Compose"}, + {0, 0x05, "Kana"}, + {0, 0x4b, "GenericIndicator"}, + { 9, 0, "Button" }, + { 10, 0, "Ordinal" }, + { 12, 0, "Consumer" }, + {0, 0x238, "HorizontalWheel"}, + { 13, 0, "Digitizers" }, + {0, 0x01, "Digitizer"}, + {0, 0x02, "Pen"}, + {0, 0x03, "LightPen"}, + {0, 0x04, "TouchScreen"}, + {0, 0x05, "TouchPad"}, + {0, 0x20, "Stylus"}, + {0, 0x21, "Puck"}, + {0, 0x22, "Finger"}, + {0, 0x30, "TipPressure"}, + {0, 0x31, "BarrelPressure"}, + {0, 0x32, "InRange"}, + {0, 0x33, "Touch"}, + {0, 0x34, "UnTouch"}, + {0, 0x35, "Tap"}, + {0, 0x39, "TabletFunctionKey"}, + {0, 0x3a, "ProgramChangeKey"}, + {0, 0x3c, "Invert"}, + {0, 0x42, "TipSwitch"}, + {0, 0x43, "SecondaryTipSwitch"}, + {0, 0x44, "BarrelSwitch"}, + {0, 0x45, "Eraser"}, + {0, 0x46, "TabletPick"}, + { 15, 0, "PhysicalInterfaceDevice" }, + {0, 0x00, "Undefined"}, + {0, 0x01, "Physical_Interface_Device"}, + {0, 0x20, "Normal"}, + {0, 0x21, "Set_Effect_Report"}, + {0, 0x22, "Effect_Block_Index"}, + {0, 0x23, "Parameter_Block_Offset"}, + {0, 0x24, "ROM_Flag"}, + {0, 0x25, "Effect_Type"}, + {0, 0x26, "ET_Constant_Force"}, + {0, 0x27, "ET_Ramp"}, + {0, 0x28, "ET_Custom_Force_Data"}, + {0, 0x30, "ET_Square"}, + {0, 0x31, "ET_Sine"}, + {0, 0x32, "ET_Triangle"}, + {0, 0x33, "ET_Sawtooth_Up"}, + {0, 0x34, "ET_Sawtooth_Down"}, + {0, 0x40, "ET_Spring"}, + {0, 0x41, "ET_Damper"}, + {0, 0x42, "ET_Inertia"}, + {0, 0x43, "ET_Friction"}, + {0, 0x50, "Duration"}, + {0, 0x51, "Sample_Period"}, + {0, 0x52, "Gain"}, + {0, 0x53, "Trigger_Button"}, + {0, 0x54, "Trigger_Repeat_Interval"}, + {0, 0x55, "Axes_Enable"}, + {0, 0x56, "Direction_Enable"}, + {0, 0x57, "Direction"}, + {0, 0x58, "Type_Specific_Block_Offset"}, + {0, 0x59, "Block_Type"}, + {0, 0x5A, "Set_Envelope_Report"}, + {0, 0x5B, "Attack_Level"}, + {0, 0x5C, "Attack_Time"}, + {0, 0x5D, "Fade_Level"}, + {0, 0x5E, "Fade_Time"}, + {0, 0x5F, "Set_Condition_Report"}, + {0, 0x60, "CP_Offset"}, + {0, 0x61, "Positive_Coefficient"}, + {0, 0x62, "Negative_Coefficient"}, + {0, 0x63, "Positive_Saturation"}, + {0, 0x64, "Negative_Saturation"}, + {0, 0x65, "Dead_Band"}, + {0, 0x66, "Download_Force_Sample"}, + {0, 0x67, "Isoch_Custom_Force_Enable"}, + {0, 0x68, "Custom_Force_Data_Report"}, + {0, 0x69, "Custom_Force_Data"}, + {0, 0x6A, "Custom_Force_Vendor_Defined_Data"}, + {0, 0x6B, "Set_Custom_Force_Report"}, + {0, 0x6C, "Custom_Force_Data_Offset"}, + {0, 0x6D, "Sample_Count"}, + {0, 0x6E, "Set_Periodic_Report"}, + {0, 0x6F, "Offset"}, + {0, 0x70, "Magnitude"}, + {0, 0x71, "Phase"}, + {0, 0x72, "Period"}, + {0, 0x73, "Set_Constant_Force_Report"}, + {0, 0x74, "Set_Ramp_Force_Report"}, + {0, 0x75, "Ramp_Start"}, + {0, 0x76, "Ramp_End"}, + {0, 0x77, "Effect_Operation_Report"}, + {0, 0x78, "Effect_Operation"}, + {0, 0x79, "Op_Effect_Start"}, + {0, 0x7A, "Op_Effect_Start_Solo"}, + {0, 0x7B, "Op_Effect_Stop"}, + {0, 0x7C, "Loop_Count"}, + {0, 0x7D, "Device_Gain_Report"}, + {0, 0x7E, "Device_Gain"}, + {0, 0x7F, "PID_Pool_Report"}, + {0, 0x80, "RAM_Pool_Size"}, + {0, 0x81, "ROM_Pool_Size"}, + {0, 0x82, "ROM_Effect_Block_Count"}, + {0, 0x83, "Simultaneous_Effects_Max"}, + {0, 0x84, "Pool_Alignment"}, + {0, 0x85, "PID_Pool_Move_Report"}, + {0, 0x86, "Move_Source"}, + {0, 0x87, "Move_Destination"}, + {0, 0x88, "Move_Length"}, + {0, 0x89, "PID_Block_Load_Report"}, + {0, 0x8B, "Block_Load_Status"}, + {0, 0x8C, "Block_Load_Success"}, + {0, 0x8D, "Block_Load_Full"}, + {0, 0x8E, "Block_Load_Error"}, + {0, 0x8F, "Block_Handle"}, + {0, 0x90, "PID_Block_Free_Report"}, + {0, 0x91, "Type_Specific_Block_Handle"}, + {0, 0x92, "PID_State_Report"}, + {0, 0x94, "Effect_Playing"}, + {0, 0x95, "PID_Device_Control_Report"}, + {0, 0x96, "PID_Device_Control"}, + {0, 0x97, "DC_Enable_Actuators"}, + {0, 0x98, "DC_Disable_Actuators"}, + {0, 0x99, "DC_Stop_All_Effects"}, + {0, 0x9A, "DC_Device_Reset"}, + {0, 0x9B, "DC_Device_Pause"}, + {0, 0x9C, "DC_Device_Continue"}, + {0, 0x9F, "Device_Paused"}, + {0, 0xA0, "Actuators_Enabled"}, + {0, 0xA4, "Safety_Switch"}, + {0, 0xA5, "Actuator_Override_Switch"}, + {0, 0xA6, "Actuator_Power"}, + {0, 0xA7, "Start_Delay"}, + {0, 0xA8, "Parameter_Block_Size"}, + {0, 0xA9, "Device_Managed_Pool"}, + {0, 0xAA, "Shared_Parameter_Blocks"}, + {0, 0xAB, "Create_New_Effect_Report"}, + {0, 0xAC, "RAM_Pool_Available"}, + { 0x84, 0, "Power Device" }, + { 0x84, 0x02, "PresentStatus" }, + { 0x84, 0x03, "ChangeStatus" }, + { 0x84, 0x04, "UPS" }, + { 0x84, 0x05, "PowerSupply" }, + { 0x84, 0x10, "BatterySystem" }, + { 0x84, 0x11, "BatterySystemID" }, + { 0x84, 0x12, "Battery" }, + { 0x84, 0x13, "BatteryID" }, + { 0x84, 0x14, "Charger" }, + { 0x84, 0x15, "ChargerID" }, + { 0x84, 0x16, "PowerConverter" }, + { 0x84, 0x17, "PowerConverterID" }, + { 0x84, 0x18, "OutletSystem" }, + { 0x84, 0x19, "OutletSystemID" }, + { 0x84, 0x1a, "Input" }, + { 0x84, 0x1b, "InputID" }, + { 0x84, 0x1c, "Output" }, + { 0x84, 0x1d, "OutputID" }, + { 0x84, 0x1e, "Flow" }, + { 0x84, 0x1f, "FlowID" }, + { 0x84, 0x20, "Outlet" }, + { 0x84, 0x21, "OutletID" }, + { 0x84, 0x22, "Gang" }, + { 0x84, 0x24, "PowerSummary" }, + { 0x84, 0x25, "PowerSummaryID" }, + { 0x84, 0x30, "Voltage" }, + { 0x84, 0x31, "Current" }, + { 0x84, 0x32, "Frequency" }, + { 0x84, 0x33, "ApparentPower" }, + { 0x84, 0x35, "PercentLoad" }, + { 0x84, 0x40, "ConfigVoltage" }, + { 0x84, 0x41, "ConfigCurrent" }, + { 0x84, 0x43, "ConfigApparentPower" }, + { 0x84, 0x53, "LowVoltageTransfer" }, + { 0x84, 0x54, "HighVoltageTransfer" }, + { 0x84, 0x56, "DelayBeforeStartup" }, + { 0x84, 0x57, "DelayBeforeShutdown" }, + { 0x84, 0x58, "Test" }, + { 0x84, 0x5a, "AudibleAlarmControl" }, + { 0x84, 0x60, "Present" }, + { 0x84, 0x61, "Good" }, + { 0x84, 0x62, "InternalFailure" }, + { 0x84, 0x65, "Overload" }, + { 0x84, 0x66, "OverCharged" }, + { 0x84, 0x67, "OverTemperature" }, + { 0x84, 0x68, "ShutdownRequested" }, + { 0x84, 0x69, "ShutdownImminent" }, + { 0x84, 0x6b, "SwitchOn/Off" }, + { 0x84, 0x6c, "Switchable" }, + { 0x84, 0x6d, "Used" }, + { 0x84, 0x6e, "Boost" }, + { 0x84, 0x73, "CommunicationLost" }, + { 0x84, 0xfd, "iManufacturer" }, + { 0x84, 0xfe, "iProduct" }, + { 0x84, 0xff, "iSerialNumber" }, + { 0x85, 0, "Battery System" }, + { 0x85, 0x01, "SMBBatteryMode" }, + { 0x85, 0x02, "SMBBatteryStatus" }, + { 0x85, 0x03, "SMBAlarmWarning" }, + { 0x85, 0x04, "SMBChargerMode" }, + { 0x85, 0x05, "SMBChargerStatus" }, + { 0x85, 0x06, "SMBChargerSpecInfo" }, + { 0x85, 0x07, "SMBSelectorState" }, + { 0x85, 0x08, "SMBSelectorPresets" }, + { 0x85, 0x09, "SMBSelectorInfo" }, + { 0x85, 0x29, "RemainingCapacityLimit" }, + { 0x85, 0x2c, "CapacityMode" }, + { 0x85, 0x42, "BelowRemainingCapacityLimit" }, + { 0x85, 0x44, "Charging" }, + { 0x85, 0x45, "Discharging" }, + { 0x85, 0x4b, "NeedReplacement" }, + { 0x85, 0x66, "RemainingCapacity" }, + { 0x85, 0x68, "RunTimeToEmpty" }, + { 0x85, 0x6a, "AverageTimeToFull" }, + { 0x85, 0x83, "DesignCapacity" }, + { 0x85, 0x85, "ManufacturerDate" }, + { 0x85, 0x89, "iDeviceChemistry" }, + { 0x85, 0x8b, "Rechargable" }, + { 0x85, 0x8f, "iOEMInformation" }, + { 0x85, 0x8d, "CapacityGranularity1" }, + { 0x85, 0xd0, "ACPresent" }, + /* pages 0xff00 to 0xffff are vendor-specific */ + { 0xffff, 0, "Vendor-specific-FF" }, + { 0, 0, NULL } +}; + +static void resolv_usage_page(unsigned page) { + const struct hid_usage_entry *p; + + for (p = hid_usage_table; p->description; p++) + if (p->page == page) { + printk("%s", p->description); + return; + } + printk("%04x", page); +} + +void hid_resolv_usage(unsigned usage) { + const struct hid_usage_entry *p; + + resolv_usage_page(usage >> 16); + printk("."); + for (p = hid_usage_table; p->description; p++) + if (p->page == (usage >> 16)) { + for(++p; p->description && p->usage != 0; p++) + if (p->usage == (usage & 0xffff)) { + printk("%s", p->description); + return; + } + break; + } + printk("%04x", usage & 0xffff); +} +EXPORT_SYMBOL_GPL(hid_resolv_usage); + +__inline__ static void tab(int n) { + while (n--) printk(" "); +} + +void hid_dump_field(struct hid_field *field, int n) { + int j; + + if (field->physical) { + tab(n); + printk("Physical("); + hid_resolv_usage(field->physical); printk(")\n"); + } + if (field->logical) { + tab(n); + printk("Logical("); + hid_resolv_usage(field->logical); printk(")\n"); + } + tab(n); printk("Usage(%d)\n", field->maxusage); + for (j = 0; j < field->maxusage; j++) { + tab(n+2); hid_resolv_usage(field->usage[j].hid); printk("\n"); + } + if (field->logical_minimum != field->logical_maximum) { + tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum); + tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum); + } + if (field->physical_minimum != field->physical_maximum) { + tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum); + tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum); + } + if (field->unit_exponent) { + tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); + } + if (field->unit) { + char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; + char *units[5][8] = { + { "None", "None", "None", "None", "None", "None", "None", "None" }, + { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, + { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, + { "None", "Inch", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }, + { "None", "Degrees", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" } + }; + + int i; + int sys; + __u32 data = field->unit; + + /* First nibble tells us which system we're in. */ + sys = data & 0xf; + data >>= 4; + + if(sys > 4) { + tab(n); printk("Unit(Invalid)\n"); + } + else { + int earlier_unit = 0; + + tab(n); printk("Unit(%s : ", systems[sys]); + + for (i=1 ; i>= 4; + if (nibble != 0) { + if(earlier_unit++ > 0) + printk("*"); + printk("%s", units[sys][i]); + if(nibble != 1) { + /* This is a _signed_ nibble(!) */ + + int val = nibble & 0x7; + if(nibble & 0x08) + val = -((0x7 & ~val) +1); + printk("^%d", val); + } + } + } + printk(")\n"); + } + } + tab(n); printk("Report Size(%u)\n", field->report_size); + tab(n); printk("Report Count(%u)\n", field->report_count); + tab(n); printk("Report Offset(%u)\n", field->report_offset); + + tab(n); printk("Flags( "); + j = field->flags; + printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); + printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); + printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); + printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); + printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); + printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : ""); + printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); + printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); + printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); + printk(")\n"); +} +EXPORT_SYMBOL_GPL(hid_dump_field); + +void hid_dump_device(struct hid_device *device) { + struct hid_report_enum *report_enum; + struct hid_report *report; + struct list_head *list; + unsigned i,k; + static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; + + for (i = 0; i < HID_REPORT_TYPES; i++) { + report_enum = device->report_enum + i; + list = report_enum->report_list.next; + while (list != &report_enum->report_list) { + report = (struct hid_report *) list; + tab(2); + printk("%s", table[i]); + if (report->id) + printk("(%d)", report->id); + printk("[%s]", table[report->type]); + printk("\n"); + for (k = 0; k < report->maxfield; k++) { + tab(4); + printk("Field(%d)\n", k); + hid_dump_field(report->field[k], 6); + } + list = list->next; + } + } +} +EXPORT_SYMBOL_GPL(hid_dump_device); + +void hid_dump_input(struct hid_usage *usage, __s32 value) { + printk("hid-debug: input "); + hid_resolv_usage(usage->hid); + printk(" = %d\n", value); +} +EXPORT_SYMBOL_GPL(hid_dump_input); + +static char *events[EV_MAX + 1] = { + [EV_SYN] = "Sync", [EV_KEY] = "Key", + [EV_REL] = "Relative", [EV_ABS] = "Absolute", + [EV_MSC] = "Misc", [EV_LED] = "LED", + [EV_SND] = "Sound", [EV_REP] = "Repeat", + [EV_FF] = "ForceFeedback", [EV_PWR] = "Power", + [EV_FF_STATUS] = "ForceFeedbackStatus", +}; + +static char *syncs[2] = { + [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config", +}; +static char *keys[KEY_MAX + 1] = { + [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc", + [KEY_1] = "1", [KEY_2] = "2", + [KEY_3] = "3", [KEY_4] = "4", + [KEY_5] = "5", [KEY_6] = "6", + [KEY_7] = "7", [KEY_8] = "8", + [KEY_9] = "9", [KEY_0] = "0", + [KEY_MINUS] = "Minus", [KEY_EQUAL] = "Equal", + [KEY_BACKSPACE] = "Backspace", [KEY_TAB] = "Tab", + [KEY_Q] = "Q", [KEY_W] = "W", + [KEY_E] = "E", [KEY_R] = "R", + [KEY_T] = "T", [KEY_Y] = "Y", + [KEY_U] = "U", [KEY_I] = "I", + [KEY_O] = "O", [KEY_P] = "P", + [KEY_LEFTBRACE] = "LeftBrace", [KEY_RIGHTBRACE] = "RightBrace", + [KEY_ENTER] = "Enter", [KEY_LEFTCTRL] = "LeftControl", + [KEY_A] = "A", [KEY_S] = "S", + [KEY_D] = "D", [KEY_F] = "F", + [KEY_G] = "G", [KEY_H] = "H", + [KEY_J] = "J", [KEY_K] = "K", + [KEY_L] = "L", [KEY_SEMICOLON] = "Semicolon", + [KEY_APOSTROPHE] = "Apostrophe", [KEY_GRAVE] = "Grave", + [KEY_LEFTSHIFT] = "LeftShift", [KEY_BACKSLASH] = "BackSlash", + [KEY_Z] = "Z", [KEY_X] = "X", + [KEY_C] = "C", [KEY_V] = "V", + [KEY_B] = "B", [KEY_N] = "N", + [KEY_M] = "M", [KEY_COMMA] = "Comma", + [KEY_DOT] = "Dot", [KEY_SLASH] = "Slash", + [KEY_RIGHTSHIFT] = "RightShift", [KEY_KPASTERISK] = "KPAsterisk", + [KEY_LEFTALT] = "LeftAlt", [KEY_SPACE] = "Space", + [KEY_CAPSLOCK] = "CapsLock", [KEY_F1] = "F1", + [KEY_F2] = "F2", [KEY_F3] = "F3", + [KEY_F4] = "F4", [KEY_F5] = "F5", + [KEY_F6] = "F6", [KEY_F7] = "F7", + [KEY_F8] = "F8", [KEY_F9] = "F9", + [KEY_F10] = "F10", [KEY_NUMLOCK] = "NumLock", + [KEY_SCROLLLOCK] = "ScrollLock", [KEY_KP7] = "KP7", + [KEY_KP8] = "KP8", [KEY_KP9] = "KP9", + [KEY_KPMINUS] = "KPMinus", [KEY_KP4] = "KP4", + [KEY_KP5] = "KP5", [KEY_KP6] = "KP6", + [KEY_KPPLUS] = "KPPlus", [KEY_KP1] = "KP1", + [KEY_KP2] = "KP2", [KEY_KP3] = "KP3", + [KEY_KP0] = "KP0", [KEY_KPDOT] = "KPDot", + [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd", + [KEY_F11] = "F11", [KEY_F12] = "F12", + [KEY_RO] = "RO", [KEY_KATAKANA] = "Katakana", + [KEY_HIRAGANA] = "HIRAGANA", [KEY_HENKAN] = "Henkan", + [KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan", + [KEY_KPJPCOMMA] = "KPJpComma", [KEY_KPENTER] = "KPEnter", + [KEY_RIGHTCTRL] = "RightCtrl", [KEY_KPSLASH] = "KPSlash", + [KEY_SYSRQ] = "SysRq", [KEY_RIGHTALT] = "RightAlt", + [KEY_LINEFEED] = "LineFeed", [KEY_HOME] = "Home", + [KEY_UP] = "Up", [KEY_PAGEUP] = "PageUp", + [KEY_LEFT] = "Left", [KEY_RIGHT] = "Right", + [KEY_END] = "End", [KEY_DOWN] = "Down", + [KEY_PAGEDOWN] = "PageDown", [KEY_INSERT] = "Insert", + [KEY_DELETE] = "Delete", [KEY_MACRO] = "Macro", + [KEY_MUTE] = "Mute", [KEY_VOLUMEDOWN] = "VolumeDown", + [KEY_VOLUMEUP] = "VolumeUp", [KEY_POWER] = "Power", + [KEY_KPEQUAL] = "KPEqual", [KEY_KPPLUSMINUS] = "KPPlusMinus", + [KEY_PAUSE] = "Pause", [KEY_KPCOMMA] = "KPComma", + [KEY_HANGUEL] = "Hangeul", [KEY_HANJA] = "Hanja", + [KEY_YEN] = "Yen", [KEY_LEFTMETA] = "LeftMeta", + [KEY_RIGHTMETA] = "RightMeta", [KEY_COMPOSE] = "Compose", + [KEY_STOP] = "Stop", [KEY_AGAIN] = "Again", + [KEY_PROPS] = "Props", [KEY_UNDO] = "Undo", + [KEY_FRONT] = "Front", [KEY_COPY] = "Copy", + [KEY_OPEN] = "Open", [KEY_PASTE] = "Paste", + [KEY_FIND] = "Find", [KEY_CUT] = "Cut", + [KEY_HELP] = "Help", [KEY_MENU] = "Menu", + [KEY_CALC] = "Calc", [KEY_SETUP] = "Setup", + [KEY_SLEEP] = "Sleep", [KEY_WAKEUP] = "WakeUp", + [KEY_FILE] = "File", [KEY_SENDFILE] = "SendFile", + [KEY_DELETEFILE] = "DeleteFile", [KEY_XFER] = "X-fer", + [KEY_PROG1] = "Prog1", [KEY_PROG2] = "Prog2", + [KEY_WWW] = "WWW", [KEY_MSDOS] = "MSDOS", + [KEY_COFFEE] = "Coffee", [KEY_DIRECTION] = "Direction", + [KEY_CYCLEWINDOWS] = "CycleWindows", [KEY_MAIL] = "Mail", + [KEY_BOOKMARKS] = "Bookmarks", [KEY_COMPUTER] = "Computer", + [KEY_BACK] = "Back", [KEY_FORWARD] = "Forward", + [KEY_CLOSECD] = "CloseCD", [KEY_EJECTCD] = "EjectCD", + [KEY_EJECTCLOSECD] = "EjectCloseCD", [KEY_NEXTSONG] = "NextSong", + [KEY_PLAYPAUSE] = "PlayPause", [KEY_PREVIOUSSONG] = "PreviousSong", + [KEY_STOPCD] = "StopCD", [KEY_RECORD] = "Record", + [KEY_REWIND] = "Rewind", [KEY_PHONE] = "Phone", + [KEY_ISO] = "ISOKey", [KEY_CONFIG] = "Config", + [KEY_HOMEPAGE] = "HomePage", [KEY_REFRESH] = "Refresh", + [KEY_EXIT] = "Exit", [KEY_MOVE] = "Move", + [KEY_EDIT] = "Edit", [KEY_SCROLLUP] = "ScrollUp", + [KEY_SCROLLDOWN] = "ScrollDown", [KEY_KPLEFTPAREN] = "KPLeftParenthesis", + [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New", + [KEY_REDO] = "Redo", [KEY_F13] = "F13", + [KEY_F14] = "F14", [KEY_F15] = "F15", + [KEY_F16] = "F16", [KEY_F17] = "F17", + [KEY_F18] = "F18", [KEY_F19] = "F19", + [KEY_F20] = "F20", [KEY_F21] = "F21", + [KEY_F22] = "F22", [KEY_F23] = "F23", + [KEY_F24] = "F24", [KEY_PLAYCD] = "PlayCD", + [KEY_PAUSECD] = "PauseCD", [KEY_PROG3] = "Prog3", + [KEY_PROG4] = "Prog4", [KEY_SUSPEND] = "Suspend", + [KEY_CLOSE] = "Close", [KEY_PLAY] = "Play", + [KEY_FASTFORWARD] = "FastForward", [KEY_BASSBOOST] = "BassBoost", + [KEY_PRINT] = "Print", [KEY_HP] = "HP", + [KEY_CAMERA] = "Camera", [KEY_SOUND] = "Sound", + [KEY_QUESTION] = "Question", [KEY_EMAIL] = "Email", + [KEY_CHAT] = "Chat", [KEY_SEARCH] = "Search", + [KEY_CONNECT] = "Connect", [KEY_FINANCE] = "Finance", + [KEY_SPORT] = "Sport", [KEY_SHOP] = "Shop", + [KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel", + [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp", + [KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown", + [BTN_0] = "Btn0", [BTN_1] = "Btn1", + [BTN_2] = "Btn2", [BTN_3] = "Btn3", + [BTN_4] = "Btn4", [BTN_5] = "Btn5", + [BTN_6] = "Btn6", [BTN_7] = "Btn7", + [BTN_8] = "Btn8", [BTN_9] = "Btn9", + [BTN_LEFT] = "LeftBtn", [BTN_RIGHT] = "RightBtn", + [BTN_MIDDLE] = "MiddleBtn", [BTN_SIDE] = "SideBtn", + [BTN_EXTRA] = "ExtraBtn", [BTN_FORWARD] = "ForwardBtn", + [BTN_BACK] = "BackBtn", [BTN_TASK] = "TaskBtn", + [BTN_TRIGGER] = "Trigger", [BTN_THUMB] = "ThumbBtn", + [BTN_THUMB2] = "ThumbBtn2", [BTN_TOP] = "TopBtn", + [BTN_TOP2] = "TopBtn2", [BTN_PINKIE] = "PinkieBtn", + [BTN_BASE] = "BaseBtn", [BTN_BASE2] = "BaseBtn2", + [BTN_BASE3] = "BaseBtn3", [BTN_BASE4] = "BaseBtn4", + [BTN_BASE5] = "BaseBtn5", [BTN_BASE6] = "BaseBtn6", + [BTN_DEAD] = "BtnDead", [BTN_A] = "BtnA", + [BTN_B] = "BtnB", [BTN_C] = "BtnC", + [BTN_X] = "BtnX", [BTN_Y] = "BtnY", + [BTN_Z] = "BtnZ", [BTN_TL] = "BtnTL", + [BTN_TR] = "BtnTR", [BTN_TL2] = "BtnTL2", + [BTN_TR2] = "BtnTR2", [BTN_SELECT] = "BtnSelect", + [BTN_START] = "BtnStart", [BTN_MODE] = "BtnMode", + [BTN_THUMBL] = "BtnThumbL", [BTN_THUMBR] = "BtnThumbR", + [BTN_TOOL_PEN] = "ToolPen", [BTN_TOOL_RUBBER] = "ToolRubber", + [BTN_TOOL_BRUSH] = "ToolBrush", [BTN_TOOL_PENCIL] = "ToolPencil", + [BTN_TOOL_AIRBRUSH] = "ToolAirbrush", [BTN_TOOL_FINGER] = "ToolFinger", + [BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens", + [BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus", + [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap", + [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn", + [BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok", + [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto", + [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2", + [KEY_OPTION] = "Option", [KEY_INFO] = "Info", + [KEY_TIME] = "Time", [KEY_VENDOR] = "Vendor", + [KEY_ARCHIVE] = "Archive", [KEY_PROGRAM] = "Program", + [KEY_CHANNEL] = "Channel", [KEY_FAVORITES] = "Favorites", + [KEY_EPG] = "EPG", [KEY_PVR] = "PVR", + [KEY_MHP] = "MHP", [KEY_LANGUAGE] = "Language", + [KEY_TITLE] = "Title", [KEY_SUBTITLE] = "Subtitle", + [KEY_ANGLE] = "Angle", [KEY_ZOOM] = "Zoom", + [KEY_MODE] = "Mode", [KEY_KEYBOARD] = "Keyboard", + [KEY_SCREEN] = "Screen", [KEY_PC] = "PC", + [KEY_TV] = "TV", [KEY_TV2] = "TV2", + [KEY_VCR] = "VCR", [KEY_VCR2] = "VCR2", + [KEY_SAT] = "Sat", [KEY_SAT2] = "Sat2", + [KEY_CD] = "CD", [KEY_TAPE] = "Tape", + [KEY_RADIO] = "Radio", [KEY_TUNER] = "Tuner", + [KEY_PLAYER] = "Player", [KEY_TEXT] = "Text", + [KEY_DVD] = "DVD", [KEY_AUX] = "Aux", + [KEY_MP3] = "MP3", [KEY_AUDIO] = "Audio", + [KEY_VIDEO] = "Video", [KEY_DIRECTORY] = "Directory", + [KEY_LIST] = "List", [KEY_MEMO] = "Memo", + [KEY_CALENDAR] = "Calendar", [KEY_RED] = "Red", + [KEY_GREEN] = "Green", [KEY_YELLOW] = "Yellow", + [KEY_BLUE] = "Blue", [KEY_CHANNELUP] = "ChannelUp", + [KEY_CHANNELDOWN] = "ChannelDown", [KEY_FIRST] = "First", + [KEY_LAST] = "Last", [KEY_AB] = "AB", + [KEY_NEXT] = "Next", [KEY_RESTART] = "Restart", + [KEY_SLOW] = "Slow", [KEY_SHUFFLE] = "Shuffle", + [KEY_BREAK] = "Break", [KEY_PREVIOUS] = "Previous", + [KEY_DIGITS] = "Digits", [KEY_TEEN] = "TEEN", + [KEY_TWEN] = "TWEN", [KEY_DEL_EOL] = "DeleteEOL", + [KEY_DEL_EOS] = "DeleteEOS", [KEY_INS_LINE] = "InsertLine", + [KEY_DEL_LINE] = "DeleteLine", + [KEY_SEND] = "Send", [KEY_REPLY] = "Reply", + [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save", + [KEY_DOCUMENTS] = "Documents", + [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC", + [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2", + [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D", + [KEY_FN_E] = "Fn+E", [KEY_FN_F] = "Fn+F", + [KEY_FN_S] = "Fn+S", + [KEY_FN_F1] = "Fn+F1", [KEY_FN_F2] = "Fn+F2", + [KEY_FN_F3] = "Fn+F3", [KEY_FN_F4] = "Fn+F4", + [KEY_FN_F5] = "Fn+F5", [KEY_FN_F6] = "Fn+F6", + [KEY_FN_F7] = "Fn+F7", [KEY_FN_F8] = "Fn+F8", + [KEY_FN_F9] = "Fn+F9", [KEY_FN_F10] = "Fn+F10", + [KEY_FN_F11] = "Fn+F11", [KEY_FN_F12] = "Fn+F12", + [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle", + [KEY_KBDILLUMDOWN] = "KbdIlluminationDown", + [KEY_KBDILLUMUP] = "KbdIlluminationUp", + [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", +}; + +static char *relatives[REL_MAX + 1] = { + [REL_X] = "X", [REL_Y] = "Y", + [REL_Z] = "Z", [REL_RX] = "Rx", + [REL_RY] = "Ry", [REL_RZ] = "Rz", + [REL_HWHEEL] = "HWheel", [REL_DIAL] = "Dial", + [REL_WHEEL] = "Wheel", [REL_MISC] = "Misc", +}; + +static char *absolutes[ABS_MAX + 1] = { + [ABS_X] = "X", [ABS_Y] = "Y", + [ABS_Z] = "Z", [ABS_RX] = "Rx", + [ABS_RY] = "Ry", [ABS_RZ] = "Rz", + [ABS_THROTTLE] = "Throttle", [ABS_RUDDER] = "Rudder", + [ABS_WHEEL] = "Wheel", [ABS_GAS] = "Gas", + [ABS_BRAKE] = "Brake", [ABS_HAT0X] = "Hat0X", + [ABS_HAT0Y] = "Hat0Y", [ABS_HAT1X] = "Hat1X", + [ABS_HAT1Y] = "Hat1Y", [ABS_HAT2X] = "Hat2X", + [ABS_HAT2Y] = "Hat2Y", [ABS_HAT3X] = "Hat3X", + [ABS_HAT3Y] = "Hat 3Y", [ABS_PRESSURE] = "Pressure", + [ABS_DISTANCE] = "Distance", [ABS_TILT_X] = "XTilt", + [ABS_TILT_Y] = "YTilt", [ABS_TOOL_WIDTH] = "Tool Width", + [ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc", +}; + +static char *misc[MSC_MAX + 1] = { + [MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled", + [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData" +}; + +static char *leds[LED_MAX + 1] = { + [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock", + [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose", + [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", + [LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute", + [LED_MISC] = "Misc", +}; + +static char *repeats[REP_MAX + 1] = { + [REP_DELAY] = "Delay", [REP_PERIOD] = "Period" +}; + +static char *sounds[SND_MAX + 1] = { + [SND_CLICK] = "Click", [SND_BELL] = "Bell", + [SND_TONE] = "Tone" +}; + +static char **names[EV_MAX + 1] = { + [EV_SYN] = syncs, [EV_KEY] = keys, + [EV_REL] = relatives, [EV_ABS] = absolutes, + [EV_MSC] = misc, [EV_LED] = leds, + [EV_SND] = sounds, [EV_REP] = repeats, +}; + +void hid_resolv_event(__u8 type, __u16 code) { + + printk("%s.%s", events[type] ? events[type] : "?", + names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); +} +EXPORT_SYMBOL_GPL(hid_resolv_event); + diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 33b1126f5e5d..ae298c4bfcbd 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -34,6 +34,7 @@ #undef DEBUG #include +#include static int hid_pb_fnmode = 1; module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644); @@ -254,7 +255,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel #ifdef DEBUG printk(KERN_DEBUG "Mapping: "); - resolv_usage(usage->hid); + hid_resolv_usage(usage->hid); printk(" ---> "); #endif @@ -682,8 +683,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel field->dpad = usage->code; } -#ifdef DEBUG - resolv_event(usage->type, usage->code); + hid_resolv_event(usage->type, usage->code); +#ifdef CONFIG_HID_DEBUG printk("\n"); #endif return; diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 1fa42f400176..6938c4e0e5e2 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -35,6 +35,7 @@ #include #include +#include #include "usbhid.h" /* diff --git a/include/linux/hid-debug.h b/include/linux/hid-debug.h index 8e4dbb51fc70..50d568ec178a 100644 --- a/include/linux/hid-debug.h +++ b/include/linux/hid-debug.h @@ -1,10 +1,8 @@ +#ifndef __HID_DEBUG_H +#define __HID_DEBUG_H + /* - * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $ - * - * (c) 1999 Andreas Gal - * (c) 2000-2001 Vojtech Pavlik - * - * Some debug stuff for the HID parser. + * Copyright (c) 2007 Jiri Kosina */ /* @@ -22,737 +20,26 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ -#include - -struct hid_usage_entry { - unsigned page; - unsigned usage; - char *description; -}; - -static const struct hid_usage_entry hid_usage_table[] = { - { 0, 0, "Undefined" }, - { 1, 0, "GenericDesktop" }, - {0, 0x01, "Pointer"}, - {0, 0x02, "Mouse"}, - {0, 0x04, "Joystick"}, - {0, 0x05, "GamePad"}, - {0, 0x06, "Keyboard"}, - {0, 0x07, "Keypad"}, - {0, 0x08, "MultiAxis"}, - {0, 0x30, "X"}, - {0, 0x31, "Y"}, - {0, 0x32, "Z"}, - {0, 0x33, "Rx"}, - {0, 0x34, "Ry"}, - {0, 0x35, "Rz"}, - {0, 0x36, "Slider"}, - {0, 0x37, "Dial"}, - {0, 0x38, "Wheel"}, - {0, 0x39, "HatSwitch"}, - {0, 0x3a, "CountedBuffer"}, - {0, 0x3b, "ByteCount"}, - {0, 0x3c, "MotionWakeup"}, - {0, 0x3d, "Start"}, - {0, 0x3e, "Select"}, - {0, 0x40, "Vx"}, - {0, 0x41, "Vy"}, - {0, 0x42, "Vz"}, - {0, 0x43, "Vbrx"}, - {0, 0x44, "Vbry"}, - {0, 0x45, "Vbrz"}, - {0, 0x46, "Vno"}, - {0, 0x80, "SystemControl"}, - {0, 0x81, "SystemPowerDown"}, - {0, 0x82, "SystemSleep"}, - {0, 0x83, "SystemWakeUp"}, - {0, 0x84, "SystemContextMenu"}, - {0, 0x85, "SystemMainMenu"}, - {0, 0x86, "SystemAppMenu"}, - {0, 0x87, "SystemMenuHelp"}, - {0, 0x88, "SystemMenuExit"}, - {0, 0x89, "SystemMenuSelect"}, - {0, 0x8a, "SystemMenuRight"}, - {0, 0x8b, "SystemMenuLeft"}, - {0, 0x8c, "SystemMenuUp"}, - {0, 0x8d, "SystemMenuDown"}, - {0, 0x90, "D-PadUp"}, - {0, 0x91, "D-PadDown"}, - {0, 0x92, "D-PadRight"}, - {0, 0x93, "D-PadLeft"}, - { 2, 0, "Simulation" }, - {0, 0xb0, "Aileron"}, - {0, 0xb1, "AileronTrim"}, - {0, 0xb2, "Anti-Torque"}, - {0, 0xb3, "Autopilot"}, - {0, 0xb4, "Chaff"}, - {0, 0xb5, "Collective"}, - {0, 0xb6, "DiveBrake"}, - {0, 0xb7, "ElectronicCountermeasures"}, - {0, 0xb8, "Elevator"}, - {0, 0xb9, "ElevatorTrim"}, - {0, 0xba, "Rudder"}, - {0, 0xbb, "Throttle"}, - {0, 0xbc, "FlightCommunications"}, - {0, 0xbd, "FlareRelease"}, - {0, 0xbe, "LandingGear"}, - {0, 0xbf, "ToeBrake"}, - { 7, 0, "Keyboard" }, - { 8, 0, "LED" }, - {0, 0x01, "NumLock"}, - {0, 0x02, "CapsLock"}, - {0, 0x03, "ScrollLock"}, - {0, 0x04, "Compose"}, - {0, 0x05, "Kana"}, - {0, 0x4b, "GenericIndicator"}, - { 9, 0, "Button" }, - { 10, 0, "Ordinal" }, - { 12, 0, "Consumer" }, - {0, 0x238, "HorizontalWheel"}, - { 13, 0, "Digitizers" }, - {0, 0x01, "Digitizer"}, - {0, 0x02, "Pen"}, - {0, 0x03, "LightPen"}, - {0, 0x04, "TouchScreen"}, - {0, 0x05, "TouchPad"}, - {0, 0x20, "Stylus"}, - {0, 0x21, "Puck"}, - {0, 0x22, "Finger"}, - {0, 0x30, "TipPressure"}, - {0, 0x31, "BarrelPressure"}, - {0, 0x32, "InRange"}, - {0, 0x33, "Touch"}, - {0, 0x34, "UnTouch"}, - {0, 0x35, "Tap"}, - {0, 0x39, "TabletFunctionKey"}, - {0, 0x3a, "ProgramChangeKey"}, - {0, 0x3c, "Invert"}, - {0, 0x42, "TipSwitch"}, - {0, 0x43, "SecondaryTipSwitch"}, - {0, 0x44, "BarrelSwitch"}, - {0, 0x45, "Eraser"}, - {0, 0x46, "TabletPick"}, - { 15, 0, "PhysicalInterfaceDevice" }, - {0, 0x00, "Undefined"}, - {0, 0x01, "Physical_Interface_Device"}, - {0, 0x20, "Normal"}, - {0, 0x21, "Set_Effect_Report"}, - {0, 0x22, "Effect_Block_Index"}, - {0, 0x23, "Parameter_Block_Offset"}, - {0, 0x24, "ROM_Flag"}, - {0, 0x25, "Effect_Type"}, - {0, 0x26, "ET_Constant_Force"}, - {0, 0x27, "ET_Ramp"}, - {0, 0x28, "ET_Custom_Force_Data"}, - {0, 0x30, "ET_Square"}, - {0, 0x31, "ET_Sine"}, - {0, 0x32, "ET_Triangle"}, - {0, 0x33, "ET_Sawtooth_Up"}, - {0, 0x34, "ET_Sawtooth_Down"}, - {0, 0x40, "ET_Spring"}, - {0, 0x41, "ET_Damper"}, - {0, 0x42, "ET_Inertia"}, - {0, 0x43, "ET_Friction"}, - {0, 0x50, "Duration"}, - {0, 0x51, "Sample_Period"}, - {0, 0x52, "Gain"}, - {0, 0x53, "Trigger_Button"}, - {0, 0x54, "Trigger_Repeat_Interval"}, - {0, 0x55, "Axes_Enable"}, - {0, 0x56, "Direction_Enable"}, - {0, 0x57, "Direction"}, - {0, 0x58, "Type_Specific_Block_Offset"}, - {0, 0x59, "Block_Type"}, - {0, 0x5A, "Set_Envelope_Report"}, - {0, 0x5B, "Attack_Level"}, - {0, 0x5C, "Attack_Time"}, - {0, 0x5D, "Fade_Level"}, - {0, 0x5E, "Fade_Time"}, - {0, 0x5F, "Set_Condition_Report"}, - {0, 0x60, "CP_Offset"}, - {0, 0x61, "Positive_Coefficient"}, - {0, 0x62, "Negative_Coefficient"}, - {0, 0x63, "Positive_Saturation"}, - {0, 0x64, "Negative_Saturation"}, - {0, 0x65, "Dead_Band"}, - {0, 0x66, "Download_Force_Sample"}, - {0, 0x67, "Isoch_Custom_Force_Enable"}, - {0, 0x68, "Custom_Force_Data_Report"}, - {0, 0x69, "Custom_Force_Data"}, - {0, 0x6A, "Custom_Force_Vendor_Defined_Data"}, - {0, 0x6B, "Set_Custom_Force_Report"}, - {0, 0x6C, "Custom_Force_Data_Offset"}, - {0, 0x6D, "Sample_Count"}, - {0, 0x6E, "Set_Periodic_Report"}, - {0, 0x6F, "Offset"}, - {0, 0x70, "Magnitude"}, - {0, 0x71, "Phase"}, - {0, 0x72, "Period"}, - {0, 0x73, "Set_Constant_Force_Report"}, - {0, 0x74, "Set_Ramp_Force_Report"}, - {0, 0x75, "Ramp_Start"}, - {0, 0x76, "Ramp_End"}, - {0, 0x77, "Effect_Operation_Report"}, - {0, 0x78, "Effect_Operation"}, - {0, 0x79, "Op_Effect_Start"}, - {0, 0x7A, "Op_Effect_Start_Solo"}, - {0, 0x7B, "Op_Effect_Stop"}, - {0, 0x7C, "Loop_Count"}, - {0, 0x7D, "Device_Gain_Report"}, - {0, 0x7E, "Device_Gain"}, - {0, 0x7F, "PID_Pool_Report"}, - {0, 0x80, "RAM_Pool_Size"}, - {0, 0x81, "ROM_Pool_Size"}, - {0, 0x82, "ROM_Effect_Block_Count"}, - {0, 0x83, "Simultaneous_Effects_Max"}, - {0, 0x84, "Pool_Alignment"}, - {0, 0x85, "PID_Pool_Move_Report"}, - {0, 0x86, "Move_Source"}, - {0, 0x87, "Move_Destination"}, - {0, 0x88, "Move_Length"}, - {0, 0x89, "PID_Block_Load_Report"}, - {0, 0x8B, "Block_Load_Status"}, - {0, 0x8C, "Block_Load_Success"}, - {0, 0x8D, "Block_Load_Full"}, - {0, 0x8E, "Block_Load_Error"}, - {0, 0x8F, "Block_Handle"}, - {0, 0x90, "PID_Block_Free_Report"}, - {0, 0x91, "Type_Specific_Block_Handle"}, - {0, 0x92, "PID_State_Report"}, - {0, 0x94, "Effect_Playing"}, - {0, 0x95, "PID_Device_Control_Report"}, - {0, 0x96, "PID_Device_Control"}, - {0, 0x97, "DC_Enable_Actuators"}, - {0, 0x98, "DC_Disable_Actuators"}, - {0, 0x99, "DC_Stop_All_Effects"}, - {0, 0x9A, "DC_Device_Reset"}, - {0, 0x9B, "DC_Device_Pause"}, - {0, 0x9C, "DC_Device_Continue"}, - {0, 0x9F, "Device_Paused"}, - {0, 0xA0, "Actuators_Enabled"}, - {0, 0xA4, "Safety_Switch"}, - {0, 0xA5, "Actuator_Override_Switch"}, - {0, 0xA6, "Actuator_Power"}, - {0, 0xA7, "Start_Delay"}, - {0, 0xA8, "Parameter_Block_Size"}, - {0, 0xA9, "Device_Managed_Pool"}, - {0, 0xAA, "Shared_Parameter_Blocks"}, - {0, 0xAB, "Create_New_Effect_Report"}, - {0, 0xAC, "RAM_Pool_Available"}, - { 0x84, 0, "Power Device" }, - { 0x84, 0x02, "PresentStatus" }, - { 0x84, 0x03, "ChangeStatus" }, - { 0x84, 0x04, "UPS" }, - { 0x84, 0x05, "PowerSupply" }, - { 0x84, 0x10, "BatterySystem" }, - { 0x84, 0x11, "BatterySystemID" }, - { 0x84, 0x12, "Battery" }, - { 0x84, 0x13, "BatteryID" }, - { 0x84, 0x14, "Charger" }, - { 0x84, 0x15, "ChargerID" }, - { 0x84, 0x16, "PowerConverter" }, - { 0x84, 0x17, "PowerConverterID" }, - { 0x84, 0x18, "OutletSystem" }, - { 0x84, 0x19, "OutletSystemID" }, - { 0x84, 0x1a, "Input" }, - { 0x84, 0x1b, "InputID" }, - { 0x84, 0x1c, "Output" }, - { 0x84, 0x1d, "OutputID" }, - { 0x84, 0x1e, "Flow" }, - { 0x84, 0x1f, "FlowID" }, - { 0x84, 0x20, "Outlet" }, - { 0x84, 0x21, "OutletID" }, - { 0x84, 0x22, "Gang" }, - { 0x84, 0x24, "PowerSummary" }, - { 0x84, 0x25, "PowerSummaryID" }, - { 0x84, 0x30, "Voltage" }, - { 0x84, 0x31, "Current" }, - { 0x84, 0x32, "Frequency" }, - { 0x84, 0x33, "ApparentPower" }, - { 0x84, 0x35, "PercentLoad" }, - { 0x84, 0x40, "ConfigVoltage" }, - { 0x84, 0x41, "ConfigCurrent" }, - { 0x84, 0x43, "ConfigApparentPower" }, - { 0x84, 0x53, "LowVoltageTransfer" }, - { 0x84, 0x54, "HighVoltageTransfer" }, - { 0x84, 0x56, "DelayBeforeStartup" }, - { 0x84, 0x57, "DelayBeforeShutdown" }, - { 0x84, 0x58, "Test" }, - { 0x84, 0x5a, "AudibleAlarmControl" }, - { 0x84, 0x60, "Present" }, - { 0x84, 0x61, "Good" }, - { 0x84, 0x62, "InternalFailure" }, - { 0x84, 0x65, "Overload" }, - { 0x84, 0x66, "OverCharged" }, - { 0x84, 0x67, "OverTemperature" }, - { 0x84, 0x68, "ShutdownRequested" }, - { 0x84, 0x69, "ShutdownImminent" }, - { 0x84, 0x6b, "SwitchOn/Off" }, - { 0x84, 0x6c, "Switchable" }, - { 0x84, 0x6d, "Used" }, - { 0x84, 0x6e, "Boost" }, - { 0x84, 0x73, "CommunicationLost" }, - { 0x84, 0xfd, "iManufacturer" }, - { 0x84, 0xfe, "iProduct" }, - { 0x84, 0xff, "iSerialNumber" }, - { 0x85, 0, "Battery System" }, - { 0x85, 0x01, "SMBBatteryMode" }, - { 0x85, 0x02, "SMBBatteryStatus" }, - { 0x85, 0x03, "SMBAlarmWarning" }, - { 0x85, 0x04, "SMBChargerMode" }, - { 0x85, 0x05, "SMBChargerStatus" }, - { 0x85, 0x06, "SMBChargerSpecInfo" }, - { 0x85, 0x07, "SMBSelectorState" }, - { 0x85, 0x08, "SMBSelectorPresets" }, - { 0x85, 0x09, "SMBSelectorInfo" }, - { 0x85, 0x29, "RemainingCapacityLimit" }, - { 0x85, 0x2c, "CapacityMode" }, - { 0x85, 0x42, "BelowRemainingCapacityLimit" }, - { 0x85, 0x44, "Charging" }, - { 0x85, 0x45, "Discharging" }, - { 0x85, 0x4b, "NeedReplacement" }, - { 0x85, 0x66, "RemainingCapacity" }, - { 0x85, 0x68, "RunTimeToEmpty" }, - { 0x85, 0x6a, "AverageTimeToFull" }, - { 0x85, 0x83, "DesignCapacity" }, - { 0x85, 0x85, "ManufacturerDate" }, - { 0x85, 0x89, "iDeviceChemistry" }, - { 0x85, 0x8b, "Rechargable" }, - { 0x85, 0x8f, "iOEMInformation" }, - { 0x85, 0x8d, "CapacityGranularity1" }, - { 0x85, 0xd0, "ACPresent" }, - /* pages 0xff00 to 0xffff are vendor-specific */ - { 0xffff, 0, "Vendor-specific-FF" }, - { 0, 0, NULL } -}; - -static void resolv_usage_page(unsigned page) { - const struct hid_usage_entry *p; - - for (p = hid_usage_table; p->description; p++) - if (p->page == page) { - printk("%s", p->description); - return; - } - printk("%04x", page); -} - -static void resolv_usage(unsigned usage) { - const struct hid_usage_entry *p; - - resolv_usage_page(usage >> 16); - printk("."); - for (p = hid_usage_table; p->description; p++) - if (p->page == (usage >> 16)) { - for(++p; p->description && p->usage != 0; p++) - if (p->usage == (usage & 0xffff)) { - printk("%s", p->description); - return; - } - break; - } - printk("%04x", usage & 0xffff); -} - -__inline__ static void tab(int n) { - while (n--) printk(" "); -} - -static void hid_dump_field(struct hid_field *field, int n) { - int j; - - if (field->physical) { - tab(n); - printk("Physical("); - resolv_usage(field->physical); printk(")\n"); - } - if (field->logical) { - tab(n); - printk("Logical("); - resolv_usage(field->logical); printk(")\n"); - } - tab(n); printk("Usage(%d)\n", field->maxusage); - for (j = 0; j < field->maxusage; j++) { - tab(n+2);resolv_usage(field->usage[j].hid); printk("\n"); - } - if (field->logical_minimum != field->logical_maximum) { - tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum); - tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum); - } - if (field->physical_minimum != field->physical_maximum) { - tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum); - tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum); - } - if (field->unit_exponent) { - tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); - } - if (field->unit) { - char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; - char *units[5][8] = { - { "None", "None", "None", "None", "None", "None", "None", "None" }, - { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, - { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, - { "None", "Inch", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }, - { "None", "Degrees", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" } - }; - - int i; - int sys; - __u32 data = field->unit; - - /* First nibble tells us which system we're in. */ - sys = data & 0xf; - data >>= 4; - - if(sys > 4) { - tab(n); printk("Unit(Invalid)\n"); - } - else { - int earlier_unit = 0; - - tab(n); printk("Unit(%s : ", systems[sys]); - - for (i=1 ; i>= 4; - if (nibble != 0) { - if(earlier_unit++ > 0) - printk("*"); - printk("%s", units[sys][i]); - if(nibble != 1) { - /* This is a _signed_ nibble(!) */ - - int val = nibble & 0x7; - if(nibble & 0x08) - val = -((0x7 & ~val) +1); - printk("^%d", val); - } - } - } - printk(")\n"); - } - } - tab(n); printk("Report Size(%u)\n", field->report_size); - tab(n); printk("Report Count(%u)\n", field->report_count); - tab(n); printk("Report Offset(%u)\n", field->report_offset); - - tab(n); printk("Flags( "); - j = field->flags; - printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); - printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); - printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); - printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); - printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); - printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : ""); - printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); - printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); - printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); - printk(")\n"); -} - -static void __attribute__((unused)) hid_dump_device(struct hid_device *device) { - struct hid_report_enum *report_enum; - struct hid_report *report; - struct list_head *list; - unsigned i,k; - static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; - - for (i = 0; i < HID_REPORT_TYPES; i++) { - report_enum = device->report_enum + i; - list = report_enum->report_list.next; - while (list != &report_enum->report_list) { - report = (struct hid_report *) list; - tab(2); - printk("%s", table[i]); - if (report->id) - printk("(%d)", report->id); - printk("[%s]", table[report->type]); - printk("\n"); - for (k = 0; k < report->maxfield; k++) { - tab(4); - printk("Field(%d)\n", k); - hid_dump_field(report->field[k], 6); - } - list = list->next; - } - } -} - -static void __attribute__((unused)) hid_dump_input(struct hid_usage *usage, __s32 value) { - printk("hid-debug: input "); - resolv_usage(usage->hid); - printk(" = %d\n", value); -} - - -static char *events[EV_MAX + 1] = { - [EV_SYN] = "Sync", [EV_KEY] = "Key", - [EV_REL] = "Relative", [EV_ABS] = "Absolute", - [EV_MSC] = "Misc", [EV_LED] = "LED", - [EV_SND] = "Sound", [EV_REP] = "Repeat", - [EV_FF] = "ForceFeedback", [EV_PWR] = "Power", - [EV_FF_STATUS] = "ForceFeedbackStatus", -}; - -static char *syncs[2] = { - [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config", -}; -static char *keys[KEY_MAX + 1] = { - [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc", - [KEY_1] = "1", [KEY_2] = "2", - [KEY_3] = "3", [KEY_4] = "4", - [KEY_5] = "5", [KEY_6] = "6", - [KEY_7] = "7", [KEY_8] = "8", - [KEY_9] = "9", [KEY_0] = "0", - [KEY_MINUS] = "Minus", [KEY_EQUAL] = "Equal", - [KEY_BACKSPACE] = "Backspace", [KEY_TAB] = "Tab", - [KEY_Q] = "Q", [KEY_W] = "W", - [KEY_E] = "E", [KEY_R] = "R", - [KEY_T] = "T", [KEY_Y] = "Y", - [KEY_U] = "U", [KEY_I] = "I", - [KEY_O] = "O", [KEY_P] = "P", - [KEY_LEFTBRACE] = "LeftBrace", [KEY_RIGHTBRACE] = "RightBrace", - [KEY_ENTER] = "Enter", [KEY_LEFTCTRL] = "LeftControl", - [KEY_A] = "A", [KEY_S] = "S", - [KEY_D] = "D", [KEY_F] = "F", - [KEY_G] = "G", [KEY_H] = "H", - [KEY_J] = "J", [KEY_K] = "K", - [KEY_L] = "L", [KEY_SEMICOLON] = "Semicolon", - [KEY_APOSTROPHE] = "Apostrophe", [KEY_GRAVE] = "Grave", - [KEY_LEFTSHIFT] = "LeftShift", [KEY_BACKSLASH] = "BackSlash", - [KEY_Z] = "Z", [KEY_X] = "X", - [KEY_C] = "C", [KEY_V] = "V", - [KEY_B] = "B", [KEY_N] = "N", - [KEY_M] = "M", [KEY_COMMA] = "Comma", - [KEY_DOT] = "Dot", [KEY_SLASH] = "Slash", - [KEY_RIGHTSHIFT] = "RightShift", [KEY_KPASTERISK] = "KPAsterisk", - [KEY_LEFTALT] = "LeftAlt", [KEY_SPACE] = "Space", - [KEY_CAPSLOCK] = "CapsLock", [KEY_F1] = "F1", - [KEY_F2] = "F2", [KEY_F3] = "F3", - [KEY_F4] = "F4", [KEY_F5] = "F5", - [KEY_F6] = "F6", [KEY_F7] = "F7", - [KEY_F8] = "F8", [KEY_F9] = "F9", - [KEY_F10] = "F10", [KEY_NUMLOCK] = "NumLock", - [KEY_SCROLLLOCK] = "ScrollLock", [KEY_KP7] = "KP7", - [KEY_KP8] = "KP8", [KEY_KP9] = "KP9", - [KEY_KPMINUS] = "KPMinus", [KEY_KP4] = "KP4", - [KEY_KP5] = "KP5", [KEY_KP6] = "KP6", - [KEY_KPPLUS] = "KPPlus", [KEY_KP1] = "KP1", - [KEY_KP2] = "KP2", [KEY_KP3] = "KP3", - [KEY_KP0] = "KP0", [KEY_KPDOT] = "KPDot", - [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd", - [KEY_F11] = "F11", [KEY_F12] = "F12", - [KEY_RO] = "RO", [KEY_KATAKANA] = "Katakana", - [KEY_HIRAGANA] = "HIRAGANA", [KEY_HENKAN] = "Henkan", - [KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan", - [KEY_KPJPCOMMA] = "KPJpComma", [KEY_KPENTER] = "KPEnter", - [KEY_RIGHTCTRL] = "RightCtrl", [KEY_KPSLASH] = "KPSlash", - [KEY_SYSRQ] = "SysRq", [KEY_RIGHTALT] = "RightAlt", - [KEY_LINEFEED] = "LineFeed", [KEY_HOME] = "Home", - [KEY_UP] = "Up", [KEY_PAGEUP] = "PageUp", - [KEY_LEFT] = "Left", [KEY_RIGHT] = "Right", - [KEY_END] = "End", [KEY_DOWN] = "Down", - [KEY_PAGEDOWN] = "PageDown", [KEY_INSERT] = "Insert", - [KEY_DELETE] = "Delete", [KEY_MACRO] = "Macro", - [KEY_MUTE] = "Mute", [KEY_VOLUMEDOWN] = "VolumeDown", - [KEY_VOLUMEUP] = "VolumeUp", [KEY_POWER] = "Power", - [KEY_KPEQUAL] = "KPEqual", [KEY_KPPLUSMINUS] = "KPPlusMinus", - [KEY_PAUSE] = "Pause", [KEY_KPCOMMA] = "KPComma", - [KEY_HANGUEL] = "Hangeul", [KEY_HANJA] = "Hanja", - [KEY_YEN] = "Yen", [KEY_LEFTMETA] = "LeftMeta", - [KEY_RIGHTMETA] = "RightMeta", [KEY_COMPOSE] = "Compose", - [KEY_STOP] = "Stop", [KEY_AGAIN] = "Again", - [KEY_PROPS] = "Props", [KEY_UNDO] = "Undo", - [KEY_FRONT] = "Front", [KEY_COPY] = "Copy", - [KEY_OPEN] = "Open", [KEY_PASTE] = "Paste", - [KEY_FIND] = "Find", [KEY_CUT] = "Cut", - [KEY_HELP] = "Help", [KEY_MENU] = "Menu", - [KEY_CALC] = "Calc", [KEY_SETUP] = "Setup", - [KEY_SLEEP] = "Sleep", [KEY_WAKEUP] = "WakeUp", - [KEY_FILE] = "File", [KEY_SENDFILE] = "SendFile", - [KEY_DELETEFILE] = "DeleteFile", [KEY_XFER] = "X-fer", - [KEY_PROG1] = "Prog1", [KEY_PROG2] = "Prog2", - [KEY_WWW] = "WWW", [KEY_MSDOS] = "MSDOS", - [KEY_COFFEE] = "Coffee", [KEY_DIRECTION] = "Direction", - [KEY_CYCLEWINDOWS] = "CycleWindows", [KEY_MAIL] = "Mail", - [KEY_BOOKMARKS] = "Bookmarks", [KEY_COMPUTER] = "Computer", - [KEY_BACK] = "Back", [KEY_FORWARD] = "Forward", - [KEY_CLOSECD] = "CloseCD", [KEY_EJECTCD] = "EjectCD", - [KEY_EJECTCLOSECD] = "EjectCloseCD", [KEY_NEXTSONG] = "NextSong", - [KEY_PLAYPAUSE] = "PlayPause", [KEY_PREVIOUSSONG] = "PreviousSong", - [KEY_STOPCD] = "StopCD", [KEY_RECORD] = "Record", - [KEY_REWIND] = "Rewind", [KEY_PHONE] = "Phone", - [KEY_ISO] = "ISOKey", [KEY_CONFIG] = "Config", - [KEY_HOMEPAGE] = "HomePage", [KEY_REFRESH] = "Refresh", - [KEY_EXIT] = "Exit", [KEY_MOVE] = "Move", - [KEY_EDIT] = "Edit", [KEY_SCROLLUP] = "ScrollUp", - [KEY_SCROLLDOWN] = "ScrollDown", [KEY_KPLEFTPAREN] = "KPLeftParenthesis", - [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New", - [KEY_REDO] = "Redo", [KEY_F13] = "F13", - [KEY_F14] = "F14", [KEY_F15] = "F15", - [KEY_F16] = "F16", [KEY_F17] = "F17", - [KEY_F18] = "F18", [KEY_F19] = "F19", - [KEY_F20] = "F20", [KEY_F21] = "F21", - [KEY_F22] = "F22", [KEY_F23] = "F23", - [KEY_F24] = "F24", [KEY_PLAYCD] = "PlayCD", - [KEY_PAUSECD] = "PauseCD", [KEY_PROG3] = "Prog3", - [KEY_PROG4] = "Prog4", [KEY_SUSPEND] = "Suspend", - [KEY_CLOSE] = "Close", [KEY_PLAY] = "Play", - [KEY_FASTFORWARD] = "FastForward", [KEY_BASSBOOST] = "BassBoost", - [KEY_PRINT] = "Print", [KEY_HP] = "HP", - [KEY_CAMERA] = "Camera", [KEY_SOUND] = "Sound", - [KEY_QUESTION] = "Question", [KEY_EMAIL] = "Email", - [KEY_CHAT] = "Chat", [KEY_SEARCH] = "Search", - [KEY_CONNECT] = "Connect", [KEY_FINANCE] = "Finance", - [KEY_SPORT] = "Sport", [KEY_SHOP] = "Shop", - [KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel", - [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp", - [KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown", - [BTN_0] = "Btn0", [BTN_1] = "Btn1", - [BTN_2] = "Btn2", [BTN_3] = "Btn3", - [BTN_4] = "Btn4", [BTN_5] = "Btn5", - [BTN_6] = "Btn6", [BTN_7] = "Btn7", - [BTN_8] = "Btn8", [BTN_9] = "Btn9", - [BTN_LEFT] = "LeftBtn", [BTN_RIGHT] = "RightBtn", - [BTN_MIDDLE] = "MiddleBtn", [BTN_SIDE] = "SideBtn", - [BTN_EXTRA] = "ExtraBtn", [BTN_FORWARD] = "ForwardBtn", - [BTN_BACK] = "BackBtn", [BTN_TASK] = "TaskBtn", - [BTN_TRIGGER] = "Trigger", [BTN_THUMB] = "ThumbBtn", - [BTN_THUMB2] = "ThumbBtn2", [BTN_TOP] = "TopBtn", - [BTN_TOP2] = "TopBtn2", [BTN_PINKIE] = "PinkieBtn", - [BTN_BASE] = "BaseBtn", [BTN_BASE2] = "BaseBtn2", - [BTN_BASE3] = "BaseBtn3", [BTN_BASE4] = "BaseBtn4", - [BTN_BASE5] = "BaseBtn5", [BTN_BASE6] = "BaseBtn6", - [BTN_DEAD] = "BtnDead", [BTN_A] = "BtnA", - [BTN_B] = "BtnB", [BTN_C] = "BtnC", - [BTN_X] = "BtnX", [BTN_Y] = "BtnY", - [BTN_Z] = "BtnZ", [BTN_TL] = "BtnTL", - [BTN_TR] = "BtnTR", [BTN_TL2] = "BtnTL2", - [BTN_TR2] = "BtnTR2", [BTN_SELECT] = "BtnSelect", - [BTN_START] = "BtnStart", [BTN_MODE] = "BtnMode", - [BTN_THUMBL] = "BtnThumbL", [BTN_THUMBR] = "BtnThumbR", - [BTN_TOOL_PEN] = "ToolPen", [BTN_TOOL_RUBBER] = "ToolRubber", - [BTN_TOOL_BRUSH] = "ToolBrush", [BTN_TOOL_PENCIL] = "ToolPencil", - [BTN_TOOL_AIRBRUSH] = "ToolAirbrush", [BTN_TOOL_FINGER] = "ToolFinger", - [BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens", - [BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus", - [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap", - [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn", - [BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok", - [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto", - [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2", - [KEY_OPTION] = "Option", [KEY_INFO] = "Info", - [KEY_TIME] = "Time", [KEY_VENDOR] = "Vendor", - [KEY_ARCHIVE] = "Archive", [KEY_PROGRAM] = "Program", - [KEY_CHANNEL] = "Channel", [KEY_FAVORITES] = "Favorites", - [KEY_EPG] = "EPG", [KEY_PVR] = "PVR", - [KEY_MHP] = "MHP", [KEY_LANGUAGE] = "Language", - [KEY_TITLE] = "Title", [KEY_SUBTITLE] = "Subtitle", - [KEY_ANGLE] = "Angle", [KEY_ZOOM] = "Zoom", - [KEY_MODE] = "Mode", [KEY_KEYBOARD] = "Keyboard", - [KEY_SCREEN] = "Screen", [KEY_PC] = "PC", - [KEY_TV] = "TV", [KEY_TV2] = "TV2", - [KEY_VCR] = "VCR", [KEY_VCR2] = "VCR2", - [KEY_SAT] = "Sat", [KEY_SAT2] = "Sat2", - [KEY_CD] = "CD", [KEY_TAPE] = "Tape", - [KEY_RADIO] = "Radio", [KEY_TUNER] = "Tuner", - [KEY_PLAYER] = "Player", [KEY_TEXT] = "Text", - [KEY_DVD] = "DVD", [KEY_AUX] = "Aux", - [KEY_MP3] = "MP3", [KEY_AUDIO] = "Audio", - [KEY_VIDEO] = "Video", [KEY_DIRECTORY] = "Directory", - [KEY_LIST] = "List", [KEY_MEMO] = "Memo", - [KEY_CALENDAR] = "Calendar", [KEY_RED] = "Red", - [KEY_GREEN] = "Green", [KEY_YELLOW] = "Yellow", - [KEY_BLUE] = "Blue", [KEY_CHANNELUP] = "ChannelUp", - [KEY_CHANNELDOWN] = "ChannelDown", [KEY_FIRST] = "First", - [KEY_LAST] = "Last", [KEY_AB] = "AB", - [KEY_NEXT] = "Next", [KEY_RESTART] = "Restart", - [KEY_SLOW] = "Slow", [KEY_SHUFFLE] = "Shuffle", - [KEY_BREAK] = "Break", [KEY_PREVIOUS] = "Previous", - [KEY_DIGITS] = "Digits", [KEY_TEEN] = "TEEN", - [KEY_TWEN] = "TWEN", [KEY_DEL_EOL] = "DeleteEOL", - [KEY_DEL_EOS] = "DeleteEOS", [KEY_INS_LINE] = "InsertLine", - [KEY_DEL_LINE] = "DeleteLine", - [KEY_SEND] = "Send", [KEY_REPLY] = "Reply", - [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save", - [KEY_DOCUMENTS] = "Documents", - [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC", - [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2", - [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D", - [KEY_FN_E] = "Fn+E", [KEY_FN_F] = "Fn+F", - [KEY_FN_S] = "Fn+S", - [KEY_FN_F1] = "Fn+F1", [KEY_FN_F2] = "Fn+F2", - [KEY_FN_F3] = "Fn+F3", [KEY_FN_F4] = "Fn+F4", - [KEY_FN_F5] = "Fn+F5", [KEY_FN_F6] = "Fn+F6", - [KEY_FN_F7] = "Fn+F7", [KEY_FN_F8] = "Fn+F8", - [KEY_FN_F9] = "Fn+F9", [KEY_FN_F10] = "Fn+F10", - [KEY_FN_F11] = "Fn+F11", [KEY_FN_F12] = "Fn+F12", - [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle", - [KEY_KBDILLUMDOWN] = "KbdIlluminationDown", - [KEY_KBDILLUMUP] = "KbdIlluminationUp", - [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", -}; - -static char *relatives[REL_MAX + 1] = { - [REL_X] = "X", [REL_Y] = "Y", - [REL_Z] = "Z", [REL_RX] = "Rx", - [REL_RY] = "Ry", [REL_RZ] = "Rz", - [REL_HWHEEL] = "HWheel", [REL_DIAL] = "Dial", - [REL_WHEEL] = "Wheel", [REL_MISC] = "Misc", -}; - -static char *absolutes[ABS_MAX + 1] = { - [ABS_X] = "X", [ABS_Y] = "Y", - [ABS_Z] = "Z", [ABS_RX] = "Rx", - [ABS_RY] = "Ry", [ABS_RZ] = "Rz", - [ABS_THROTTLE] = "Throttle", [ABS_RUDDER] = "Rudder", - [ABS_WHEEL] = "Wheel", [ABS_GAS] = "Gas", - [ABS_BRAKE] = "Brake", [ABS_HAT0X] = "Hat0X", - [ABS_HAT0Y] = "Hat0Y", [ABS_HAT1X] = "Hat1X", - [ABS_HAT1Y] = "Hat1Y", [ABS_HAT2X] = "Hat2X", - [ABS_HAT2Y] = "Hat2Y", [ABS_HAT3X] = "Hat3X", - [ABS_HAT3Y] = "Hat 3Y", [ABS_PRESSURE] = "Pressure", - [ABS_DISTANCE] = "Distance", [ABS_TILT_X] = "XTilt", - [ABS_TILT_Y] = "YTilt", [ABS_TOOL_WIDTH] = "Tool Width", - [ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc", -}; +#ifdef CONFIG_HID_DEBUG -static char *misc[MSC_MAX + 1] = { - [MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled", - [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData" -}; +void hid_dump_input(struct hid_usage *, __s32); +void hid_dump_device(struct hid_device *); +void hid_dump_field(struct hid_field *, int); +void hid_resolv_usage(unsigned); +void hid_resolv_event(__u8, __u16); -static char *leds[LED_MAX + 1] = { - [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock", - [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose", - [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", - [LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute", - [LED_MISC] = "Misc", -}; +#else -static char *repeats[REP_MAX + 1] = { - [REP_DELAY] = "Delay", [REP_PERIOD] = "Period" -}; +#define hid_dump_input(a,b) do { } while (0) +#define hid_dump_device(c) do { } while (0) +#define hid_dump_field(a,b) do { } while (0) +#define hid_resolv_usage(a) do { } while (0) +#define hid_resolv_event(a,b) do { } while (0) -static char *sounds[SND_MAX + 1] = { - [SND_CLICK] = "Click", [SND_BELL] = "Bell", - [SND_TONE] = "Tone" -}; +#endif /* CONFIG_HID_DEBUG */ -static char **names[EV_MAX + 1] = { - [EV_SYN] = syncs, [EV_KEY] = keys, - [EV_REL] = relatives, [EV_ABS] = absolutes, - [EV_MSC] = misc, [EV_LED] = leds, - [EV_SND] = sounds, [EV_REP] = repeats, -}; -static void __attribute__((unused)) resolv_event(__u8 type, __u16 code) { +#endif - printk("%s.%s", events[type] ? events[type] : "?", - names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); -} diff --git a/include/linux/hid.h b/include/linux/hid.h index 18d0f2ce817f..189460e7b03f 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -472,16 +472,6 @@ struct hid_descriptor { struct hid_class_descriptor desc[1]; } __attribute__ ((packed)); -#ifdef DEBUG -#include "hid-debug.h" -#else -#define hid_dump_input(a,b) do { } while (0) -#define hid_dump_device(c) do { } while (0) -#define hid_dump_field(a,b) do { } while (0) -#define resolv_usage(a) do { } while (0) -#define resolv_event(a,b) do { } while (0) -#endif - /* Applications from HID Usage Tables 4/8/99 Version 1.1 */ /* We ignore a few input applications that are not widely used */ #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001)) -- cgit v1.2.3 From 7c379146005d277982acde02da44c773de5e7e5a Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 24 Jan 2007 11:54:19 +0100 Subject: HID: API - fix leftovers of hidinput API in USB HID hidinput_{open,close}() functions do not belong to usbhid, but to the generic HID layer. Move them, and fix hooks in struct hid_device, so that now the callbacks are done to transport-specific _open() functions, but not input_open() functions. Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 16 ++++++++++++++-- drivers/usb/input/hid-core.c | 16 ++-------------- include/linux/hid.h | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index ae298c4bfcbd..4824b19b8646 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -805,6 +805,18 @@ int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int } EXPORT_SYMBOL_GPL(hidinput_find_field); +static int hidinput_open(struct input_dev *dev) +{ + struct hid_device *hid = dev->private; + return hid->hid_open(hid); +} + +static void hidinput_close(struct input_dev *dev) +{ + struct hid_device *hid = dev->private; + hid->hid_close(hid); +} + /* * Register the input device; print a message. * Configure the input layer interface @@ -851,8 +863,8 @@ int hidinput_connect(struct hid_device *hid) input_dev->private = hid; input_dev->event = hid->hidinput_input_event; - input_dev->open = hid->hidinput_open; - input_dev->close = hid->hidinput_close; + input_dev->open = hidinput_open; + input_dev->close = hidinput_close; input_dev->name = hid->name; input_dev->phys = hid->phys; diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 6938c4e0e5e2..0392d0e8d020 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -529,18 +529,6 @@ void usbhid_close(struct hid_device *hid) usb_kill_urb(usbhid->urbin); } -static int hidinput_open(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - return usbhid_open(hid); -} - -static void hidinput_close(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - usbhid_close(hid); -} - #define USB_VENDOR_ID_PANJIT 0x134c #define USB_VENDOR_ID_TURBOX 0x062a @@ -1241,8 +1229,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma; usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); hid->hidinput_input_event = usb_hidinput_input_event; - hid->hidinput_open = hidinput_open; - hid->hidinput_close = hidinput_close; + hid->hid_open = usbhid_open; + hid->hid_close = usbhid_close; #ifdef CONFIG_USB_HIDDEV hid->hiddev_hid_event = hiddev_hid_event; hid->hiddev_report_event = hiddev_report_event; diff --git a/include/linux/hid.h b/include/linux/hid.h index 189460e7b03f..829690d8071e 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -431,8 +431,8 @@ struct hid_device { /* device report descriptor */ /* device-specific function pointers */ int (*hidinput_input_event) (struct input_dev *, unsigned int, unsigned int, int); - int (*hidinput_open) (struct input_dev *); - void (*hidinput_close) (struct input_dev *); + int (*hid_open) (struct hid_device *); + void (*hid_close) (struct hid_device *); /* hiddev event handler */ void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field, -- cgit v1.2.3 From a417a21e10831bca695b4ba9c74f4ddf5a95ac06 Mon Sep 17 00:00:00 2001 From: Soeren Sonnenburg Date: Mon, 5 Feb 2007 10:06:01 +0100 Subject: USB HID: handle multi-interface devices for Apple macbook pro properly Some HID devices by Apple have both keyboard and mouse interfaces; the keyboard interface is handled by usbhid, but the mouse (really touchpad) interface must be handled by the separate 'appletouch' driver. Using HID_QUIRK_IGNORE will make hiddev ignore both interfaces, therefore a new quirk flag to ignore only the mouse interface is required. Signed-off-by: Soeren Sonnenburg Signed-off-by: Sergey Vlasov Signed-off-by: Jiri Kosina --- drivers/usb/input/hid-core.c | 34 +++++++++++++++++++++------------- include/linux/hid.h | 1 + 2 files changed, 22 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 68b68a2b1022..e07a30490726 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -742,6 +742,7 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b +#define USB_DEVICE_ID_APPLE_IR 0x8240 #define USB_VENDOR_ID_CHERRY 0x046a #define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023 @@ -921,19 +922,21 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE }, @@ -1041,6 +1044,11 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) if (quirks & HID_QUIRK_IGNORE) return NULL; + if ((quirks & HID_QUIRK_IGNORE_MOUSE) && + (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)) + return NULL; + + if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && (!interface->desc.bNumEndpoints || usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { diff --git a/include/linux/hid.h b/include/linux/hid.h index 829690d8071e..93173fe45634 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -265,6 +265,7 @@ struct hid_item { #define HID_QUIRK_POWERBOOK_ISO_KEYBOARD 0x00008000 #define HID_QUIRK_BAD_RELATIVE_KEYS 0x00010000 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00020000 +#define HID_QUIRK_IGNORE_MOUSE 0x00040000 /* * This is the global environment of the parser. This information is -- cgit v1.2.3 From f5cd7872768d5856b1b409a33f516e5ac7798f75 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 31 Jan 2007 21:43:54 -0600 Subject: PA Semi PWRficient Ethernet driver Driver for the PA Semi PWRficient on-chip Ethernet (1/10G) Basic enablement, will be complemented with performance enhancements over time. PHY support will be added as well. Signed-off-by: Olof Johansson Signed-off-by: Jeff Garzik --- MAINTAINERS | 6 + drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/pasemi_mac.c | 1019 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/pasemi_mac.h | 460 +++++++++++++++++++++ include/linux/pci_ids.h | 2 + 6 files changed, 1495 insertions(+) create mode 100644 drivers/net/pasemi_mac.c create mode 100644 drivers/net/pasemi_mac.h (limited to 'include/linux') diff --git a/MAINTAINERS b/MAINTAINERS index 603066666f86..32581c2f859d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2477,6 +2477,12 @@ L: orinoco-devel@lists.sourceforge.net W: http://www.nongnu.org/orinoco/ S: Maintained +PA SEMI ETHERNET DRIVER +P: Olof Johansson +M: olof@lixom.net +L: netdev@vger.kernel.org +S: Maintained + PARALLEL PORT SUPPORT P: Phil Blundell M: philb@gnu.org diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8ffa82559116..a005517a4184 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2493,6 +2493,13 @@ config NETXEN_NIC help This enables the support for NetXen's Gigabit Ethernet card. +config PASEMI_MAC + tristate "PA Semi 1/10Gbit MAC" + depends on PPC64 && PCI + help + This driver supports the on-chip 1/10Gbit Ethernet controller on + PA Semi's PWRficient line of chips. + endmenu source "drivers/net/tokenring/Kconfig" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 9a86ebf9ab77..0878e3df5174 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -195,6 +195,7 @@ obj-$(CONFIG_SMC91X) += smc91x.o obj-$(CONFIG_SMC911X) += smc911x.o obj-$(CONFIG_DM9000) += dm9000.o obj-$(CONFIG_FEC_8XX) += fec_8xx/ +obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o obj-$(CONFIG_MACB) += macb.o diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c new file mode 100644 index 000000000000..d670ac74824f --- /dev/null +++ b/drivers/net/pasemi_mac.c @@ -0,0 +1,1019 @@ +/* + * Copyright (C) 2006-2007 PA Semi, Inc + * + * Driver for the PA Semi PWRficient onchip 1G/10G Ethernet MACs + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pasemi_mac.h" + + +/* 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 + */ + + +/* Must be a power of two */ +#define RX_RING_SIZE 512 +#define TX_RING_SIZE 512 + +#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 RX_BUFF(mac, num) ((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)]) + +#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ + +/* XXXOJN these should come out of the device tree some day */ +#define PAS_DMA_CAP_BASE 0xe00d0040 +#define PAS_DMA_CAP_SIZE 0x100 +#define PAS_DMA_COM_BASE 0xe00d0100 +#define PAS_DMA_COM_SIZE 0x100 + +static struct pasdma_status *dma_status; + +static int pasemi_get_mac_addr(struct pasemi_mac *mac) +{ + struct pci_dev *pdev = mac->pdev; + struct device_node *dn = pci_device_to_OF_node(pdev); + const u8 *maddr; + u8 addr[6]; + + if (!dn) { + dev_dbg(&pdev->dev, + "No device node for mac, not configuring\n"); + return -ENOENT; + } + + maddr = get_property(dn, "mac-address", NULL); + if (maddr == NULL) { + dev_warn(&pdev->dev, + "no mac address in device tree, not configuring\n"); + return -ENOENT; + } + + if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0], + &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) { + dev_warn(&pdev->dev, + "can't parse mac address, not configuring\n"); + return -EINVAL; + } + + memcpy(mac->mac_addr, addr, sizeof(addr)); + return 0; +} + +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; + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + + if (!ring) + goto out_ring; + + spin_lock_init(&ring->lock); + + ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) * + RX_RING_SIZE, GFP_KERNEL); + + if (!ring->desc_info) + goto out_desc_info; + + /* Allocate descriptors */ + ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev, + RX_RING_SIZE * + sizeof(struct pas_dma_xct_descr), + &ring->dma, GFP_KERNEL); + + if (!ring->desc) + goto out_desc; + + memset(ring->desc, 0, RX_RING_SIZE * sizeof(struct pas_dma_xct_descr)); + + ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev, + RX_RING_SIZE * sizeof(u64), + &ring->buf_dma, GFP_KERNEL); + if (!ring->buffers) + goto out_buffers; + + 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)); + + 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)); + + pci_write_config_dword(mac->dma_pdev, 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))); + + 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)); + + ring->next_to_fill = 0; + ring->next_to_clean = 0; + + snprintf(ring->irq_name, sizeof(ring->irq_name), + "%s rx", dev->name); + mac->rx = ring; + + return 0; + +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: + kfree(ring); +out_ring: + return -ENOMEM; +} + + +static int pasemi_mac_setup_tx_resources(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + u32 val; + int chan_id = mac->dma_txch; + struct pasemi_mac_txring *ring; + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + if (!ring) + goto out_ring; + + spin_lock_init(&ring->lock); + + ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) * + TX_RING_SIZE, GFP_KERNEL); + if (!ring->desc_info) + goto out_desc_info; + + /* Allocate descriptors */ + ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev, + TX_RING_SIZE * + sizeof(struct pas_dma_xct_descr), + &ring->dma, GFP_KERNEL); + if (!ring->desc) + goto out_desc; + + 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)); + 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); + + 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)); + + ring->next_to_use = 0; + ring->next_to_clean = 0; + + snprintf(ring->irq_name, sizeof(ring->irq_name), + "%s tx", dev->name); + mac->tx = ring; + + return 0; + +out_desc: + kfree(ring->desc_info); +out_desc_info: + kfree(ring); +out_ring: + return -ENOMEM; +} + +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; + } + } + + dma_free_coherent(&mac->dma_pdev->dev, + TX_RING_SIZE * sizeof(struct pas_dma_xct_descr), + mac->tx->desc, mac->tx->dma); + + kfree(mac->tx->desc_info); + kfree(mac->tx); + mac->tx = NULL; +} + +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->dma) { + if (info->skb) { + 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; + } + } + + dma_free_coherent(&mac->dma_pdev->dev, + RX_RING_SIZE * sizeof(struct pas_dma_xct_descr), + mac->rx->desc, 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); + mac->rx = NULL; +} + +static void pasemi_mac_replenish_rx_ring(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + unsigned int i; + int start = mac->rx->next_to_fill; + unsigned int count; + + count = (mac->rx->next_to_clean + RX_RING_SIZE - + mac->rx->next_to_fill) & (RX_RING_SIZE - 1); + + /* Check to see if we're doing first-time setup */ + if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0)) + count = RX_RING_SIZE; + + if (count <= 0) + return; + + for (i = start; i < start + count; i++) { + struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i); + u64 *buff = &RX_BUFF(mac, i); + struct sk_buff *skb; + dma_addr_t dma; + + skb = dev_alloc_skb(BUF_SIZE); + + if (!skb) { + count = i - start; + break; + } + + skb->dev = dev; + + dma = pci_map_single(mac->dma_pdev, skb->data, skb->len, + PCI_DMA_FROMDEVICE); + + if (dma_mapping_error(dma)) { + dev_kfree_skb_irq(info->skb); + count = i - start; + break; + } + + info->skb = skb; + info->dma = dma; + *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma); + } + + wmb(); + + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_RXCHAN_INCR(mac->dma_rxch), + count); + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_RXINT_INCR(mac->dma_if), + count); + + mac->rx->next_to_fill += count; +} + +static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) +{ + unsigned int i; + int start, count; + + spin_lock(&mac->rx->lock); + + start = mac->rx->next_to_clean; + count = 0; + + for (i = start; i < (start + RX_RING_SIZE) && count < limit; i++) { + struct pas_dma_xct_descr *dp; + struct pasemi_mac_buffer *info; + struct sk_buff *skb; + unsigned int j, len; + dma_addr_t dma; + + rmb(); + + dp = &RX_DESC(mac, i); + + if (!(dp->macrx & XCT_MACRX_O)) + break; + + count++; + + 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. + */ + + dma = (dp->ptr & XCT_PTR_ADDR_M); + for (j = start; j < (start + RX_RING_SIZE); j++) { + info = &RX_DESC_INFO(mac, j); + if (info->dma == dma) + break; + } + + BUG_ON(!info); + BUG_ON(info->dma != dma); + + pci_unmap_single(mac->dma_pdev, info->dma, info->skb->len, + PCI_DMA_FROMDEVICE); + + skb = info->skb; + + len = (dp->macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S; + + skb_put(skb, len); + + skb->protocol = eth_type_trans(skb, mac->netdev); + + if ((dp->macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) { + skb->ip_summed = CHECKSUM_COMPLETE; + skb->csum = (dp->macrx & XCT_MACRX_CSUM_M) >> + XCT_MACRX_CSUM_S; + } else + skb->ip_summed = CHECKSUM_NONE; + + mac->stats.rx_bytes += len; + mac->stats.rx_packets++; + + netif_receive_skb(skb); + + info->dma = 0; + info->skb = NULL; + dp->ptr = 0; + dp->macrx = 0; + } + + mac->rx->next_to_clean += count; + pasemi_mac_replenish_rx_ring(mac->netdev); + + spin_unlock(&mac->rx->lock); + + return count; +} + +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; + int flags; + + spin_lock_irqsave(&mac->tx->lock, flags); + + start = mac->tx->next_to_clean; + count = 0; + + for (i = start; i < mac->tx->next_to_use; i++) { + dp = &TX_DESC(mac, i); + if (!dp || (dp->mactx & XCT_MACTX_O)) + 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); + + info->skb = NULL; + info->dma = 0; + dp->mactx = 0; + dp->ptr = 0; + } + mac->tx->next_to_clean += count; + spin_unlock_irqrestore(&mac->tx->lock, flags); + + return count; +} + + +static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) +{ + struct net_device *dev = data; + struct pasemi_mac *mac = netdev_priv(dev); + unsigned int reg; + + if (!(*mac->rx_status & PAS_STATUS_INT)) + return IRQ_NONE; + + netif_rx_schedule(dev); + pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, + PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0)); + + reg = PAS_IOB_DMA_RXCH_RESET_PINTC | PAS_IOB_DMA_RXCH_RESET_SINTC | + PAS_IOB_DMA_RXCH_RESET_DINTC; + if (*mac->rx_status & PAS_STATUS_TIMER) + reg |= PAS_IOB_DMA_RXCH_RESET_TINTC; + + pci_write_config_dword(mac->iob_pdev, + PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); + + + return IRQ_HANDLED; +} + +static irqreturn_t pasemi_mac_tx_intr(int irq, void *data) +{ + struct net_device *dev = data; + struct pasemi_mac *mac = netdev_priv(dev); + unsigned int reg; + int was_full; + + was_full = mac->tx->next_to_clean - mac->tx->next_to_use == TX_RING_SIZE; + + if (!(*mac->tx_status & PAS_STATUS_INT)) + return IRQ_NONE; + + pasemi_mac_clean_tx(mac); + + reg = PAS_IOB_DMA_TXCH_RESET_PINTC | PAS_IOB_DMA_TXCH_RESET_SINTC; + if (*mac->tx_status & PAS_STATUS_TIMER) + reg |= PAS_IOB_DMA_TXCH_RESET_TINTC; + + pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), + reg); + + if (was_full) + netif_wake_queue(dev); + + return IRQ_HANDLED; +} + +static int pasemi_mac_open(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + unsigned int flags; + int ret; + + /* enable rx section */ + pci_write_config_dword(mac->dma_pdev, 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); + + 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); + + 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(30)); + + pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, + PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000)); + + pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags); + + ret = pasemi_mac_setup_rx_resources(dev); + if (ret) + goto out_rx_resources; + + ret = pasemi_mac_setup_tx_resources(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)); + + /* enable rx if */ + pci_write_config_dword(mac->dma_pdev, + 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); + + /* enable tx channel */ + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), + PAS_DMA_TXCHAN_TCMDSTA_EN); + + pasemi_mac_replenish_rx_ring(dev); + + netif_start_queue(dev); + netif_poll_enable(dev); + + ret = request_irq(mac->dma_pdev->irq + mac->dma_txch, + &pasemi_mac_tx_intr, IRQF_DISABLED, + mac->tx->irq_name, dev); + if (ret) { + dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", + mac->dma_pdev->irq + mac->dma_txch, ret); + goto out_tx_int; + } + + ret = request_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, + &pasemi_mac_rx_intr, IRQF_DISABLED, + mac->rx->irq_name, dev); + if (ret) { + dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", + mac->dma_pdev->irq + 20 + mac->dma_rxch, ret); + goto out_rx_int; + } + + return 0; + +out_rx_int: + free_irq(mac->dma_pdev->irq + mac->dma_txch, dev); +out_tx_int: + netif_poll_disable(dev); + netif_stop_queue(dev); + pasemi_mac_free_tx_resources(dev); +out_tx_resources: + pasemi_mac_free_rx_resources(dev); +out_rx_resources: + + return ret; +} + +#define MAX_RETRIES 5000 + +static int pasemi_mac_close(struct net_device *dev) +{ + struct pasemi_mac *mac = netdev_priv(dev); + unsigned int stat; + int retries; + + netif_stop_queue(dev); + + /* Clean out any pending buffers */ + pasemi_mac_clean_tx(mac); + 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); + + for (retries = 0; retries < MAX_RETRIES; retries++) { + pci_read_config_dword(mac->dma_pdev, + PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), + &stat); + if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT) + break; + cond_resched(); + } + + if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) { + 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); + if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT) + break; + cond_resched(); + } + + if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) { + 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); + if (stat & PAS_DMA_RXINT_RCMDSTA_ACT) + break; + cond_resched(); + } + + if (!(stat & 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 + * 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); + + free_irq(mac->dma_pdev->irq + mac->dma_txch, dev); + free_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, dev); + + /* Free resources */ + pasemi_mac_free_rx_resources(dev); + pasemi_mac_free_tx_resources(dev); + + return 0; +} + +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; + dma_addr_t map; + int flags; + + dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD; + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + switch (skb->nh.iph->protocol) { + case IPPROTO_TCP: + dflags |= XCT_MACTX_CSUM_TCP; + dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2); + dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data); + break; + case IPPROTO_UDP: + dflags |= XCT_MACTX_CSUM_UDP; + dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2); + dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data); + break; + } + } + + map = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + + if (dma_mapping_error(map)) + return NETDEV_TX_BUSY; + + txring = mac->tx; + + spin_lock_irqsave(&txring->lock, flags); + + if (txring->next_to_clean - txring->next_to_use == TX_RING_SIZE) { + spin_unlock_irqrestore(&txring->lock, flags); + pasemi_mac_clean_tx(mac); + spin_lock_irqsave(&txring->lock, flags); + + if (txring->next_to_clean - txring->next_to_use == + TX_RING_SIZE) { + /* Still no room -- stop the queue and wait for tx + * intr when there's room. + */ + netif_stop_queue(dev); + goto out_err; + } + } + + + 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); + info->dma = map; + info->skb = skb; + + txring->next_to_use++; + mac->stats.tx_packets++; + mac->stats.tx_bytes += skb->len; + + spin_unlock_irqrestore(&txring->lock, flags); + + pci_write_config_dword(mac->dma_pdev, + PAS_DMA_TXCHAN_INCR(mac->dma_txch), 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); + 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); + unsigned int flags; + + pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags); + + /* Set promiscuous */ + if (dev->flags & IFF_PROMISC) + flags |= PAS_MAC_CFG_PCFG_PR; + else + flags &= ~PAS_MAC_CFG_PCFG_PR; + + pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags); +} + + +static int pasemi_mac_poll(struct net_device *dev, int *budget) +{ + int pkts, limit = min(*budget, dev->quota); + struct pasemi_mac *mac = netdev_priv(dev); + + pkts = pasemi_mac_clean_rx(mac, limit); + + if (pkts < limit) { + /* all done, no more packets present */ + netif_rx_complete(dev); + + /* re-enable receive interrupts */ + pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG, + PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000)); + return 0; + } else { + /* used up our quantum, so reschedule */ + dev->quota -= pkts; + *budget -= pkts; + return 1; + } +} + +static int __devinit +pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int index = 0; + struct net_device *dev; + struct pasemi_mac *mac; + int err; + + err = pci_enable_device(pdev); + if (err) + return err; + + dev = alloc_etherdev(sizeof(struct pasemi_mac)); + if (dev == NULL) { + dev_err(&pdev->dev, + "pasemi_mac: Could not allocate ethernet device.\n"); + err = -ENOMEM; + goto out_disable_device; + } + + SET_MODULE_OWNER(dev); + pci_set_drvdata(pdev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + mac = netdev_priv(dev); + + mac->pdev = pdev; + mac->netdev = dev; + mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL); + + 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; + + /* We probe GMAC before XAUI, but the DMA interfaces are + * in XAUI, GMAC order. + */ + if (index < 4) + mac->dma_if = index + 2; + else + mac->dma_if = index - 4; + index++; + + switch (pdev->device) { + case 0xa005: + mac->type = MAC_TYPE_GMAC; + break; + case 0xa006: + mac->type = MAC_TYPE_XAUI; + break; + default: + err = -ENODEV; + goto out; + } + + /* get mac addr from device tree */ + if (pasemi_get_mac_addr(mac) || !is_valid_ether_addr(mac->mac_addr)) { + err = -ENODEV; + goto out; + } + memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr)); + + 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; + 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. + */ + if (!dma_status) + /* XXXOJN This should come from the device tree */ + dma_status = __ioremap(0xfd800000, 0x1000, 0); + + mac->rx_status = &dma_status->rx_sta[mac->dma_rxch]; + mac->tx_status = &dma_status->tx_sta[mac->dma_txch]; + + err = register_netdev(dev); + + if (err) { + dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n", + err); + 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", + 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]); + + return err; + +out: + pci_dev_put(mac->iob_pdev); +out_put_dma_pdev: + pci_dev_put(mac->dma_pdev); +out_free_netdev: + free_netdev(dev); +out_disable_device: + pci_disable_device(pdev); + return err; + +} + +static void __devexit pasemi_mac_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct pasemi_mac *mac; + + if (!netdev) + return; + + mac = netdev_priv(netdev); + + unregister_netdev(netdev); + + pci_disable_device(pdev); + pci_dev_put(mac->dma_pdev); + pci_dev_put(mac->iob_pdev); + + pci_set_drvdata(pdev, NULL); + free_netdev(netdev); +} + +static struct pci_device_id pasemi_mac_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa005) }, + { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa006) }, +}; + +MODULE_DEVICE_TABLE(pci, pasemi_mac_pci_tbl); + +static struct pci_driver pasemi_mac_driver = { + .name = "pasemi_mac", + .id_table = pasemi_mac_pci_tbl, + .probe = pasemi_mac_probe, + .remove = __devexit_p(pasemi_mac_remove), +}; + +static void __exit pasemi_mac_cleanup_module(void) +{ + pci_unregister_driver(&pasemi_mac_driver); + __iounmap(dma_status); + dma_status = NULL; +} + +int pasemi_mac_init_module(void) +{ + return pci_register_driver(&pasemi_mac_driver); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR ("Olof Johansson "); +MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver"); + +module_init(pasemi_mac_init_module); +module_exit(pasemi_mac_cleanup_module); diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h new file mode 100644 index 000000000000..c3e37e46a18a --- /dev/null +++ b/drivers/net/pasemi_mac.h @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2006 PA Semi, Inc + * + * Driver for the PA6T-1682M onchip 1G/10G Ethernet MACs, soft state and + * hardware register layouts. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PASEMI_MAC_H +#define PASEMI_MAC_H + +#include +#include +#include + +struct pasemi_mac_txring { + spinlock_t lock; + struct pas_dma_xct_descr *desc; + dma_addr_t dma; + unsigned int size; + unsigned int next_to_use; + unsigned int next_to_clean; + struct pasemi_mac_buffer *desc_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 */ + 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; + char irq_name[10]; /* "eth%d rx" */ +}; + +struct pasemi_mac { + struct net_device *netdev; + struct pci_dev *pdev; + struct pci_dev *dma_pdev; + struct pci_dev *iob_pdev; + struct net_device_stats stats; + + /* Pointer to the cacheable per-channel status registers */ + u64 *rx_status; + u64 *tx_status; + + u8 type; +#define MAC_TYPE_GMAC 1 +#define MAC_TYPE_XAUI 2 + u32 dma_txch; + u32 dma_if; + u32 dma_rxch; + + u8 mac_addr[6]; + + struct timer_list rxtimer; + + struct pasemi_mac_txring *tx; + struct pasemi_mac_rxring *rx; +}; + +/* Software status descriptor (desc_info) */ +struct pasemi_mac_buffer { + struct sk_buff *skb; + dma_addr_t dma; +}; + + +/* status register layout in IOB region, at 0xfb800000 */ +struct pasdma_status { + u64 rx_sta[64]; + 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, + PAS_MAC_IPC_CHNL = 0x208, +}; + +/* MAC CFG register fields */ +#define PAS_MAC_CFG_PCFG_PE 0x80000000 +#define PAS_MAC_CFG_PCFG_CE 0x40000000 +#define PAS_MAC_CFG_PCFG_BU 0x20000000 +#define PAS_MAC_CFG_PCFG_TT 0x10000000 +#define PAS_MAC_CFG_PCFG_TSR_M 0x0c000000 +#define PAS_MAC_CFG_PCFG_TSR_10M 0x00000000 +#define PAS_MAC_CFG_PCFG_TSR_100M 0x04000000 +#define PAS_MAC_CFG_PCFG_TSR_1G 0x08000000 +#define PAS_MAC_CFG_PCFG_TSR_10G 0x0c000000 +#define PAS_MAC_CFG_PCFG_T24 0x02000000 +#define PAS_MAC_CFG_PCFG_PR 0x01000000 +#define PAS_MAC_CFG_PCFG_CRO_M 0x00ff0000 +#define PAS_MAC_CFG_PCFG_CRO_S 16 +#define PAS_MAC_CFG_PCFG_IPO_M 0x0000ff00 +#define PAS_MAC_CFG_PCFG_IPO_S 8 +#define PAS_MAC_CFG_PCFG_S1 0x00000080 +#define PAS_MAC_CFG_PCFG_IO_M 0x00000060 +#define PAS_MAC_CFG_PCFG_IO_MAC 0x00000000 +#define PAS_MAC_CFG_PCFG_IO_OFF 0x00000020 +#define PAS_MAC_CFG_PCFG_IO_IND_ETH 0x00000040 +#define PAS_MAC_CFG_PCFG_IO_IND_IP 0x00000060 +#define PAS_MAC_CFG_PCFG_LP 0x00000010 +#define PAS_MAC_CFG_PCFG_TS 0x00000008 +#define PAS_MAC_CFG_PCFG_HD 0x00000004 +#define PAS_MAC_CFG_PCFG_SPD_M 0x00000003 +#define PAS_MAC_CFG_PCFG_SPD_10M 0x00000000 +#define PAS_MAC_CFG_PCFG_SPD_100M 0x00000001 +#define PAS_MAC_CFG_PCFG_SPD_1G 0x00000002 +#define PAS_MAC_CFG_PCFG_SPD_10G 0x00000003 +#define PAS_MAC_CFG_TXP_FCF 0x01000000 +#define PAS_MAC_CFG_TXP_FCE 0x00800000 +#define PAS_MAC_CFG_TXP_FC 0x00400000 +#define PAS_MAC_CFG_TXP_FPC_M 0x00300000 +#define PAS_MAC_CFG_TXP_FPC_S 20 +#define PAS_MAC_CFG_TXP_FPC(x) (((x) << PAS_MAC_CFG_TXP_FPC_S) & \ + PAS_MAC_CFG_TXP_FPC_M) +#define PAS_MAC_CFG_TXP_RT 0x00080000 +#define PAS_MAC_CFG_TXP_BL 0x00040000 +#define PAS_MAC_CFG_TXP_SL_M 0x00030000 +#define PAS_MAC_CFG_TXP_SL_S 16 +#define PAS_MAC_CFG_TXP_SL(x) (((x) << PAS_MAC_CFG_TXP_SL_S) & \ + PAS_MAC_CFG_TXP_SL_M) +#define PAS_MAC_CFG_TXP_COB_M 0x0000f000 +#define PAS_MAC_CFG_TXP_COB_S 12 +#define PAS_MAC_CFG_TXP_COB(x) (((x) << PAS_MAC_CFG_TXP_COB_S) & \ + PAS_MAC_CFG_TXP_COB_M) +#define PAS_MAC_CFG_TXP_TIFT_M 0x00000f00 +#define PAS_MAC_CFG_TXP_TIFT_S 8 +#define PAS_MAC_CFG_TXP_TIFT(x) (((x) << PAS_MAC_CFG_TXP_TIFT_S) & \ + PAS_MAC_CFG_TXP_TIFT_M) +#define PAS_MAC_CFG_TXP_TIFG_M 0x000000ff +#define PAS_MAC_CFG_TXP_TIFG_S 0 +#define PAS_MAC_CFG_TXP_TIFG(x) (((x) << PAS_MAC_CFG_TXP_TIFG_S) & \ + PAS_MAC_CFG_TXP_TIFG_M) + +#define PAS_MAC_IPC_CHNL_DCHNO_M 0x003f0000 +#define PAS_MAC_IPC_CHNL_DCHNO_S 16 +#define PAS_MAC_IPC_CHNL_DCHNO(x) (((x) << PAS_MAC_IPC_CHNL_DCHNO_S) & \ + PAS_MAC_IPC_CHNL_DCHNO_M) +#define PAS_MAC_IPC_CHNL_BCH_M 0x0000003f +#define PAS_MAC_IPC_CHNL_BCH_S 0 +#define PAS_MAC_IPC_CHNL_BCH(x) (((x) << PAS_MAC_IPC_CHNL_BCH_S) & \ + PAS_MAC_IPC_CHNL_BCH_M) + +/* All these registers live in the PCI configuration space for the DMA PCI + * device. Use the normal PCI config access functions for them. + */ +enum { + PAS_DMA_COM_TXCMD = 0x100, /* Transmit Command Register */ + PAS_DMA_COM_TXSTA = 0x104, /* Transmit Status Register */ + PAS_DMA_COM_RXCMD = 0x108, /* Receive Command Register */ + PAS_DMA_COM_RXSTA = 0x10c, /* Receive Status Register */ +}; +#define PAS_DMA_COM_TXCMD_EN 0x00000001 /* enable */ +#define PAS_DMA_COM_TXSTA_ACT 0x00000001 /* active */ +#define PAS_DMA_COM_RXCMD_EN 0x00000001 /* enable */ +#define PAS_DMA_COM_RXSTA_ACT 0x00000001 /* active */ + + +/* Per-interface and per-channel registers */ +#define _PAS_DMA_RXINT_STRIDE 0x20 +#define PAS_DMA_RXINT_RCMDSTA(i) (0x200+(i)*_PAS_DMA_RXINT_STRIDE) +#define PAS_DMA_RXINT_RCMDSTA_EN 0x00000001 +#define PAS_DMA_RXINT_RCMDSTA_ST 0x00000002 +#define PAS_DMA_RXINT_RCMDSTA_OO 0x00000100 +#define PAS_DMA_RXINT_RCMDSTA_BP 0x00000200 +#define PAS_DMA_RXINT_RCMDSTA_DR 0x00000400 +#define PAS_DMA_RXINT_RCMDSTA_BT 0x00000800 +#define PAS_DMA_RXINT_RCMDSTA_TB 0x00001000 +#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_INCR(i) (0x210+(i)*_PAS_DMA_RXINT_STRIDE) +#define PAS_DMA_RXINT_INCR_INCR_M 0x0000ffff +#define PAS_DMA_RXINT_INCR_INCR_S 0 +#define PAS_DMA_RXINT_INCR_INCR(x) ((x) & 0x0000ffff) +#define PAS_DMA_RXINT_BASEL(i) (0x218+(i)*_PAS_DMA_RXINT_STRIDE) +#define PAS_DMA_RXINT_BASEL_BRBL(x) ((x) & ~0x3f) +#define PAS_DMA_RXINT_BASEU(i) (0x21c+(i)*_PAS_DMA_RXINT_STRIDE) +#define PAS_DMA_RXINT_BASEU_BRBH(x) ((x) & 0xfff) +#define PAS_DMA_RXINT_BASEU_SIZ_M 0x3fff0000 /* # of cache lines worth of buffer ring */ +#define PAS_DMA_RXINT_BASEU_SIZ_S 16 /* 0 = 16K */ +#define PAS_DMA_RXINT_BASEU_SIZ(x) (((x) << PAS_DMA_RXINT_BASEU_SIZ_S) & \ + PAS_DMA_RXINT_BASEU_SIZ_M) + + +#define _PAS_DMA_TXCHAN_STRIDE 0x20 /* Size per channel */ +#define _PAS_DMA_TXCHAN_TCMDSTA 0x300 /* Command / Status */ +#define _PAS_DMA_TXCHAN_CFG 0x304 /* Configuration */ +#define _PAS_DMA_TXCHAN_DSCRBU 0x308 /* Descriptor BU Allocation */ +#define _PAS_DMA_TXCHAN_INCR 0x310 /* Descriptor increment */ +#define _PAS_DMA_TXCHAN_CNT 0x314 /* Descriptor count/offset */ +#define _PAS_DMA_TXCHAN_BASEL 0x318 /* Descriptor ring base (low) */ +#define _PAS_DMA_TXCHAN_BASEU 0x31c /* (high) */ +#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE) +#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_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 +#define PAS_DMA_TXCHAN_CFG_TATTR_S 2 +#define PAS_DMA_TXCHAN_CFG_TATTR(x) (((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \ + PAS_DMA_TXCHAN_CFG_TATTR_M) +#define PAS_DMA_TXCHAN_CFG_WT_M 0x000001c0 +#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_UP 0x00004000 /* update tx descr when sent */ +#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 +#define PAS_DMA_TXCHAN_BASEL_BRBL_S 0 +#define PAS_DMA_TXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \ + PAS_DMA_TXCHAN_BASEL_BRBL_M) +#define PAS_DMA_TXCHAN_BASEU(c) (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE) +#define PAS_DMA_TXCHAN_BASEU_BRBH_M 0x00000fff +#define PAS_DMA_TXCHAN_BASEU_BRBH_S 0 +#define PAS_DMA_TXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \ + PAS_DMA_TXCHAN_BASEU_BRBH_M) +/* # of cache lines worth of buffer ring */ +#define PAS_DMA_TXCHAN_BASEU_SIZ_M 0x3fff0000 +#define PAS_DMA_TXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */ +#define PAS_DMA_TXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \ + PAS_DMA_TXCHAN_BASEU_SIZ_M) + +#define _PAS_DMA_RXCHAN_STRIDE 0x20 /* Size per channel */ +#define _PAS_DMA_RXCHAN_CCMDSTA 0x800 /* Command / Status */ +#define _PAS_DMA_RXCHAN_CFG 0x804 /* Configuration */ +#define _PAS_DMA_RXCHAN_INCR 0x810 /* Descriptor increment */ +#define _PAS_DMA_RXCHAN_CNT 0x814 /* Descriptor count/offset */ +#define _PAS_DMA_RXCHAN_BASEL 0x818 /* Descriptor ring base (low) */ +#define _PAS_DMA_RXCHAN_BASEU 0x81c /* (high) */ +#define PAS_DMA_RXCHAN_CCMDSTA(c) (0x800+(c)*_PAS_DMA_RXCHAN_STRIDE) +#define PAS_DMA_RXCHAN_CCMDSTA_EN 0x00000001 /* Enabled */ +#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_CFG(c) (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE) +#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) & \ + PAS_DMA_RXCHAN_CFG_HBU_M) +#define PAS_DMA_RXCHAN_INCR(c) (0x810+(c)*_PAS_DMA_RXCHAN_STRIDE) +#define PAS_DMA_RXCHAN_BASEL(c) (0x818+(c)*_PAS_DMA_RXCHAN_STRIDE) +#define PAS_DMA_RXCHAN_BASEL_BRBL_M 0xffffffc0 +#define PAS_DMA_RXCHAN_BASEL_BRBL_S 0 +#define PAS_DMA_RXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_RXCHAN_BASEL_BRBL_S) & \ + PAS_DMA_RXCHAN_BASEL_BRBL_M) +#define PAS_DMA_RXCHAN_BASEU(c) (0x81c+(c)*_PAS_DMA_RXCHAN_STRIDE) +#define PAS_DMA_RXCHAN_BASEU_BRBH_M 0x00000fff +#define PAS_DMA_RXCHAN_BASEU_BRBH_S 0 +#define PAS_DMA_RXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_RXCHAN_BASEU_BRBH_S) & \ + PAS_DMA_RXCHAN_BASEU_BRBH_M) +/* # of cache lines worth of buffer ring */ +#define PAS_DMA_RXCHAN_BASEU_SIZ_M 0x3fff0000 +#define PAS_DMA_RXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */ +#define PAS_DMA_RXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_RXCHAN_BASEU_SIZ_S) & \ + PAS_DMA_RXCHAN_BASEU_SIZ_M) + +#define PAS_STATUS_PCNT_M 0x000000000000ffffull +#define PAS_STATUS_PCNT_S 0 +#define PAS_STATUS_DCNT_M 0x00000000ffff0000ull +#define PAS_STATUS_DCNT_S 16 +#define PAS_STATUS_BPCNT_M 0x0000ffff00000000ull +#define PAS_STATUS_BPCNT_S 32 +#define PAS_STATUS_TIMER 0x1000000000000000ull +#define PAS_STATUS_ERROR 0x2000000000000000ull +#define PAS_STATUS_SOFT 0x4000000000000000ull +#define PAS_STATUS_INT 0x8000000000000000ull + +#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 +#define PAS_IOB_DMA_RXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \ + PAS_IOB_DMA_RXCH_CFG_CNTTH_M) +#define PAS_IOB_DMA_TXCH_CFG(i) (0x1200 + (i)*4) +#define PAS_IOB_DMA_TXCH_CFG_CNTTH_M 0x00000fff +#define PAS_IOB_DMA_TXCH_CFG_CNTTH_S 0 +#define PAS_IOB_DMA_TXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \ + PAS_IOB_DMA_TXCH_CFG_CNTTH_M) +#define PAS_IOB_DMA_RXCH_STAT(i) (0x1300 + (i)*4) +#define PAS_IOB_DMA_RXCH_STAT_INTGEN 0x00001000 +#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_M 0x00000fff +#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_S 0 +#define PAS_IOB_DMA_RXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\ + PAS_IOB_DMA_RXCH_STAT_CNTDEL_M) +#define PAS_IOB_DMA_TXCH_STAT(i) (0x1400 + (i)*4) +#define PAS_IOB_DMA_TXCH_STAT_INTGEN 0x00001000 +#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_M 0x00000fff +#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_S 0 +#define PAS_IOB_DMA_TXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\ + PAS_IOB_DMA_TXCH_STAT_CNTDEL_M) +#define PAS_IOB_DMA_RXCH_RESET(i) (0x1500 + (i)*4) +#define PAS_IOB_DMA_RXCH_RESET_PCNT_M 0xffff0000 +#define PAS_IOB_DMA_RXCH_RESET_PCNT_S 0 +#define PAS_IOB_DMA_RXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \ + PAS_IOB_DMA_RXCH_RESET_PCNT_M) +#define PAS_IOB_DMA_RXCH_RESET_PCNTRST 0x00000020 +#define PAS_IOB_DMA_RXCH_RESET_DCNTRST 0x00000010 +#define PAS_IOB_DMA_RXCH_RESET_TINTC 0x00000008 +#define PAS_IOB_DMA_RXCH_RESET_DINTC 0x00000004 +#define PAS_IOB_DMA_RXCH_RESET_SINTC 0x00000002 +#define PAS_IOB_DMA_RXCH_RESET_PINTC 0x00000001 +#define PAS_IOB_DMA_TXCH_RESET(i) (0x1600 + (i)*4) +#define PAS_IOB_DMA_TXCH_RESET_PCNT_M 0xffff0000 +#define PAS_IOB_DMA_TXCH_RESET_PCNT_S 0 +#define PAS_IOB_DMA_TXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \ + PAS_IOB_DMA_TXCH_RESET_PCNT_M) +#define PAS_IOB_DMA_TXCH_RESET_PCNTRST 0x00000020 +#define PAS_IOB_DMA_TXCH_RESET_DCNTRST 0x00000010 +#define PAS_IOB_DMA_TXCH_RESET_TINTC 0x00000008 +#define PAS_IOB_DMA_TXCH_RESET_DINTC 0x00000004 +#define PAS_IOB_DMA_TXCH_RESET_SINTC 0x00000002 +#define PAS_IOB_DMA_TXCH_RESET_PINTC 0x00000001 + +#define PAS_IOB_DMA_COM_TIMEOUTCFG 0x1700 +#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M 0x00ffffff +#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S 0 +#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x) (((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \ + PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M) + +/* Transmit descriptor fields */ +#define XCT_MACTX_T 0x8000000000000000ull +#define XCT_MACTX_ST 0x4000000000000000ull +#define XCT_MACTX_NORES 0x0000000000000000ull +#define XCT_MACTX_8BRES 0x1000000000000000ull +#define XCT_MACTX_24BRES 0x2000000000000000ull +#define XCT_MACTX_40BRES 0x3000000000000000ull +#define XCT_MACTX_I 0x0800000000000000ull +#define XCT_MACTX_O 0x0400000000000000ull +#define XCT_MACTX_E 0x0200000000000000ull +#define XCT_MACTX_VLAN_M 0x0180000000000000ull +#define XCT_MACTX_VLAN_NOP 0x0000000000000000ull +#define XCT_MACTX_VLAN_REMOVE 0x0080000000000000ull +#define XCT_MACTX_VLAN_INSERT 0x0100000000000000ull +#define XCT_MACTX_VLAN_REPLACE 0x0180000000000000ull +#define XCT_MACTX_CRC_M 0x0060000000000000ull +#define XCT_MACTX_CRC_NOP 0x0000000000000000ull +#define XCT_MACTX_CRC_INSERT 0x0020000000000000ull +#define XCT_MACTX_CRC_PAD 0x0040000000000000ull +#define XCT_MACTX_CRC_REPLACE 0x0060000000000000ull +#define XCT_MACTX_SS 0x0010000000000000ull +#define XCT_MACTX_LLEN_M 0x00007fff00000000ull +#define XCT_MACTX_LLEN_S 32ull +#define XCT_MACTX_LLEN(x) ((((long)(x)) << XCT_MACTX_LLEN_S) & \ + XCT_MACTX_LLEN_M) +#define XCT_MACTX_IPH_M 0x00000000f8000000ull +#define XCT_MACTX_IPH_S 27ull +#define XCT_MACTX_IPH(x) ((((long)(x)) << XCT_MACTX_IPH_S) & \ + XCT_MACTX_IPH_M) +#define XCT_MACTX_IPO_M 0x0000000007c00000ull +#define XCT_MACTX_IPO_S 22ull +#define XCT_MACTX_IPO(x) ((((long)(x)) << XCT_MACTX_IPO_S) & \ + XCT_MACTX_IPO_M) +#define XCT_MACTX_CSUM_M 0x0000000000000060ull +#define XCT_MACTX_CSUM_NOP 0x0000000000000000ull +#define XCT_MACTX_CSUM_TCP 0x0000000000000040ull +#define XCT_MACTX_CSUM_UDP 0x0000000000000060ull +#define XCT_MACTX_V6 0x0000000000000010ull +#define XCT_MACTX_C 0x0000000000000004ull +#define XCT_MACTX_AL2 0x0000000000000002ull + +/* 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_O 0x0400000000000000ull +#define XCT_MACRX_E 0x0200000000000000ull +#define XCT_MACRX_FF 0x0100000000000000ull +#define XCT_MACRX_PF 0x0080000000000000ull +#define XCT_MACRX_OB 0x0040000000000000ull +#define XCT_MACRX_OD 0x0020000000000000ull +#define XCT_MACRX_FS 0x0010000000000000ull +#define XCT_MACRX_NB_M 0x000fc00000000000ull +#define XCT_MACRX_NB_S 46ULL +#define XCT_MACRX_NB(x) ((((long)(x)) << XCT_MACRX_NB_S) & \ + XCT_MACRX_NB_M) +#define XCT_MACRX_LLEN_M 0x00003fff00000000ull +#define XCT_MACRX_LLEN_S 32ULL +#define XCT_MACRX_LLEN(x) ((((long)(x)) << XCT_MACRX_LLEN_S) & \ + XCT_MACRX_LLEN_M) +#define XCT_MACRX_CRC 0x0000000080000000ull +#define XCT_MACRX_LEN_M 0x0000000060000000ull +#define XCT_MACRX_LEN_TOOSHORT 0x0000000020000000ull +#define XCT_MACRX_LEN_BELOWMIN 0x0000000040000000ull +#define XCT_MACRX_LEN_TRUNC 0x0000000060000000ull +#define XCT_MACRX_CAST_M 0x0000000018000000ull +#define XCT_MACRX_CAST_UNI 0x0000000000000000ull +#define XCT_MACRX_CAST_MULTI 0x0000000008000000ull +#define XCT_MACRX_CAST_BROAD 0x0000000010000000ull +#define XCT_MACRX_CAST_PAUSE 0x0000000018000000ull +#define XCT_MACRX_VLC_M 0x0000000006000000ull +#define XCT_MACRX_FM 0x0000000001000000ull +#define XCT_MACRX_HTY_M 0x0000000000c00000ull +#define XCT_MACRX_HTY_IPV4_OK 0x0000000000000000ull +#define XCT_MACRX_HTY_IPV6 0x0000000000400000ull +#define XCT_MACRX_HTY_IPV4_BAD 0x0000000000800000ull +#define XCT_MACRX_HTY_NONIP 0x0000000000c00000ull +#define XCT_MACRX_IPP_M 0x00000000003f0000ull +#define XCT_MACRX_IPP_S 16 +#define XCT_MACRX_CSUM_M 0x000000000000ffffull +#define XCT_MACRX_CSUM_S 0 + +#define XCT_PTR_T 0x8000000000000000ull +#define XCT_PTR_LEN_M 0x7ffff00000000000ull +#define XCT_PTR_LEN_S 44 +#define XCT_PTR_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & \ + XCT_PTR_LEN_M) +#define XCT_PTR_ADDR_M 0x00000fffffffffffull +#define XCT_PTR_ADDR_S 0 +#define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \ + XCT_PTR_ADDR_M) + +/* Receive interface buffer fields */ +#define XCT_RXB_LEN_M 0x0ffff00000000000ull +#define XCT_RXB_LEN_S 44 +#define XCT_RXB_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & XCT_PTR_LEN_M) +#define XCT_RXB_ADDR_M 0x00000fffffffffffull +#define XCT_RXB_ADDR_S 0 +#define XCT_RXB_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & XCT_PTR_ADDR_M) + + +#endif /* PASEMI_MAC_H */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3d1d21035dec..7098961cc869 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2066,6 +2066,8 @@ #define PCI_VENDOR_ID_TDI 0x192E #define PCI_DEVICE_ID_TDI_EHCI 0x0101 +#define PCI_VENDOR_ID_PASEMI 0x1959 + #define PCI_VENDOR_ID_JMICRON 0x197B #define PCI_DEVICE_ID_JMICRON_JMB360 0x2360 #define PCI_DEVICE_ID_JMICRON_JMB361 0x2361 -- cgit v1.2.3 From f1ddcaf3393b7a3871809b97fae90fac841a1f39 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 27 Jan 2007 10:05:15 +1100 Subject: [CRYPTO] api: Remove deprecated interface This patch removes the old cipher interface and related code. Signed-off-by: Herbert Xu --- crypto/algapi.c | 2 +- crypto/api.c | 63 +----- crypto/cipher.c | 447 +----------------------------------------- crypto/compress.c | 5 - crypto/digest.c | 5 - crypto/internal.h | 26 +-- fs/ecryptfs/crypto.c | 4 +- fs/ecryptfs/ecryptfs_kernel.h | 1 - include/linux/crypto.h | 127 ------------ 9 files changed, 17 insertions(+), 663 deletions(-) (limited to 'include/linux') diff --git a/crypto/algapi.c b/crypto/algapi.c index c91530021e9c..69eb504721a4 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -396,7 +396,7 @@ struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn) return ERR_PTR(-EAGAIN); } - tfm = __crypto_alloc_tfm(alg, 0); + tfm = __crypto_alloc_tfm(alg); if (IS_ERR(tfm)) crypto_mod_put(alg); diff --git a/crypto/api.c b/crypto/api.c index 8c446871cd5b..8b80baec853a 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -212,25 +212,6 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) } EXPORT_SYMBOL_GPL(crypto_alg_mod_lookup); -static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) -{ - tfm->crt_flags = flags & CRYPTO_TFM_REQ_MASK; - flags &= ~CRYPTO_TFM_REQ_MASK; - - switch (crypto_tfm_alg_type(tfm)) { - case CRYPTO_ALG_TYPE_CIPHER: - return crypto_init_cipher_flags(tfm, flags); - - case CRYPTO_ALG_TYPE_DIGEST: - return crypto_init_digest_flags(tfm, flags); - - case CRYPTO_ALG_TYPE_COMPRESS: - return crypto_init_compress_flags(tfm, flags); - } - - return 0; -} - static int crypto_init_ops(struct crypto_tfm *tfm) { const struct crypto_type *type = tfm->__crt_alg->cra_type; @@ -285,7 +266,7 @@ static void crypto_exit_ops(struct crypto_tfm *tfm) } } -static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags) +static unsigned int crypto_ctxsize(struct crypto_alg *alg) { const struct crypto_type *type = alg->cra_type; unsigned int len; @@ -299,15 +280,15 @@ static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags) BUG(); case CRYPTO_ALG_TYPE_CIPHER: - len += crypto_cipher_ctxsize(alg, flags); + len += crypto_cipher_ctxsize(alg); break; case CRYPTO_ALG_TYPE_DIGEST: - len += crypto_digest_ctxsize(alg, flags); + len += crypto_digest_ctxsize(alg); break; case CRYPTO_ALG_TYPE_COMPRESS: - len += crypto_compress_ctxsize(alg, flags); + len += crypto_compress_ctxsize(alg); break; } @@ -322,23 +303,19 @@ void crypto_shoot_alg(struct crypto_alg *alg) } EXPORT_SYMBOL_GPL(crypto_shoot_alg); -struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags) +struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg) { struct crypto_tfm *tfm = NULL; unsigned int tfm_size; int err = -ENOMEM; - tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags); + tfm_size = sizeof(*tfm) + crypto_ctxsize(alg); tfm = kzalloc(tfm_size, GFP_KERNEL); if (tfm == NULL) goto out_err; tfm->__crt_alg = alg; - err = crypto_init_flags(tfm, flags); - if (err) - goto out_free_tfm; - err = crypto_init_ops(tfm); if (err) goto out_free_tfm; @@ -362,31 +339,6 @@ out: } EXPORT_SYMBOL_GPL(__crypto_alloc_tfm); -struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) -{ - struct crypto_tfm *tfm = NULL; - int err; - - do { - struct crypto_alg *alg; - - alg = crypto_alg_mod_lookup(name, 0, CRYPTO_ALG_ASYNC); - err = PTR_ERR(alg); - if (IS_ERR(alg)) - continue; - - tfm = __crypto_alloc_tfm(alg, flags); - err = 0; - if (IS_ERR(tfm)) { - crypto_mod_put(alg); - err = PTR_ERR(tfm); - tfm = NULL; - } - } while (err == -EAGAIN && !signal_pending(current)); - - return tfm; -} - /* * crypto_alloc_base - Locate algorithm and allocate transform * @alg_name: Name of algorithm @@ -420,7 +372,7 @@ struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask) goto err; } - tfm = __crypto_alloc_tfm(alg, 0); + tfm = __crypto_alloc_tfm(alg); if (!IS_ERR(tfm)) return tfm; @@ -466,7 +418,6 @@ void crypto_free_tfm(struct crypto_tfm *tfm) kfree(tfm); } -EXPORT_SYMBOL_GPL(crypto_alloc_tfm); EXPORT_SYMBOL_GPL(crypto_free_tfm); int crypto_has_alg(const char *name, u32 type, u32 mask) diff --git a/crypto/cipher.c b/crypto/cipher.c index 9e03701cfdcc..333aab2f0277 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -12,274 +12,13 @@ * any later version. * */ -#include + #include #include #include -#include -#include +#include #include -#include #include "internal.h" -#include "scatterwalk.h" - -struct cipher_alg_compat { - unsigned int cia_min_keysize; - unsigned int cia_max_keysize; - int (*cia_setkey)(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen); - void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); - void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); - - unsigned int (*cia_encrypt_ecb)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes); - unsigned int (*cia_decrypt_ecb)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes); - unsigned int (*cia_encrypt_cbc)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes); - unsigned int (*cia_decrypt_cbc)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes); -}; - -static inline void xor_64(u8 *a, const u8 *b) -{ - ((u32 *)a)[0] ^= ((u32 *)b)[0]; - ((u32 *)a)[1] ^= ((u32 *)b)[1]; -} - -static inline void xor_128(u8 *a, const u8 *b) -{ - ((u32 *)a)[0] ^= ((u32 *)b)[0]; - ((u32 *)a)[1] ^= ((u32 *)b)[1]; - ((u32 *)a)[2] ^= ((u32 *)b)[2]; - ((u32 *)a)[3] ^= ((u32 *)b)[3]; -} - -static unsigned int crypt_slow(const struct cipher_desc *desc, - struct scatter_walk *in, - struct scatter_walk *out, unsigned int bsize) -{ - unsigned long alignmask = crypto_tfm_alg_alignmask(desc->tfm); - u8 buffer[bsize * 2 + alignmask]; - u8 *src = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - u8 *dst = src + bsize; - - scatterwalk_copychunks(src, in, bsize, 0); - desc->prfn(desc, dst, src, bsize); - scatterwalk_copychunks(dst, out, bsize, 1); - - return bsize; -} - -static inline unsigned int crypt_fast(const struct cipher_desc *desc, - struct scatter_walk *in, - struct scatter_walk *out, - unsigned int nbytes, u8 *tmp) -{ - u8 *src, *dst; - u8 *real_src, *real_dst; - - real_src = scatterwalk_map(in, 0); - real_dst = scatterwalk_map(out, 1); - - src = real_src; - dst = scatterwalk_samebuf(in, out) ? src : real_dst; - - if (tmp) { - memcpy(tmp, src, nbytes); - src = tmp; - dst = tmp; - } - - nbytes = desc->prfn(desc, dst, src, nbytes); - - if (tmp) - memcpy(real_dst, tmp, nbytes); - - scatterwalk_unmap(real_src, 0); - scatterwalk_unmap(real_dst, 1); - - scatterwalk_advance(in, nbytes); - scatterwalk_advance(out, nbytes); - - return nbytes; -} - -/* - * Generic encrypt/decrypt wrapper for ciphers, handles operations across - * multiple page boundaries by using temporary blocks. In user context, - * the kernel is given a chance to schedule us once per page. - */ -static int crypt(const struct cipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct scatter_walk walk_in, walk_out; - struct crypto_tfm *tfm = desc->tfm; - const unsigned int bsize = crypto_tfm_alg_blocksize(tfm); - unsigned int alignmask = crypto_tfm_alg_alignmask(tfm); - unsigned long buffer = 0; - - if (!nbytes) - return 0; - - if (nbytes % bsize) { - tfm->crt_flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; - return -EINVAL; - } - - scatterwalk_start(&walk_in, src); - scatterwalk_start(&walk_out, dst); - - for(;;) { - unsigned int n = nbytes; - u8 *tmp = NULL; - - if (!scatterwalk_aligned(&walk_in, alignmask) || - !scatterwalk_aligned(&walk_out, alignmask)) { - if (!buffer) { - buffer = __get_free_page(GFP_ATOMIC); - if (!buffer) - n = 0; - } - tmp = (u8 *)buffer; - } - - n = scatterwalk_clamp(&walk_in, n); - n = scatterwalk_clamp(&walk_out, n); - - if (likely(n >= bsize)) - n = crypt_fast(desc, &walk_in, &walk_out, n, tmp); - else - n = crypt_slow(desc, &walk_in, &walk_out, bsize); - - nbytes -= n; - - scatterwalk_done(&walk_in, 0, nbytes); - scatterwalk_done(&walk_out, 1, nbytes); - - if (!nbytes) - break; - - crypto_yield(tfm->crt_flags); - } - - if (buffer) - free_page(buffer); - - return 0; -} - -static int crypt_iv_unaligned(struct cipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct crypto_tfm *tfm = desc->tfm; - unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); - u8 *iv = desc->info; - - if (unlikely(((unsigned long)iv & alignmask))) { - unsigned int ivsize = tfm->crt_cipher.cit_ivsize; - u8 buffer[ivsize + alignmask]; - u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - int err; - - desc->info = memcpy(tmp, iv, ivsize); - err = crypt(desc, dst, src, nbytes); - memcpy(iv, tmp, ivsize); - - return err; - } - - return crypt(desc, dst, src, nbytes); -} - -static unsigned int cbc_process_encrypt(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes) -{ - struct crypto_tfm *tfm = desc->tfm; - void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block; - int bsize = crypto_tfm_alg_blocksize(tfm); - - void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn; - u8 *iv = desc->info; - unsigned int done = 0; - - nbytes -= bsize; - - do { - xor(iv, src); - fn(tfm, dst, iv); - memcpy(iv, dst, bsize); - - src += bsize; - dst += bsize; - } while ((done += bsize) <= nbytes); - - return done; -} - -static unsigned int cbc_process_decrypt(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes) -{ - struct crypto_tfm *tfm = desc->tfm; - void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block; - int bsize = crypto_tfm_alg_blocksize(tfm); - unsigned long alignmask = crypto_tfm_alg_alignmask(desc->tfm); - - u8 stack[src == dst ? bsize + alignmask : 0]; - u8 *buf = (u8 *)ALIGN((unsigned long)stack, alignmask + 1); - u8 **dst_p = src == dst ? &buf : &dst; - - void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn; - u8 *iv = desc->info; - unsigned int done = 0; - - nbytes -= bsize; - - do { - u8 *tmp_dst = *dst_p; - - fn(tfm, tmp_dst, src); - xor(tmp_dst, iv); - memcpy(iv, src, bsize); - if (tmp_dst != dst) - memcpy(dst, tmp_dst, bsize); - - src += bsize; - dst += bsize; - } while ((done += bsize) <= nbytes); - - return done; -} - -static unsigned int ecb_process(const struct cipher_desc *desc, u8 *dst, - const u8 *src, unsigned int nbytes) -{ - struct crypto_tfm *tfm = desc->tfm; - int bsize = crypto_tfm_alg_blocksize(tfm); - void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = desc->crfn; - unsigned int done = 0; - - nbytes -= bsize; - - do { - fn(tfm, dst, src); - - src += bsize; - dst += bsize; - } while ((done += bsize) <= nbytes); - - return done; -} static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) { @@ -293,122 +32,6 @@ static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) return cia->cia_setkey(tfm, key, keylen); } -static int ecb_encrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_encrypt; - desc.prfn = cipher->cia_encrypt_ecb ?: ecb_process; - - return crypt(&desc, dst, src, nbytes); -} - -static int ecb_decrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_decrypt; - desc.prfn = cipher->cia_decrypt_ecb ?: ecb_process; - - return crypt(&desc, dst, src, nbytes); -} - -static int cbc_encrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_encrypt; - desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt; - desc.info = tfm->crt_cipher.cit_iv; - - return crypt(&desc, dst, src, nbytes); -} - -static int cbc_encrypt_iv(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, u8 *iv) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_encrypt; - desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt; - desc.info = iv; - - return crypt_iv_unaligned(&desc, dst, src, nbytes); -} - -static int cbc_decrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_decrypt; - desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt; - desc.info = tfm->crt_cipher.cit_iv; - - return crypt(&desc, dst, src, nbytes); -} - -static int cbc_decrypt_iv(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, u8 *iv) -{ - struct cipher_desc desc; - struct cipher_alg_compat *cipher = (void *)&tfm->__crt_alg->cra_cipher; - - desc.tfm = tfm; - desc.crfn = cipher->cia_decrypt; - desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt; - desc.info = iv; - - return crypt_iv_unaligned(&desc, dst, src, nbytes); -} - -static int nocrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - return -ENOSYS; -} - -static int nocrypt_iv(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, u8 *iv) -{ - return -ENOSYS; -} - -int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags) -{ - u32 mode = flags & CRYPTO_TFM_MODE_MASK; - tfm->crt_cipher.cit_mode = mode ? mode : CRYPTO_TFM_MODE_ECB; - return 0; -} - static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *, const u8 *), struct crypto_tfm *tfm, @@ -454,7 +77,6 @@ static void cipher_decrypt_unaligned(struct crypto_tfm *tfm, int crypto_init_cipher_ops(struct crypto_tfm *tfm) { - int ret = 0; struct cipher_tfm *ops = &tfm->crt_cipher; struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; @@ -464,70 +86,7 @@ int crypto_init_cipher_ops(struct crypto_tfm *tfm) ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ? cipher_decrypt_unaligned : cipher->cia_decrypt; - switch (tfm->crt_cipher.cit_mode) { - case CRYPTO_TFM_MODE_ECB: - ops->cit_encrypt = ecb_encrypt; - ops->cit_decrypt = ecb_decrypt; - ops->cit_encrypt_iv = nocrypt_iv; - ops->cit_decrypt_iv = nocrypt_iv; - break; - - case CRYPTO_TFM_MODE_CBC: - ops->cit_encrypt = cbc_encrypt; - ops->cit_decrypt = cbc_decrypt; - ops->cit_encrypt_iv = cbc_encrypt_iv; - ops->cit_decrypt_iv = cbc_decrypt_iv; - break; - - case CRYPTO_TFM_MODE_CFB: - ops->cit_encrypt = nocrypt; - ops->cit_decrypt = nocrypt; - ops->cit_encrypt_iv = nocrypt_iv; - ops->cit_decrypt_iv = nocrypt_iv; - break; - - case CRYPTO_TFM_MODE_CTR: - ops->cit_encrypt = nocrypt; - ops->cit_decrypt = nocrypt; - ops->cit_encrypt_iv = nocrypt_iv; - ops->cit_decrypt_iv = nocrypt_iv; - break; - - default: - BUG(); - } - - if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) { - unsigned long align; - unsigned long addr; - - switch (crypto_tfm_alg_blocksize(tfm)) { - case 8: - ops->cit_xor_block = xor_64; - break; - - case 16: - ops->cit_xor_block = xor_128; - break; - - default: - printk(KERN_WARNING "%s: block size %u not supported\n", - crypto_tfm_alg_name(tfm), - crypto_tfm_alg_blocksize(tfm)); - ret = -EINVAL; - goto out; - } - - ops->cit_ivsize = crypto_tfm_alg_blocksize(tfm); - align = crypto_tfm_alg_alignmask(tfm) + 1; - addr = (unsigned long)crypto_tfm_ctx(tfm); - addr = ALIGN(addr, align); - addr += ALIGN(tfm->__crt_alg->cra_ctxsize, align); - ops->cit_iv = (void *)addr; - } - -out: - return ret; + return 0; } void crypto_exit_cipher_ops(struct crypto_tfm *tfm) diff --git a/crypto/compress.c b/crypto/compress.c index eca182aa3380..0a6570048c1e 100644 --- a/crypto/compress.c +++ b/crypto/compress.c @@ -34,11 +34,6 @@ static int crypto_decompress(struct crypto_tfm *tfm, dlen); } -int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags) -{ - return flags ? -EINVAL : 0; -} - int crypto_init_compress_ops(struct crypto_tfm *tfm) { struct compress_tfm *ops = &tfm->crt_compress; diff --git a/crypto/digest.c b/crypto/digest.c index bc47af648cb1..1bf7414aeb9e 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -136,11 +136,6 @@ static int digest(struct hash_desc *desc, return final(desc, out); } -int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) -{ - return flags ? -EINVAL : 0; -} - int crypto_init_digest_ops(struct crypto_tfm *tfm) { struct hash_tfm *ops = &tfm->crt_hash; diff --git a/crypto/internal.h b/crypto/internal.h index 2da6ad4f3593..784a7745315f 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -83,8 +83,7 @@ static inline void crypto_exit_proc(void) { } #endif -static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg, - int flags) +static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg) { unsigned int len = alg->cra_ctxsize; @@ -96,23 +95,12 @@ static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg, return len; } -static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg, - int flags) +static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg) { - unsigned int len = alg->cra_ctxsize; - - switch (flags & CRYPTO_TFM_MODE_MASK) { - case CRYPTO_TFM_MODE_CBC: - len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1); - len += alg->cra_blocksize; - break; - } - - return len; + return alg->cra_ctxsize; } -static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg, - int flags) +static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg) { return alg->cra_ctxsize; } @@ -121,10 +109,6 @@ struct crypto_alg *crypto_mod_get(struct crypto_alg *alg); struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask); struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask); -int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags); -int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags); -int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags); - int crypto_init_digest_ops(struct crypto_tfm *tfm); int crypto_init_cipher_ops(struct crypto_tfm *tfm); int crypto_init_compress_ops(struct crypto_tfm *tfm); @@ -136,7 +120,7 @@ void crypto_exit_compress_ops(struct crypto_tfm *tfm); void crypto_larval_error(const char *name, u32 type, u32 mask); void crypto_shoot_alg(struct crypto_alg *alg); -struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags); +struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg); int crypto_register_instance(struct crypto_template *tmpl, struct crypto_instance *inst); diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 7196f50fe152..a86a55ccf874 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -828,9 +828,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) mutex_unlock(&crypt_stat->cs_tfm_mutex); goto out; } - crypto_blkcipher_set_flags(crypt_stat->tfm, - (ECRYPTFS_DEFAULT_CHAINING_MODE - | CRYPTO_TFM_REQ_WEAK_KEY)); + crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); mutex_unlock(&crypt_stat->cs_tfm_mutex); rc = 0; out: diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index afb64bdbe6ad..0f897109759b 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -176,7 +176,6 @@ ecryptfs_get_key_payload_data(struct key *key) #define ECRYPTFS_FILE_SIZE_BYTES 8 #define ECRYPTFS_DEFAULT_CIPHER "aes" #define ECRYPTFS_DEFAULT_KEY_BYTES 16 -#define ECRYPTFS_DEFAULT_CHAINING_MODE CRYPTO_TFM_MODE_CBC #define ECRYPTFS_DEFAULT_HASH "md5" #define ECRYPTFS_TAG_3_PACKET_TYPE 0x8C #define ECRYPTFS_TAG_11_PACKET_TYPE 0xED diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 4aa9046601da..95936a5e7c12 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -51,15 +51,9 @@ /* * Transform masks and values (for crt_flags). */ -#define CRYPTO_TFM_MODE_MASK 0x000000ff #define CRYPTO_TFM_REQ_MASK 0x000fff00 #define CRYPTO_TFM_RES_MASK 0xfff00000 -#define CRYPTO_TFM_MODE_ECB 0x00000001 -#define CRYPTO_TFM_MODE_CBC 0x00000002 -#define CRYPTO_TFM_MODE_CFB 0x00000004 -#define CRYPTO_TFM_MODE_CTR 0x00000008 - #define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100 #define CRYPTO_TFM_REQ_MAY_SLEEP 0x00000200 #define CRYPTO_TFM_RES_WEAK_KEY 0x00100000 @@ -71,12 +65,8 @@ /* * Miscellaneous stuff. */ -#define CRYPTO_UNSPEC 0 #define CRYPTO_MAX_ALG_NAME 64 -#define CRYPTO_DIR_ENCRYPT 1 -#define CRYPTO_DIR_DECRYPT 0 - /* * The macro CRYPTO_MINALIGN_ATTR (along with the void * type in the actual * declaration) is used to ensure that the crypto_tfm context structure is @@ -148,19 +138,6 @@ struct cipher_alg { unsigned int keylen); void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); - - unsigned int (*cia_encrypt_ecb)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes) __deprecated; - unsigned int (*cia_decrypt_ecb)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes) __deprecated; - unsigned int (*cia_encrypt_cbc)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes) __deprecated; - unsigned int (*cia_decrypt_cbc)(const struct cipher_desc *desc, - u8 *dst, const u8 *src, - unsigned int nbytes) __deprecated; }; struct digest_alg { @@ -243,11 +220,6 @@ int crypto_unregister_alg(struct crypto_alg *alg); #ifdef CONFIG_CRYPTO int crypto_has_alg(const char *name, u32 type, u32 mask); #else -static inline int crypto_alg_available(const char *name, u32 flags) -{ - return 0; -} - static inline int crypto_has_alg(const char *name, u32 type, u32 mask) { return 0; @@ -395,40 +367,11 @@ static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm) return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK; } -static unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm) - __deprecated; -static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm) -{ - BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); - return tfm->__crt_alg->cra_cipher.cia_min_keysize; -} - -static unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm) - __deprecated; -static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm) -{ - BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); - return tfm->__crt_alg->cra_cipher.cia_max_keysize; -} - -static unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm) __deprecated; -static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm) -{ - BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); - return tfm->crt_cipher.cit_ivsize; -} - static inline unsigned int crypto_tfm_alg_blocksize(struct crypto_tfm *tfm) { return tfm->__crt_alg->cra_blocksize; } -static inline unsigned int crypto_tfm_alg_digestsize(struct crypto_tfm *tfm) -{ - BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST); - return tfm->__crt_alg->cra_digest.dia_digestsize; -} - static inline unsigned int crypto_tfm_alg_alignmask(struct crypto_tfm *tfm) { return tfm->__crt_alg->cra_alignmask; @@ -809,76 +752,6 @@ static inline int crypto_hash_setkey(struct crypto_hash *hash, return crypto_hash_crt(hash)->setkey(hash, key, keylen); } -static int crypto_cipher_encrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) __deprecated; -static inline int crypto_cipher_encrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); - return tfm->crt_cipher.cit_encrypt(tfm, dst, src, nbytes); -} - -static int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, u8 *iv) __deprecated; -static inline int crypto_cipher_encrypt_iv(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, u8 *iv) -{ - BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); - return tfm->crt_cipher.cit_encrypt_iv(tfm, dst, src, nbytes, iv); -} - -static int crypto_cipher_decrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) __deprecated; -static inline int crypto_cipher_decrypt(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); - return tfm->crt_cipher.cit_decrypt(tfm, dst, src, nbytes); -} - -static int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, u8 *iv) __deprecated; -static inline int crypto_cipher_decrypt_iv(struct crypto_tfm *tfm, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes, u8 *iv) -{ - BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); - return tfm->crt_cipher.cit_decrypt_iv(tfm, dst, src, nbytes, iv); -} - -static void crypto_cipher_set_iv(struct crypto_tfm *tfm, - const u8 *src, unsigned int len) __deprecated; -static inline void crypto_cipher_set_iv(struct crypto_tfm *tfm, - const u8 *src, unsigned int len) -{ - BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); - memcpy(tfm->crt_cipher.cit_iv, src, len); -} - -static void crypto_cipher_get_iv(struct crypto_tfm *tfm, - u8 *dst, unsigned int len) __deprecated; -static inline void crypto_cipher_get_iv(struct crypto_tfm *tfm, - u8 *dst, unsigned int len) -{ - BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); - memcpy(dst, tfm->crt_cipher.cit_iv, len); -} - static inline struct crypto_comp *__crypto_comp_cast(struct crypto_tfm *tfm) { return (struct crypto_comp *)tfm; -- cgit v1.2.3 From 78a1fe4f242cbe6b4578e072b75e171b92745afa Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 24 Dec 2006 10:02:00 +1100 Subject: [CRYPTO] api: Use structs for cipher/compression Now that all cipher/compression users have switched over to the new allocation scheme, we can get rid of the compatility defines and use proper structs for them. Signed-off-by: Herbert Xu --- include/linux/crypto.h | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 95936a5e7c12..779aa78ee643 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -311,13 +311,18 @@ struct crypto_tfm { void *__crt_ctx[] CRYPTO_MINALIGN_ATTR; }; -#define crypto_cipher crypto_tfm -#define crypto_comp crypto_tfm - struct crypto_blkcipher { struct crypto_tfm base; }; +struct crypto_cipher { + struct crypto_tfm base; +}; + +struct crypto_comp { + struct crypto_tfm base; +}; + struct crypto_hash { struct crypto_tfm base; }; @@ -576,7 +581,7 @@ static inline struct crypto_cipher *crypto_alloc_cipher(const char *alg_name, static inline struct crypto_tfm *crypto_cipher_tfm(struct crypto_cipher *tfm) { - return tfm; + return &tfm->base; } static inline void crypto_free_cipher(struct crypto_cipher *tfm) @@ -776,7 +781,7 @@ static inline struct crypto_comp *crypto_alloc_comp(const char *alg_name, static inline struct crypto_tfm *crypto_comp_tfm(struct crypto_comp *tfm) { - return tfm; + return &tfm->base; } static inline void crypto_free_comp(struct crypto_comp *tfm) @@ -807,14 +812,16 @@ static inline int crypto_comp_compress(struct crypto_comp *tfm, const u8 *src, unsigned int slen, u8 *dst, unsigned int *dlen) { - return crypto_comp_crt(tfm)->cot_compress(tfm, src, slen, dst, dlen); + return crypto_comp_crt(tfm)->cot_compress(crypto_comp_tfm(tfm), + src, slen, dst, dlen); } static inline int crypto_comp_decompress(struct crypto_comp *tfm, const u8 *src, unsigned int slen, u8 *dst, unsigned int *dlen) { - return crypto_comp_crt(tfm)->cot_decompress(tfm, src, slen, dst, dlen); + return crypto_comp_crt(tfm)->cot_decompress(crypto_comp_tfm(tfm), + src, slen, dst, dlen); } #endif /* _LINUX_CRYPTO_H */ -- cgit v1.2.3 From 390fbd1bfaa7b561af8e4f385067c55bdf4100ba Mon Sep 17 00:00:00 2001 From: Noriaki TAKAMIYA Date: Sun, 22 Oct 2006 15:02:48 +1000 Subject: [IPSEC]: added the definition of Camellia cipher This patch adds the definitions used by pfkeyv2 interface for Camellia cipher algorithm. Signed-off-by: Noriaki TAKAMIYA Signed-off-by: Herbert Xu --- include/linux/pfkeyv2.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index 265bafab6494..52ed4a56f672 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h @@ -297,6 +297,7 @@ struct sadb_x_sec_ctx { #define SADB_X_EALG_BLOWFISHCBC 7 #define SADB_EALG_NULL 11 #define SADB_X_EALG_AESCBC 12 +#define SADB_X_EALG_CAMELLIACBC 22 #define SADB_EALG_MAX 253 /* last EALG */ /* private allocations should use 249-255 (RFC2407) */ #define SADB_X_EALG_SERPENTCBC 252 /* draft-ietf-ipsec-ciph-aes-cbc-00 */ -- cgit v1.2.3 From 7583b6e424ebaa278342f6a8c2a61211af56dad1 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Sun, 28 Jan 2007 21:24:57 -0600 Subject: [POWERPC] Introduce _SYSDEV_ATTR Introduce _SYSDEV_ATTR(), to be used to just define the struct, and not a named variable with the attribute. Useful for arrays of sysdev_attributes. Signed-off-by: Olof Johansson Signed-off-by: Greg Kroah-Hartman Signed-off-by: Paul Mackerras --- include/linux/sysdev.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h index 166a2e58c287..389ccf858d37 100644 --- a/include/linux/sysdev.h +++ b/include/linux/sysdev.h @@ -98,12 +98,16 @@ struct sysdev_attribute { }; -#define SYSDEV_ATTR(_name,_mode,_show,_store) \ -struct sysdev_attribute attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode }, \ +#define _SYSDEV_ATTR(_name,_mode,_show,_store) \ +{ \ + .attr = { .name = __stringify(_name), .mode = _mode, \ + .owner = THIS_MODULE }, \ .show = _show, \ .store = _store, \ -}; +} + +#define SYSDEV_ATTR(_name,_mode,_show,_store) \ +struct sysdev_attribute attr_##_name = _SYSDEV_ATTR(_name,_mode,_show,_store); extern int sysdev_create_file(struct sys_device *, struct sysdev_attribute *); extern void sysdev_remove_file(struct sys_device *, struct sysdev_attribute *); -- cgit v1.2.3 From 63c2f782e8f6aafbc11b14b2cb291b3dc9fc217d Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Tue, 30 Jan 2007 06:06:00 -0500 Subject: [POWERPC] Add "is_power_of_2" checking to log2.h. Add the inline function "is_power_of_2()" to log2.h, where the value zero is *not* considered to be a power of two. Signed-off-by: Robert P. J. Day Acked-by: Kumar Gala Signed-off-by: Paul Mackerras --- arch/powerpc/mm/pgtable_32.c | 5 +---- arch/ppc/mm/pgtable.c | 5 +---- arch/ppc/syslib/ppc85xx_rio.c | 2 -- drivers/net/gianfar_ethtool.c | 2 -- include/linux/log2.h | 11 +++++++++++ 5 files changed, 13 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 1891dbeeb8e9..bd02272bcb0f 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -294,11 +294,8 @@ void __init mapin_ram(void) } } -/* is x a power of 2? */ -#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) - /* is x a power of 4? */ -#define is_power_of_4(x) ((x) != 0 && (((x) & (x-1)) == 0) && (ffs(x) & 1)) +#define is_power_of_4(x) is_power_of_2(x) && (ffs(x) & 1)) /* * Set up a mapping for a block of I/O. diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c index 354a9408f024..82b06a1ef95d 100644 --- a/arch/ppc/mm/pgtable.c +++ b/arch/ppc/mm/pgtable.c @@ -313,11 +313,8 @@ void __init mapin_ram(void) } } -/* is x a power of 2? */ -#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) - /* is x a power of 4? */ -#define is_power_of_4(x) ((x) != 0 && (((x) & (x-1)) == 0) && (ffs(x) & 1)) +#define is_power_of_4(x) is_power_of_2(x) && (ffs(x) & 1)) /* * Set up a mapping for a block of I/O. diff --git a/arch/ppc/syslib/ppc85xx_rio.c b/arch/ppc/syslib/ppc85xx_rio.c index 05b0e9415085..2b097800cdd9 100644 --- a/arch/ppc/syslib/ppc85xx_rio.c +++ b/arch/ppc/syslib/ppc85xx_rio.c @@ -59,8 +59,6 @@ #define DBELL_TID(x) (*(u8 *)(x + DOORBELL_TID_OFFSET)) #define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET)) -#define is_power_of_2(x) (((x) & ((x) - 1)) == 0) - struct rio_atmu_regs { u32 rowtar; u32 pad1; diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 6d71bea5e900..0d6943d67096 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -42,8 +42,6 @@ #include "gianfar.h" -#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) - extern void gfar_start(struct net_device *dev); extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); diff --git a/include/linux/log2.h b/include/linux/log2.h index d02e1a547a7e..99922bedfcc9 100644 --- a/include/linux/log2.h +++ b/include/linux/log2.h @@ -43,6 +43,17 @@ int __ilog2_u64(u64 n) } #endif +/* + * Determine whether some value is a power of two, where zero is + * *not* considered a power of two. + */ + +static inline __attribute__((const)) +bool is_power_of_2(unsigned long n) +{ + return (n != 0 && ((n & (n - 1)) == 0)); +} + /* * round up to nearest power of two */ -- cgit v1.2.3 From 33dced2ea5ed03dda10e7f9f41f0910f32e02eaa Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 7 Feb 2007 18:18:45 +0100 Subject: ide: add Toshiba TC86C001 IDE driver (take 2) This is the driver for the Toshiba TC86C001 GOKU-S PCI IDE controller, completely reworked from the original brain-damaged Toshiba's 2.4 version. This single channel UltraDMA/66 controller is very simple in programming, yet Toshiba managed to plant many interesting bugs in it. The particularly nasty "limitation 5" (as they call the errata) caused me to abuse the IDE core in a possibly most interesting way so far. However, this is still better than the #ifdef mess in drivers/ide/ide-io.c that the original version included (well, it had much more mess)... Signed-off-by: Sergei Shtylyov Acked-by: Alan Cox Cc: Greg KH Signed-off-by: Andrew Morton Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/Kconfig | 5 + drivers/ide/pci/Makefile | 1 + drivers/ide/pci/tc86c001.c | 308 +++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/quirks.c | 18 +++ include/linux/pci_ids.h | 1 + 5 files changed, 333 insertions(+) create mode 100644 drivers/ide/pci/tc86c001.c (limited to 'include/linux') diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 3f828052f8d2..4eb420891f9d 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -742,6 +742,11 @@ config BLK_DEV_VIA82CXXX This allows the kernel to change PIO, DMA and UDMA speeds and to configure the chip to optimum performance. +config BLK_DEV_TC86C001 + tristate "Toshiba TC86C001 support" + help + This driver adds support for Toshiba TC86C001 GOKU-S chip. + endif config BLK_DEV_IDE_PMAC diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile index fef08960aa4c..73f54dfb8c03 100644 --- a/drivers/ide/pci/Makefile +++ b/drivers/ide/pci/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o +obj-$(CONFIG_BLK_DEV_TC86C001) += tc86c001.o obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c new file mode 100644 index 000000000000..b6566534a31f --- /dev/null +++ b/drivers/ide/pci/tc86c001.c @@ -0,0 +1,308 @@ +/* + * drivers/ide/pci/tc86c001.c Version 1.00 Dec 12, 2006 + * + * Copyright (C) 2002 Toshiba Corporation + * Copyright (C) 2005-2006 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 + +static inline u8 tc86c001_ratemask(ide_drive_t *drive) +{ + return eighty_ninty_three(drive) ? 2 : 1; +} + +static int tc86c001_tune_chipset(ide_drive_t *drive, 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(tc86c001_ratemask(drive), speed); + + switch (speed) { + case XFER_UDMA_4: mode = 0x00c0; break; + case XFER_UDMA_3: mode = 0x00b0; break; + case XFER_UDMA_2: mode = 0x00a0; break; + case XFER_UDMA_1: mode = 0x0090; break; + case XFER_UDMA_0: mode = 0x0080; break; + case XFER_MW_DMA_2: mode = 0x0070; break; + case XFER_MW_DMA_1: mode = 0x0060; break; + case XFER_MW_DMA_0: mode = 0x0050; break; + case XFER_PIO_4: mode = 0x0400; break; + case XFER_PIO_3: mode = 0x0300; break; + case XFER_PIO_2: mode = 0x0200; break; + case XFER_PIO_1: mode = 0x0100; break; + case XFER_PIO_0: + default: mode = 0x0000; break; + } + + scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f; + scr |= mode; + hwif->OUTW(scr, scr_port); + + return ide_config_drive_speed(drive, speed); +} + +static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio) +{ + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + (void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio); +} + +/* + * HACKITY HACK + * + * This is a workaround for the limitation 5 of the TC86C001 IDE controller: + * if a DMA transfer terminates prematurely, the controller leaves the device's + * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or + * set the interrupt bit in the DMA status register), thus no PCI interrupt + * will occur until a DMA transfer has been successfully completed. + * + * We work around this by initiating dummy, zero-length DMA transfer on + * a DMA timeout expiration. I found no better way to do this with the current + * IDE core than to temporarily replace a higher level driver's timer expiry + * handler with our own backing up to that handler in case our recovery fails. + */ +static int tc86c001_timer_expiry(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + ide_expiry_t *expiry = ide_get_hwifdata(hwif); + ide_hwgroup_t *hwgroup = HWGROUP(drive); + u8 dma_stat = hwif->INB(hwif->dma_status); + + /* Restore a higher level driver's expiry handler first. */ + hwgroup->expiry = expiry; + + if ((dma_stat & 5) == 1) { /* DMA active and no interrupt */ + unsigned long sc_base = hwif->config_data; + unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04); + u8 dma_cmd = hwif->INB(hwif->dma_command); + + printk(KERN_WARNING "%s: DMA interrupt possibly stuck, " + "attempting recovery...\n", drive->name); + + /* Stop DMA */ + hwif->OUTB(dma_cmd & ~0x01, hwif->dma_command); + + /* Setup the dummy DMA transfer */ + hwif->OUTW(0, sc_base + 0x0a); /* Sector Count */ + hwif->OUTW(0, twcr_port); /* Transfer Word Count 1 or 2 */ + + /* Start the dummy DMA transfer */ + hwif->OUTB(0x00, hwif->dma_command); /* clear R_OR_WCTR for write */ + hwif->OUTB(0x01, hwif->dma_command); /* set START_STOPBM */ + + /* + * If an interrupt was pending, it should come thru shortly. + * If not, a higher level driver's expiry handler should + * eventually cause some kind of recovery from the DMA stall. + */ + return WAIT_MIN_SLEEP; + } + + /* Chain to the restored expiry handler if DMA wasn't active. */ + if (likely(expiry != NULL)) + return expiry(drive); + + /* If there was no handler, "emulate" that for ide_timer_expiry()... */ + return -1; +} + +static void tc86c001_dma_start(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + ide_hwgroup_t *hwgroup = HWGROUP(drive); + unsigned long sc_base = hwif->config_data; + unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04); + unsigned long nsectors = hwgroup->rq->nr_sectors; + + /* + * We have to manually load the sector count and size into + * the appropriate system control registers for DMA to work + * with LBA48 and ATAPI devices... + */ + hwif->OUTW(nsectors, sc_base + 0x0a); /* Sector Count */ + hwif->OUTW(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */ + + /* Install our timeout expiry hook, saving the current handler... */ + ide_set_hwifdata(hwif, hwgroup->expiry); + hwgroup->expiry = &tc86c001_timer_expiry; + + ide_dma_start(drive); +} + +static int tc86c001_busproc(ide_drive_t *drive, int state) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long sc_base = hwif->config_data; + u16 scr1; + + /* System Control 1 Register bit 11 (ATA Hard Reset) read */ + scr1 = hwif->INW(sc_base + 0x00); + + switch (state) { + case BUSSTATE_ON: + if (!(scr1 & 0x0800)) + return 0; + scr1 &= ~0x0800; + + hwif->drives[0].failures = hwif->drives[1].failures = 0; + break; + case BUSSTATE_OFF: + if (scr1 & 0x0800) + return 0; + scr1 |= 0x0800; + + hwif->drives[0].failures = hwif->drives[0].max_failures + 1; + hwif->drives[1].failures = hwif->drives[1].max_failures + 1; + break; + default: + return -EINVAL; + } + + /* System Control 1 Register bit 11 (ATA Hard Reset) write */ + hwif->OUTW(scr1, sc_base + 0x00); + return 0; +} + +static int config_chipset_for_dma(ide_drive_t *drive) +{ + u8 speed = ide_dma_speed(drive, tc86c001_ratemask(drive)); + + if (!speed) + return 0; + + (void) tc86c001_tune_chipset(drive, speed); + return ide_dma_enable(drive); +} + +static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct hd_driveid *id = drive->id; + + if ((id->capability & 1) && drive->autodma) { + + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return hwif->ide_dma_on(drive); + + goto fast_ata_pio; + + } else if ((id->capability & 8) || (id->field_valid & 2)) { +fast_ata_pio: + tc86c001_tune_drive(drive, 255); + return hwif->ide_dma_off_quietly(drive); + } + /* IORDY not supported */ + return 0; +} + +void __devinit init_hwif_tc86c001(ide_hwif_t *hwif) +{ + unsigned long sc_base = pci_resource_start(hwif->pci_dev, 5); + u16 scr1 = hwif->INW(sc_base + 0x00);; + + /* System Control 1 Register bit 15 (Soft Reset) set */ + hwif->OUTW(scr1 | 0x8000, sc_base + 0x00); + + /* System Control 1 Register bit 14 (FIFO Reset) set */ + hwif->OUTW(scr1 | 0x4000, sc_base + 0x00); + + /* System Control 1 Register: reset clear */ + hwif->OUTW(scr1 & ~0xc000, sc_base + 0x00); + + /* Store the system control register base for convenience... */ + hwif->config_data = sc_base; + + hwif->tuneproc = &tc86c001_tune_drive; + hwif->speedproc = &tc86c001_tune_chipset; + hwif->busproc = &tc86c001_busproc; + + hwif->drives[0].autotune = hwif->drives[1].autotune = 1; + + if (!hwif->dma_base) + return; + + /* + * Sector Count Control Register bits 0 and 1 set: + * software sets Sector Count Register for master and slave device + */ + hwif->OUTW(0x0003, sc_base + 0x0c); + + /* Sector Count Register limit */ + hwif->rqsize = 0xffff; + + hwif->atapi_dma = 1; + hwif->ultra_mask = 0x1f; + hwif->mwdma_mask = 0x07; + + hwif->ide_dma_check = &tc86c001_config_drive_xfer_rate; + hwif->dma_start = &tc86c001_dma_start; + + if (!hwif->udma_four) { + /* + * System Control 1 Register bit 13 (PDIAGN): + * 0=80-pin cable, 1=40-pin cable + */ + scr1 = hwif->INW(sc_base + 0x00); + hwif->udma_four = (scr1 & 0x2000) ? 0 : 1; + } + + if (!noautodma) + hwif->autodma = 1; + hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma; +} + +static unsigned int init_chipset_tc86c001(struct pci_dev *dev, const char *name) +{ + int err = pci_request_region(dev, 5, name); + + if (err) + printk(KERN_ERR "%s: system control regs already in use", name); + return err; +} + +static ide_pci_device_t tc86c001_chipset __devinitdata = { + .name = "TC86C001", + .init_chipset = init_chipset_tc86c001, + .init_hwif = init_hwif_tc86c001, + .channels = 1, + .autodma = AUTODMA, + .bootable = OFF_BOARD +}; + +static int __devinit tc86c001_init_one(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return ide_setup_pci_device(dev, &tc86c001_chipset); +} + +static struct pci_device_id tc86c001_pci_tbl[] = { + { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl); + +static struct pci_driver driver = { + .name = "TC86C001", + .id_table = tc86c001_pci_tbl, + .probe = tc86c001_init_one +}; + +static int tc86c001_ide_init(void) +{ + return ide_pci_register_driver(&driver); +} +module_init(tc86c001_ide_init); + +MODULE_AUTHOR("MontaVista Software, Inc. "); +MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index c913ea4e545c..40c1825c8b93 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1481,6 +1481,24 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2609, quirk_intel_pcie_pm); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm); +/* + * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size + * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes. + * Re-allocate the region if needed... + */ +static void __init quirk_tc86c001_ide(struct pci_dev *dev) +{ + struct resource *r = &dev->resource[0]; + + if (r->start & 0x8) { + r->start = 0; + r->end = 0xf; + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2, + PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE, + quirk_tc86c001_ide); + static void __devinit quirk_netmos(struct pci_dev *dev) { unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ccd706f876ec..b859faf5184d 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1454,6 +1454,7 @@ #define PCI_VENDOR_ID_TOSHIBA_2 0x102f #define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030 +#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE 0x0105 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108 #define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3 -- cgit v1.2.3 From e3a59b4d9378522479609042836ae930305a67fe Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 7 Feb 2007 18:19:37 +0100 Subject: ACPI support for IDE devices This patch implements ACPI integration for generic IDE devices. The ACPI spec mandates that some methods are called during suspend and resume. And consequently there most modern Laptops cannot resume properly without it. According to the spec, we should call '_GTM' (Get Timing) upon suspend to store the current IDE adapter settings. Upon resume we should call '_STM' (Set Timing) to initialize the adapter with the stored settings; afterwards '_GTF' (Get Taskfile) should be called which returns a buffer with some IDE initialisation commands. Those commands should be passed to the drive. There are two module params which control the behaviour of this patch: 'ide=noacpi' Do not call any ACPI methods (Disables any ACPI method calls) 'ide=acpigtf' Enable execution of _GTF methods upon resume. Has no effect if 'ide=noacpi' is set. 'ide=acpionboot' Enable execution of ACPI methods during boot. This might be required on some machines if 'ide=acpigtf' is selected as some machines modify the _GTF information depending on the drive identification passed down with _STM. Signed-off-by: Hannes Reinecke Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/Kconfig | 7 + drivers/ide/Makefile | 1 + drivers/ide/ide-acpi.c | 696 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/ide/ide-probe.c | 3 + drivers/ide/ide.c | 36 +++ include/linux/ide.h | 27 ++ 6 files changed, 770 insertions(+) create mode 100644 drivers/ide/ide-acpi.c (limited to 'include/linux') diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 0e511ca50b84..ec03341d2bd8 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -271,6 +271,13 @@ config BLK_DEV_IDESCSI If both this SCSI emulation and native ATAPI support are compiled into the kernel, the native support will be used. +config BLK_DEV_IDEACPI + bool "IDE ACPI support" + depends on ACPI + ---help--- + Implement ACPI support for generic IDE devices. On modern + machines ACPI support is required to properly handle ACPI S3 states. + config IDE_TASK_IOCTL bool "IDE Taskfile Access" help diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index 569fae717503..d9f029e8ff74 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -22,6 +22,7 @@ ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o ide-core-$(CONFIG_PROC_FS) += ide-proc.o ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o +ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o # built-in only drivers from arm/ ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c new file mode 100644 index 000000000000..1eb734951dc9 --- /dev/null +++ b/drivers/ide/ide-acpi.c @@ -0,0 +1,696 @@ +/* + * ide-acpi.c + * Provides ACPI support for IDE drives. + * + * Copyright (C) 2005 Intel Corp. + * Copyright (C) 2005 Randy Dunlap + * Copyright (C) 2006 SUSE Linux Products GmbH + * Copyright (C) 2006 Hannes Reinecke + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define REGS_PER_GTF 7 +struct taskfile_array { + u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ +}; + +struct GTM_buffer { + u32 PIO_speed0; + u32 DMA_speed0; + u32 PIO_speed1; + u32 DMA_speed1; + u32 GTM_flags; +}; + +struct ide_acpi_drive_link { + ide_drive_t *drive; + acpi_handle obj_handle; + u8 idbuff[512]; +}; + +struct ide_acpi_hwif_link { + ide_hwif_t *hwif; + acpi_handle obj_handle; + struct GTM_buffer gtm; + struct ide_acpi_drive_link master; + struct ide_acpi_drive_link slave; +}; + +#undef DEBUGGING +/* note: adds function name and KERN_DEBUG */ +#ifdef DEBUGGING +#define DEBPRINT(fmt, args...) \ + printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args) +#else +#define DEBPRINT(fmt, args...) do {} while (0) +#endif /* DEBUGGING */ + +extern int ide_noacpi; +extern int ide_noacpitfs; +extern int ide_noacpionboot; + +/** + * ide_get_dev_handle - finds acpi_handle and PCI device.function + * @dev: device to locate + * @handle: returned acpi_handle for @dev + * @pcidevfn: return PCI device.func for @dev + * + * Returns the ACPI object handle to the corresponding PCI device. + * + * Returns 0 on success, <0 on error. + */ +static int ide_get_dev_handle(struct device *dev, acpi_handle *handle, + acpi_integer *pcidevfn) +{ + struct pci_dev *pdev = to_pci_dev(dev); + unsigned int bus, devnum, func; + acpi_integer addr; + acpi_handle dev_handle; + struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER, + .pointer = NULL}; + acpi_status status; + struct acpi_device_info *dinfo = NULL; + int ret = -ENODEV; + + bus = pdev->bus->number; + devnum = PCI_SLOT(pdev->devfn); + func = PCI_FUNC(pdev->devfn); + /* ACPI _ADR encoding for PCI bus: */ + addr = (acpi_integer)(devnum << 16 | func); + + DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func); + + dev_handle = DEVICE_ACPI_HANDLE(dev); + if (!dev_handle) { + DEBPRINT("no acpi handle for device\n"); + goto err; + } + + status = acpi_get_object_info(dev_handle, &buffer); + if (ACPI_FAILURE(status)) { + DEBPRINT("get_object_info for device failed\n"); + goto err; + } + dinfo = buffer.pointer; + if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && + dinfo->address == addr) { + *pcidevfn = addr; + *handle = dev_handle; + } else { + DEBPRINT("get_object_info for device has wrong " + " address: %llu, should be %u\n", + dinfo ? (unsigned long long)dinfo->address : -1ULL, + (unsigned int)addr); + goto err; + } + + DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n", + devnum, func, (unsigned long long)addr, *handle); + ret = 0; +err: + kfree(dinfo); + return ret; +} + +/** + * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif + * @hwif: device to locate + * + * Retrieves the object handle for a given hwif. + * + * Returns handle on success, 0 on error. + */ +static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif) +{ + struct device *dev = hwif->gendev.parent; + acpi_handle dev_handle; + acpi_integer pcidevfn; + acpi_handle chan_handle; + int err; + + DEBPRINT("ENTER: device %s\n", hwif->name); + + if (!dev) { + DEBPRINT("no PCI device for %s\n", hwif->name); + return NULL; + } + + err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn); + if (err < 0) { + DEBPRINT("ide_get_dev_handle failed (%d)\n", err); + return NULL; + } + + /* get child objects of dev_handle == channel objects, + * + _their_ children == drive objects */ + /* channel is hwif->channel */ + chan_handle = acpi_get_child(dev_handle, hwif->channel); + DEBPRINT("chan adr=%d: handle=0x%p\n", + hwif->channel, chan_handle); + + return chan_handle; +} + +/** + * ide_acpi_drive_get_handle - Get ACPI object handle for a given drive + * @drive: device to locate + * + * Retrieves the object handle of a given drive. According to the ACPI + * spec the drive is a child of the hwif. + * + * Returns handle on success, 0 on error. + */ +static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + int port; + acpi_handle drive_handle; + + if (!hwif->acpidata) + return NULL; + + if (!hwif->acpidata->obj_handle) + return NULL; + + port = hwif->channel ? drive->dn - 2: drive->dn; + + DEBPRINT("ENTER: %s at channel#: %d port#: %d\n", + drive->name, hwif->channel, port); + + + /* TBD: could also check ACPI object VALID bits */ + drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port); + DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle); + + return drive_handle; +} + +/** + * do_drive_get_GTF - get the drive bootup default taskfile settings + * @drive: the drive for which the taskfile settings should be retrieved + * @gtf_length: number of bytes of _GTF data returned at @gtf_address + * @gtf_address: buffer containing _GTF taskfile arrays + * + * The _GTF method has no input parameters. + * It returns a variable number of register set values (registers + * hex 1F1..1F7, taskfiles). + * The is not known in advance, so have ACPI-CA + * allocate the buffer as needed and return it, then free it later. + * + * The returned @gtf_length and @gtf_address are only valid if the + * function return value is 0. + */ +static int do_drive_get_GTF(ide_drive_t *drive, + unsigned int *gtf_length, unsigned long *gtf_address, + unsigned long *obj_loc) +{ + acpi_status status; + struct acpi_buffer output; + union acpi_object *out_obj; + ide_hwif_t *hwif = HWIF(drive); + struct device *dev = hwif->gendev.parent; + int err = -ENODEV; + int port; + + *gtf_length = 0; + *gtf_address = 0UL; + *obj_loc = 0UL; + + if (ide_noacpi) + return 0; + + if (!dev) { + DEBPRINT("no PCI device for %s\n", hwif->name); + goto out; + } + + if (!hwif->acpidata) { + DEBPRINT("no ACPI data for %s\n", hwif->name); + goto out; + } + + port = hwif->channel ? drive->dn - 2: drive->dn; + + if (!drive->acpidata) { + if (port == 0) { + drive->acpidata = &hwif->acpidata->master; + hwif->acpidata->master.drive = drive; + } else { + drive->acpidata = &hwif->acpidata->slave; + hwif->acpidata->slave.drive = drive; + } + } + + DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n", + hwif->name, dev->bus_id, port, hwif->channel); + + if (!drive->present) { + DEBPRINT("%s drive %d:%d not present\n", + hwif->name, hwif->channel, port); + goto out; + } + + /* Get this drive's _ADR info. if not already known. */ + if (!drive->acpidata->obj_handle) { + drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive); + if (!drive->acpidata->obj_handle) { + DEBPRINT("No ACPI object found for %s\n", + drive->name); + goto out; + } + } + + /* Setting up output buffer */ + output.length = ACPI_ALLOCATE_BUFFER; + output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ + + /* _GTF has no input parameters */ + err = -EIO; + status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF", + NULL, &output); + if (ACPI_FAILURE(status)) { + printk(KERN_DEBUG + "%s: Run _GTF error: status = 0x%x\n", + __FUNCTION__, status); + goto out; + } + + if (!output.length || !output.pointer) { + DEBPRINT("Run _GTF: " + "length or ptr is NULL (0x%llx, 0x%p)\n", + (unsigned long long)output.length, + output.pointer); + goto out; + } + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) { + DEBPRINT("Run _GTF: error: " + "expected object type of ACPI_TYPE_BUFFER, " + "got 0x%x\n", out_obj->type); + err = -ENOENT; + kfree(output.pointer); + goto out; + } + + if (!out_obj->buffer.length || !out_obj->buffer.pointer || + out_obj->buffer.length % REGS_PER_GTF) { + printk(KERN_ERR + "%s: unexpected GTF length (%d) or addr (0x%p)\n", + __FUNCTION__, out_obj->buffer.length, + out_obj->buffer.pointer); + err = -ENOENT; + kfree(output.pointer); + goto out; + } + + *gtf_length = out_obj->buffer.length; + *gtf_address = (unsigned long)out_obj->buffer.pointer; + *obj_loc = (unsigned long)out_obj; + DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n", + *gtf_length, *gtf_address, *obj_loc); + err = 0; +out: + return err; +} + +/** + * taskfile_load_raw - send taskfile registers to drive + * @drive: drive to which output is sent + * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) + * + * Outputs IDE taskfile to the drive. + */ +static int taskfile_load_raw(ide_drive_t *drive, + const struct taskfile_array *gtf) +{ + ide_task_t args; + int err = 0; + + DEBPRINT("(0x1f1-1f7): hex: " + "%02x %02x %02x %02x %02x %02x %02x\n", + gtf->tfa[0], gtf->tfa[1], gtf->tfa[2], + gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]); + + memset(&args, 0, sizeof(ide_task_t)); + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.data_phase = TASKFILE_IN; + args.handler = &task_no_data_intr; + + /* convert gtf to IDE Taskfile */ + args.tfRegister[1] = gtf->tfa[0]; /* 0x1f1 */ + args.tfRegister[2] = gtf->tfa[1]; /* 0x1f2 */ + args.tfRegister[3] = gtf->tfa[2]; /* 0x1f3 */ + args.tfRegister[4] = gtf->tfa[3]; /* 0x1f4 */ + args.tfRegister[5] = gtf->tfa[4]; /* 0x1f5 */ + args.tfRegister[6] = gtf->tfa[5]; /* 0x1f6 */ + args.tfRegister[7] = gtf->tfa[6]; /* 0x1f7 */ + + if (ide_noacpitfs) { + DEBPRINT("_GTF execution disabled\n"); + return err; + } + + err = ide_raw_taskfile(drive, &args, NULL); + if (err) + printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n", + __FUNCTION__, err); + + return err; +} + +/** + * do_drive_set_taskfiles - write the drive taskfile settings from _GTF + * @drive: the drive to which the taskfile command should be sent + * @gtf_length: total number of bytes of _GTF taskfiles + * @gtf_address: location of _GTF taskfile arrays + * + * Write {gtf_address, length gtf_length} in groups of + * REGS_PER_GTF bytes. + */ +static int do_drive_set_taskfiles(ide_drive_t *drive, + unsigned int gtf_length, + unsigned long gtf_address) +{ + int rc = -ENODEV, err; + int gtf_count = gtf_length / REGS_PER_GTF; + int ix; + struct taskfile_array *gtf; + + if (ide_noacpi) + return 0; + + DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn); + + if (!drive->present) + goto out; + if (!gtf_count) /* shouldn't be here */ + goto out; + + DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n", + gtf_length, gtf_length, gtf_count, gtf_address); + + if (gtf_length % REGS_PER_GTF) { + printk(KERN_ERR "%s: unexpected GTF length (%d)\n", + __FUNCTION__, gtf_length); + goto out; + } + + rc = 0; + for (ix = 0; ix < gtf_count; ix++) { + gtf = (struct taskfile_array *) + (gtf_address + ix * REGS_PER_GTF); + + /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ + err = taskfile_load_raw(drive, gtf); + if (err) + rc = err; + } + +out: + return rc; +} + +/** + * ide_acpi_exec_tfs - get then write drive taskfile settings + * @drive: the drive for which the taskfile settings should be + * written. + * + * According to the ACPI spec this should be called after _STM + * has been evaluated for the interface. Some ACPI vendors interpret + * that as a hard requirement and modify the taskfile according + * to the Identify Drive information passed down with _STM. + * So one should really make sure to call this only after _STM has + * been executed. + */ +int ide_acpi_exec_tfs(ide_drive_t *drive) +{ + int ret; + unsigned int gtf_length; + unsigned long gtf_address; + unsigned long obj_loc; + + if (ide_noacpi) + return 0; + + DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn); + + ret = do_drive_get_GTF(drive, >f_length, >f_address, &obj_loc); + if (ret < 0) { + DEBPRINT("get_GTF error (%d)\n", ret); + return ret; + } + + DEBPRINT("call set_taskfiles, drive=%s\n", drive->name); + + ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address); + kfree((void *)obj_loc); + if (ret < 0) { + DEBPRINT("set_taskfiles error (%d)\n", ret); + } + + DEBPRINT("ret=%d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs); + +/** + * ide_acpi_get_timing - get the channel (controller) timings + * @hwif: target IDE interface (channel) + * + * This function executes the _GTM ACPI method for the target channel. + * + */ +void ide_acpi_get_timing(ide_hwif_t *hwif) +{ + acpi_status status; + struct acpi_buffer output; + union acpi_object *out_obj; + + if (ide_noacpi) + return; + + DEBPRINT("ENTER:\n"); + + if (!hwif->acpidata) { + DEBPRINT("no ACPI data for %s\n", hwif->name); + return; + } + + /* Setting up output buffer for _GTM */ + output.length = ACPI_ALLOCATE_BUFFER; + output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ + + /* _GTM has no input parameters */ + status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM", + NULL, &output); + + DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n", + status, output.pointer, + (unsigned long long)output.length); + + if (ACPI_FAILURE(status)) { + DEBPRINT("Run _GTM error: status = 0x%x\n", status); + return; + } + + if (!output.length || !output.pointer) { + DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n", + (unsigned long long)output.length, + output.pointer); + kfree(output.pointer); + return; + } + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) { + kfree(output.pointer); + DEBPRINT("Run _GTM: error: " + "expected object type of ACPI_TYPE_BUFFER, " + "got 0x%x\n", out_obj->type); + return; + } + + if (!out_obj->buffer.length || !out_obj->buffer.pointer || + out_obj->buffer.length != sizeof(struct GTM_buffer)) { + kfree(output.pointer); + printk(KERN_ERR + "%s: unexpected _GTM length (0x%x)[should be 0x%x] or addr (0x%p)\n", + __FUNCTION__, out_obj->buffer.length, + sizeof(struct GTM_buffer), out_obj->buffer.pointer); + return; + } + + memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer, + sizeof(struct GTM_buffer)); + + DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n", + out_obj->buffer.pointer, out_obj->buffer.length, + sizeof(struct GTM_buffer)); + + DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", + hwif->acpidata->gtm.PIO_speed0, + hwif->acpidata->gtm.DMA_speed0, + hwif->acpidata->gtm.PIO_speed1, + hwif->acpidata->gtm.DMA_speed1, + hwif->acpidata->gtm.GTM_flags); + + kfree(output.pointer); +} +EXPORT_SYMBOL_GPL(ide_acpi_get_timing); + +/** + * ide_acpi_push_timing - set the channel (controller) timings + * @hwif: target IDE interface (channel) + * + * This function executes the _STM ACPI method for the target channel. + * + * _STM requires Identify Drive data, which has to passed as an argument. + * Unfortunately hd_driveid is a mangled version which we can't readily + * use; hence we'll get the information afresh. + */ +void ide_acpi_push_timing(ide_hwif_t *hwif) +{ + acpi_status status; + struct acpi_object_list input; + union acpi_object in_params[3]; + struct ide_acpi_drive_link *master = &hwif->acpidata->master; + struct ide_acpi_drive_link *slave = &hwif->acpidata->slave; + + if (ide_noacpi) + return; + + DEBPRINT("ENTER:\n"); + + if (!hwif->acpidata) { + DEBPRINT("no ACPI data for %s\n", hwif->name); + return; + } + + /* Give the GTM buffer + drive Identify data to the channel via the + * _STM method: */ + /* setup input parameters buffer for _STM */ + input.count = 3; + input.pointer = in_params; + in_params[0].type = ACPI_TYPE_BUFFER; + in_params[0].buffer.length = sizeof(struct GTM_buffer); + in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm; + in_params[1].type = ACPI_TYPE_BUFFER; + in_params[1].buffer.length = sizeof(struct hd_driveid); + in_params[1].buffer.pointer = (u8 *)&master->idbuff; + in_params[2].type = ACPI_TYPE_BUFFER; + in_params[2].buffer.length = sizeof(struct hd_driveid); + in_params[2].buffer.pointer = (u8 *)&slave->idbuff; + /* Output buffer: _STM has no output */ + + status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM", + &input, NULL); + + if (ACPI_FAILURE(status)) { + DEBPRINT("Run _STM error: status = 0x%x\n", status); + } + DEBPRINT("_STM status: %d\n", status); +} +EXPORT_SYMBOL_GPL(ide_acpi_push_timing); + +/** + * ide_acpi_init - initialize the ACPI link for an IDE interface + * @hwif: target IDE interface (channel) + * + * The ACPI spec is not quite clear when the drive identify buffer + * should be obtained. Calling IDENTIFY DEVICE during shutdown + * is not the best of ideas as the drive might already being put to + * sleep. And obviously we can't call it during resume. + * So we get the information during startup; but this means that + * any changes during run-time will be lost after resume. + */ +void ide_acpi_init(ide_hwif_t *hwif) +{ + int unit; + int err; + struct ide_acpi_drive_link *master; + struct ide_acpi_drive_link *slave; + + hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL); + if (!hwif->acpidata) + return; + + hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif); + if (!hwif->acpidata->obj_handle) { + DEBPRINT("no ACPI object for %s found\n", hwif->name); + kfree(hwif->acpidata); + hwif->acpidata = NULL; + return; + } + + /* + * The ACPI spec mandates that we send information + * for both drives, regardless whether they are connected + * or not. + */ + hwif->acpidata->master.drive = &hwif->drives[0]; + hwif->drives[0].acpidata = &hwif->acpidata->master; + master = &hwif->acpidata->master; + + hwif->acpidata->slave.drive = &hwif->drives[1]; + hwif->drives[1].acpidata = &hwif->acpidata->slave; + slave = &hwif->acpidata->slave; + + + /* + * Send IDENTIFY for each drive + */ + if (master->drive->present) { + err = taskfile_lib_get_identify(master->drive, master->idbuff); + if (err) { + DEBPRINT("identify device %s failed (%d)\n", + master->drive->name, err); + } + } + + if (slave->drive->present) { + err = taskfile_lib_get_identify(slave->drive, slave->idbuff); + if (err) { + DEBPRINT("identify device %s failed (%d)\n", + slave->drive->name, err); + } + } + + if (ide_noacpionboot) { + DEBPRINT("ACPI methods disabled on boot\n"); + return; + } + + /* + * ACPI requires us to call _STM on startup + */ + ide_acpi_get_timing(hwif); + ide_acpi_push_timing(hwif); + + for (unit = 0; unit < MAX_DRIVES; ++unit) { + ide_drive_t *drive = &hwif->drives[unit]; + + if (drive->present) { + /* Execute ACPI startup code */ + ide_acpi_exec_tfs(drive); + } + } +} +EXPORT_SYMBOL_GPL(ide_acpi_init); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 5a5c565a32a8..176bbc850d6b 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1384,6 +1384,9 @@ static int hwif_init(ide_hwif_t *hwif) done: init_gendisk(hwif); + + ide_acpi_init(hwif); + hwif->present = 1; /* success */ return 1; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 6c9bd5165bdb..c750f6ce770a 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -187,6 +187,12 @@ int noautodma = 1; EXPORT_SYMBOL(noautodma); +#ifdef CONFIG_BLK_DEV_IDEACPI +int ide_noacpi = 0; +int ide_noacpitfs = 1; +int ide_noacpionboot = 1; +#endif + /* * This is declared extern in ide.h, for access by other IDE modules: */ @@ -1214,10 +1220,15 @@ EXPORT_SYMBOL(system_bus_clock); static int generic_ide_suspend(struct device *dev, pm_message_t mesg) { ide_drive_t *drive = dev->driver_data; + ide_hwif_t *hwif = HWIF(drive); struct request rq; struct request_pm_state rqpm; ide_task_t args; + /* Call ACPI _GTM only once */ + if (!(drive->dn % 2)) + ide_acpi_get_timing(hwif); + memset(&rq, 0, sizeof(rq)); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); @@ -1235,10 +1246,17 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) static int generic_ide_resume(struct device *dev) { ide_drive_t *drive = dev->driver_data; + ide_hwif_t *hwif = HWIF(drive); struct request rq; struct request_pm_state rqpm; ide_task_t args; + /* Call ACPI _STM only once */ + if (!(drive->dn % 2)) + ide_acpi_push_timing(hwif); + + ide_acpi_exec_tfs(drive); + memset(&rq, 0, sizeof(rq)); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); @@ -1543,6 +1561,24 @@ static int __init ide_setup(char *s) } #endif /* CONFIG_BLK_DEV_IDEPCI */ +#ifdef CONFIG_BLK_DEV_IDEACPI + if (!strcmp(s, "ide=noacpi")) { + //printk(" : Disable IDE ACPI support.\n"); + ide_noacpi = 1; + return 1; + } + if (!strcmp(s, "ide=acpigtf")) { + //printk(" : Enable IDE ACPI _GTF support.\n"); + ide_noacpitfs = 0; + return 1; + } + if (!strcmp(s, "ide=acpionboot")) { + //printk(" : Call IDE ACPI methods on boot.\n"); + ide_noacpionboot = 0; + return 1; + } +#endif /* CONFIG_BLK_DEV_IDEACPI */ + /* * Look for drive options: "hdx=" */ diff --git a/include/linux/ide.h b/include/linux/ide.h index e26a03981a94..ba1c92999f6e 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -18,6 +18,9 @@ #include #include #include +#ifdef CONFIG_BLK_DEV_IDEACPI +#include +#endif #include #include #include @@ -541,6 +544,11 @@ typedef enum { struct ide_driver_s; struct ide_settings_s; +#ifdef CONFIG_BLK_DEV_IDEACPI +struct ide_acpi_drive_link; +struct ide_acpi_hwif_link; +#endif + typedef struct ide_drive_s { char name[4]; /* drive name, such as "hda" */ char driver_req[10]; /* requests specific driver */ @@ -637,6 +645,9 @@ typedef struct ide_drive_s { int lun; /* logical unit */ int crc_count; /* crc counter to reduce drive speed */ +#ifdef CONFIG_BLK_DEV_IDEACPI + struct ide_acpi_drive_link *acpidata; +#endif struct list_head list; struct device gendev; struct completion gendev_rel_comp; /* to deal with device release() */ @@ -804,6 +815,10 @@ typedef struct hwif_s { void *hwif_data; /* extra hwif data */ unsigned dma; + +#ifdef CONFIG_BLK_DEV_IDEACPI + struct ide_acpi_hwif_link *acpidata; +#endif } ____cacheline_internodealigned_in_smp ide_hwif_t; /* @@ -1298,6 +1313,18 @@ static inline void ide_dma_verbose(ide_drive_t *drive) { ; } static inline void ide_release_dma(ide_hwif_t *drive) {;} #endif +#ifdef CONFIG_BLK_DEV_IDEACPI +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); +#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) { ; } +#endif + extern int ide_hwif_request_regions(ide_hwif_t *hwif); extern void ide_hwif_release_regions(ide_hwif_t* hwif); extern void ide_unregister (unsigned int index); -- cgit v1.2.3 From 2943ecf2ed32632473c06f1975db47a7aa98c10f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 22 Jan 2007 13:45:38 -0800 Subject: Driver core: convert SPI code to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Cc: Signed-off-by: Greg Kroah-Hartman --- drivers/spi/pxa2xx_spi.c | 2 +- drivers/spi/spi.c | 32 ++++++++++++++++---------------- drivers/spi/spi_bitbang.c | 6 +++--- drivers/spi/spi_butterfly.c | 4 ++-- include/linux/spi/spi.h | 10 +++++----- 5 files changed, 27 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 8b41f9cc2560..dccdc50b0296 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -1234,7 +1234,7 @@ static int init_queue(struct driver_data *drv_data) INIT_WORK(&drv_data->pump_messages, pump_messages); drv_data->workqueue = create_singlethread_workqueue( - drv_data->master->cdev.dev->bus_id); + drv_data->master->dev.parent->bus_id); if (drv_data->workqueue == NULL) return -EBUSY; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 6307428d2c94..35d8c01b42ac 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -193,7 +193,7 @@ struct spi_device *__init_or_module spi_new_device(struct spi_master *master, struct spi_board_info *chip) { struct spi_device *proxy; - struct device *dev = master->cdev.dev; + struct device *dev = &master->dev; int status; /* NOTE: caller did any chip->bus_num checks necessary */ @@ -215,7 +215,7 @@ spi_new_device(struct spi_master *master, struct spi_board_info *chip) proxy->modalias = chip->modalias; snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id, - "%s.%u", master->cdev.class_id, + "%s.%u", master->dev.bus_id, chip->chip_select); proxy->dev.parent = dev; proxy->dev.bus = &spi_bus_type; @@ -290,7 +290,7 @@ static void __init_or_module scan_boardinfo(struct spi_master *master) { struct boardinfo *bi; - struct device *dev = master->cdev.dev; + struct device *dev = master->dev.parent; down(&board_lock); list_for_each_entry(bi, &board_list, list) { @@ -319,18 +319,18 @@ scan_boardinfo(struct spi_master *master) /*-------------------------------------------------------------------------*/ -static void spi_master_release(struct class_device *cdev) +static void spi_master_release(struct device *dev) { struct spi_master *master; - master = container_of(cdev, struct spi_master, cdev); + master = container_of(dev, struct spi_master, dev); kfree(master); } static struct class spi_master_class = { .name = "spi_master", .owner = THIS_MODULE, - .release = spi_master_release, + .dev_release = spi_master_release, }; @@ -364,9 +364,9 @@ spi_alloc_master(struct device *dev, unsigned size) if (!master) return NULL; - class_device_initialize(&master->cdev); - master->cdev.class = &spi_master_class; - master->cdev.dev = get_device(dev); + device_initialize(&master->dev); + master->dev.class = &spi_master_class; + master->dev.parent = get_device(dev); spi_master_set_devdata(master, &master[1]); return master; @@ -396,7 +396,7 @@ int __init_or_module spi_register_master(struct spi_master *master) { static atomic_t dyn_bus_id = ATOMIC_INIT((1<<16) - 1); - struct device *dev = master->cdev.dev; + struct device *dev = master->dev.parent; int status = -ENODEV; int dynamic = 0; @@ -412,12 +412,12 @@ spi_register_master(struct spi_master *master) /* register the device, then userspace will see it. * registration fails if the bus ID is in use. */ - snprintf(master->cdev.class_id, sizeof master->cdev.class_id, + snprintf(master->dev.bus_id, sizeof master->dev.bus_id, "spi%u", master->bus_num); - status = class_device_add(&master->cdev); + status = device_add(&master->dev); if (status < 0) goto done; - dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id, + dev_dbg(dev, "registered master %s%s\n", master->dev.bus_id, dynamic ? " (dynamic)" : ""); /* populate children from any spi device tables */ @@ -449,8 +449,8 @@ void spi_unregister_master(struct spi_master *master) { int dummy; - dummy = device_for_each_child(master->cdev.dev, NULL, __unregister); - class_device_unregister(&master->cdev); + dummy = device_for_each_child(&master->dev, NULL, __unregister); + device_unregister(&master->dev); } EXPORT_SYMBOL_GPL(spi_unregister_master); @@ -471,7 +471,7 @@ struct spi_master *spi_busnum_to_master(u16 bus_num) down(&spi_master_class.sem); list_for_each_entry(cdev, &spi_master_class.children, node) { - m = container_of(cdev, struct spi_master, cdev); + m = container_of(cdev, struct spi_master, dev.kobj); if (m->bus_num == bus_num) { master = spi_master_get(m); break; diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 57289b61d0be..4638e6c83715 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -479,7 +479,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) /* this task is the only thing to touch the SPI bits */ bitbang->busy = 0; bitbang->workqueue = create_singlethread_workqueue( - bitbang->master->cdev.dev->bus_id); + bitbang->master->dev.parent->bus_id); if (bitbang->workqueue == NULL) { status = -EBUSY; goto err1; @@ -513,14 +513,14 @@ int spi_bitbang_stop(struct spi_bitbang *bitbang) while (!list_empty(&bitbang->queue) && limit--) { spin_unlock_irq(&bitbang->lock); - dev_dbg(bitbang->master->cdev.dev, "wait for queue\n"); + dev_dbg(&bitbang->master->dev, "wait for queue\n"); msleep(10); spin_lock_irq(&bitbang->lock); } spin_unlock_irq(&bitbang->lock); if (!list_empty(&bitbang->queue)) { - dev_err(bitbang->master->cdev.dev, "queue didn't empty\n"); + dev_err(&bitbang->master->dev, "queue didn't empty\n"); return -EBUSY; } diff --git a/drivers/spi/spi_butterfly.c b/drivers/spi/spi_butterfly.c index 312987a03210..31b7970ae463 100644 --- a/drivers/spi/spi_butterfly.c +++ b/drivers/spi/spi_butterfly.c @@ -246,7 +246,7 @@ static void butterfly_attach(struct parport *p) * and no way to be selective about what it binds to. */ - /* FIXME where should master->cdev.dev come from? + /* FIXME where should master->dev.parent come from? * e.g. /sys/bus/pnp0/00:0b, some PCI thing, etc * setting up a platform device like this is an ugly kluge... */ @@ -386,7 +386,7 @@ static void butterfly_detach(struct parport *p) butterfly = NULL; /* stop() unregisters child devices too */ - pdev = to_platform_device(pp->bitbang.master->cdev.dev); + pdev = to_platform_device(pp->bitbang.master->dev.parent); status = spi_bitbang_stop(&pp->bitbang); /* turn off VCC */ diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 176f6e36dbfa..8c2edd82a073 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -170,7 +170,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * message's completion function when the transaction completes. */ struct spi_master { - struct class_device cdev; + struct device dev; /* other than negative (== assign one dynamically), bus_num is fully * board-specific. usually that simplifies to being SOC-specific. @@ -216,17 +216,17 @@ struct spi_master { static inline void *spi_master_get_devdata(struct spi_master *master) { - return class_get_devdata(&master->cdev); + return dev_get_drvdata(&master->dev); } static inline void spi_master_set_devdata(struct spi_master *master, void *data) { - class_set_devdata(&master->cdev, data); + dev_set_drvdata(&master->dev, data); } static inline struct spi_master *spi_master_get(struct spi_master *master) { - if (!master || !class_device_get(&master->cdev)) + if (!master || !get_device(&master->dev)) return NULL; return master; } @@ -234,7 +234,7 @@ static inline struct spi_master *spi_master_get(struct spi_master *master) static inline void spi_master_put(struct spi_master *master) { if (master) - class_device_put(&master->cdev); + put_device(&master->dev); } -- cgit v1.2.3 From 43cb76d91ee85f579a69d42bc8efc08bac560278 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 9 Apr 2002 12:14:34 -0700 Subject: Network: convert network devices to use struct device instead of class_device This lets the network core have the ability to handle suspend/resume issues, if it wants to. Thanks to Frederik Deweerdt for the arm driver fixes. Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 33 ++-- drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 11 +- drivers/net/arm/at91_ether.c | 2 +- drivers/net/arm/etherh.c | 2 +- drivers/net/bonding/bond_sysfs.c | 287 ++++++++++++++++++------------ drivers/net/iseries_veth.c | 2 +- drivers/net/macb.c | 36 ++-- drivers/net/smc911x.c | 2 +- drivers/net/smc91x.c | 2 +- drivers/net/wireless/hostap/hostap_main.c | 2 +- drivers/net/wireless/orinoco.c | 4 +- drivers/net/wireless/orinoco_cs.c | 2 +- drivers/net/wireless/spectrum_cs.c | 2 +- include/linux/netdevice.h | 5 +- net/bridge/br_if.c | 2 +- net/bridge/br_sysfs_br.c | 234 +++++++++++++----------- net/bridge/br_sysfs_if.c | 2 +- net/core/dev.c | 6 +- net/core/net-sysfs.c | 175 +++++++++--------- net/core/skbuff.c | 2 +- 20 files changed, 451 insertions(+), 362 deletions(-) (limited to 'include/linux') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 705eb1d0e554..af5ee2ec4499 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -958,16 +958,17 @@ struct ipoib_dev_priv *ipoib_intf_alloc(const char *name) return netdev_priv(dev); } -static ssize_t show_pkey(struct class_device *cdev, char *buf) +static ssize_t show_pkey(struct device *dev, + struct device_attribute *attr, char *buf) { - struct ipoib_dev_priv *priv = - netdev_priv(container_of(cdev, struct net_device, class_dev)); + struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); return sprintf(buf, "0x%04x\n", priv->pkey); } -static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); +static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); -static ssize_t create_child(struct class_device *cdev, +static ssize_t create_child(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { int pkey; @@ -985,14 +986,14 @@ static ssize_t create_child(struct class_device *cdev, */ pkey |= 0x8000; - ret = ipoib_vlan_add(container_of(cdev, struct net_device, class_dev), - pkey); + ret = ipoib_vlan_add(to_net_dev(dev), pkey); return ret ? ret : count; } -static CLASS_DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child); +static DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child); -static ssize_t delete_child(struct class_device *cdev, +static ssize_t delete_child(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { int pkey; @@ -1004,18 +1005,16 @@ static ssize_t delete_child(struct class_device *cdev, if (pkey < 0 || pkey > 0xffff) return -EINVAL; - ret = ipoib_vlan_delete(container_of(cdev, struct net_device, class_dev), - pkey); + ret = ipoib_vlan_delete(to_net_dev(dev), pkey); return ret ? ret : count; } -static CLASS_DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child); +static DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child); int ipoib_add_pkey_attr(struct net_device *dev) { - return class_device_create_file(&dev->class_dev, - &class_device_attr_pkey); + return device_create_file(&dev->dev, &dev_attr_pkey); } static struct net_device *ipoib_add_port(const char *format, @@ -1083,11 +1082,9 @@ static struct net_device *ipoib_add_port(const char *format, if (ipoib_add_pkey_attr(priv->dev)) goto sysfs_failed; - if (class_device_create_file(&priv->dev->class_dev, - &class_device_attr_create_child)) + if (device_create_file(&priv->dev->dev, &dev_attr_create_child)) goto sysfs_failed; - if (class_device_create_file(&priv->dev->class_dev, - &class_device_attr_delete_child)) + if (device_create_file(&priv->dev->dev, &dev_attr_delete_child)) goto sysfs_failed; return priv->dev; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index f887780e8093..085eafe6667c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -42,15 +42,15 @@ #include "ipoib.h" -static ssize_t show_parent(struct class_device *class_dev, char *buf) +static ssize_t show_parent(struct device *d, struct device_attribute *attr, + char *buf) { - struct net_device *dev = - container_of(class_dev, struct net_device, class_dev); + struct net_device *dev = to_net_dev(d); struct ipoib_dev_priv *priv = netdev_priv(dev); return sprintf(buf, "%s\n", priv->parent->name); } -static CLASS_DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); +static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) { @@ -118,8 +118,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) if (ipoib_add_pkey_attr(priv->dev)) goto sysfs_failed; - if (class_device_create_file(&priv->dev->class_dev, - &class_device_attr_parent)) + if (device_create_file(&priv->dev->dev, &dev_attr_parent)) goto sysfs_failed; list_add_tail(&priv->list, &ppriv->child_intfs); diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index fada15d959de..1621b8fe35cf 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -641,7 +641,7 @@ static void at91ether_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo { strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); strlcpy(info->version, DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info)); + strlcpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); } static const struct ethtool_ops at91ether_ethtool_ops = { diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index f3faa4fe58e7..72c41f5907f2 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -587,7 +587,7 @@ static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i { strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); strlcpy(info->version, DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, dev->class_dev.dev->bus_id, + strlcpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index ced9ed8f995a..0e610aa1fdf9 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -39,8 +39,7 @@ /* #define BONDING_DEBUG 1 */ #include "bonding.h" -#define to_class_dev(obj) container_of(obj,struct class_device,kobj) -#define to_net_dev(class) container_of(class, struct net_device, class_dev) +#define to_dev(obj) container_of(obj,struct device,kobj) #define to_bond(cd) ((struct bonding *)(to_net_dev(cd)->priv)) /*---------------------------- Declarations -------------------------------*/ @@ -154,7 +153,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t * If it's > expected, then there's a file open, * and we have to fail. */ - if (atomic_read(&bond->dev->class_dev.kobj.kref.refcount) + if (atomic_read(&bond->dev->dev.kobj.kref.refcount) > expected_refcount){ rtnl_unlock(); printk(KERN_INFO DRV_NAME @@ -201,13 +200,13 @@ int bond_create_slave_symlinks(struct net_device *master, struct net_device *sla int ret = 0; /* first, create a link from the slave back to the master */ - ret = sysfs_create_link(&(slave->class_dev.kobj), &(master->class_dev.kobj), + ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj), "master"); if (ret) return ret; /* next, create a link from the master to the slave */ sprintf(linkname,"slave_%s",slave->name); - ret = sysfs_create_link(&(master->class_dev.kobj), &(slave->class_dev.kobj), + ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj), linkname); return ret; @@ -217,20 +216,21 @@ void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *s { char linkname[IFNAMSIZ+7]; - sysfs_remove_link(&(slave->class_dev.kobj), "master"); + sysfs_remove_link(&(slave->dev.kobj), "master"); sprintf(linkname,"slave_%s",slave->name); - sysfs_remove_link(&(master->class_dev.kobj), linkname); + sysfs_remove_link(&(master->dev.kobj), linkname); } /* * Show the slaves in the current bond. */ -static ssize_t bonding_show_slaves(struct class_device *cd, char *buf) +static ssize_t bonding_show_slaves(struct device *d, + struct device_attribute *attr, char *buf) { struct slave *slave; int i, res = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); read_lock_bh(&bond->lock); bond_for_each_slave(bond, slave, i) { @@ -254,14 +254,16 @@ static ssize_t bonding_show_slaves(struct class_device *cd, char *buf) * up for this to succeed. * This function is largely the same flow as bonding_update_bonds(). */ -static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, size_t count) +static ssize_t bonding_store_slaves(struct device *d, + struct device_attribute *attr, + const char *buffer, size_t count) { char command[IFNAMSIZ + 1] = { 0, }; char *ifname; int i, res, found, ret = count; struct slave *slave; struct net_device *dev = NULL; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); /* Quick sanity check -- is the bond interface up? */ if (!(bond->dev->flags & IFF_UP)) { @@ -387,25 +389,28 @@ out: return ret; } -static CLASS_DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves); +static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves); /* * Show and set the bonding mode. The bond interface must be down to * change the mode. */ -static ssize_t bonding_show_mode(struct class_device *cd, char *buf) +static ssize_t bonding_show_mode(struct device *d, + struct device_attribute *attr, char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%s %d\n", bond_mode_tbl[bond->params.mode].modename, bond->params.mode) + 1; } -static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_mode(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { printk(KERN_ERR DRV_NAME @@ -438,16 +443,18 @@ static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size out: return ret; } -static CLASS_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode); +static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode); /* * Show and set the bonding transmit hash method. The bond interface must be down to * change the xmit hash policy. */ -static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf) +static ssize_t bonding_show_xmit_hash(struct device *d, + struct device_attribute *attr, + char *buf) { int count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if ((bond->params.mode != BOND_MODE_XOR) && (bond->params.mode != BOND_MODE_8023AD)) { @@ -462,10 +469,12 @@ static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf) return count; } -static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_xmit_hash(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { printk(KERN_ERR DRV_NAME @@ -501,24 +510,28 @@ static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, out: return ret; } -static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash); +static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash); /* * Show and set arp_validate. */ -static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf) +static ssize_t bonding_show_arp_validate(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%s %d\n", arp_validate_tbl[bond->params.arp_validate].modename, bond->params.arp_validate) + 1; } -static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_arp_validate(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); new_value = bond_parse_parm((char *)buf, arp_validate_tbl); if (new_value < 0) { @@ -548,7 +561,7 @@ static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *b return count; } -static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); +static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); /* * Show and set the arp timer interval. There are two tricky bits @@ -556,17 +569,21 @@ static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_valid * MII monitoring. Second, if the ARP timer isn't running, we must * start it. */ -static ssize_t bonding_show_arp_interval(struct class_device *cd, char *buf) +static ssize_t bonding_show_arp_interval(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.arp_interval) + 1; } -static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_arp_interval(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { printk(KERN_ERR DRV_NAME @@ -638,15 +655,17 @@ static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *b out: return ret; } -static CLASS_DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval); +static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval); /* * Show and set the arp targets. */ -static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf) +static ssize_t bonding_show_arp_targets(struct device *d, + struct device_attribute *attr, + char *buf) { int i, res = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { if (bond->params.arp_targets[i]) @@ -660,11 +679,13 @@ static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf) return res; } -static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_arp_targets(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { u32 newtarget; int i = 0, done = 0, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); u32 *targets; targets = bond->params.arp_targets; @@ -742,24 +763,28 @@ static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *bu out: return ret; } -static CLASS_DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); +static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); /* * Show and set the up and down delays. These must be multiples of the * MII monitoring value, and are stored internally as the multiplier. * Thus, we must translate to MS for the real world. */ -static ssize_t bonding_show_downdelay(struct class_device *cd, char *buf) +static ssize_t bonding_show_downdelay(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon) + 1; } -static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_downdelay(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (!(bond->params.miimon)) { printk(KERN_ERR DRV_NAME @@ -800,20 +825,24 @@ static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf, out: return ret; } -static CLASS_DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay); +static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay); -static ssize_t bonding_show_updelay(struct class_device *cd, char *buf) +static ssize_t bonding_show_updelay(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon) + 1; } -static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_updelay(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (!(bond->params.miimon)) { printk(KERN_ERR DRV_NAME @@ -854,25 +883,29 @@ static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, s out: return ret; } -static CLASS_DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay); +static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay); /* * Show and set the LACP interval. Interface must be down, and the mode * must be set to 802.3ad mode. */ -static ssize_t bonding_show_lacp(struct class_device *cd, char *buf) +static ssize_t bonding_show_lacp(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%s %d\n", bond_lacp_tbl[bond->params.lacp_fast].modename, bond->params.lacp_fast) + 1; } -static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_lacp(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { printk(KERN_ERR DRV_NAME @@ -906,7 +939,7 @@ static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size out: return ret; } -static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); +static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); /* * Show and set the MII monitor interval. There are two tricky bits @@ -914,17 +947,21 @@ static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bondin * ARP monitoring. Second, if the timer isn't running, we must * start it. */ -static ssize_t bonding_show_miimon(struct class_device *cd, char *buf) +static ssize_t bonding_show_miimon(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.miimon) + 1; } -static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_miimon(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { printk(KERN_ERR DRV_NAME @@ -1000,7 +1037,7 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si out: return ret; } -static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon); +static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon); /* * Show and set the primary slave. The store function is much @@ -1009,10 +1046,12 @@ static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding * The bond must be a mode that supports a primary for this be * set. */ -static ssize_t bonding_show_primary(struct class_device *cd, char *buf) +static ssize_t bonding_show_primary(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->primary_slave) count = sprintf(buf, "%s\n", bond->primary_slave->dev->name) + 1; @@ -1022,11 +1061,13 @@ static ssize_t bonding_show_primary(struct class_device *cd, char *buf) return count; } -static ssize_t bonding_store_primary(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_primary(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int i; struct slave *slave; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); write_lock_bh(&bond->lock); if (!USES_PRIMARY(bond->params.mode)) { @@ -1065,22 +1106,26 @@ out: write_unlock_bh(&bond->lock); return count; } -static CLASS_DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary); +static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary); /* * Show and set the use_carrier flag. */ -static ssize_t bonding_show_carrier(struct class_device *cd, char *buf) +static ssize_t bonding_show_carrier(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.use_carrier) + 1; } -static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_carrier(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { @@ -1102,16 +1147,18 @@ static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, s out: return count; } -static CLASS_DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier); +static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier); /* * Show and set currently active_slave. */ -static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf) +static ssize_t bonding_show_active_slave(struct device *d, + struct device_attribute *attr, + char *buf) { struct slave *curr; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); int count; @@ -1126,13 +1173,15 @@ static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf) return count; } -static ssize_t bonding_store_active_slave(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_active_slave(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int i; struct slave *slave; struct slave *old_active = NULL; struct slave *new_active = NULL; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); write_lock_bh(&bond->lock); if (!USES_PRIMARY(bond->params.mode)) { @@ -1194,16 +1243,18 @@ out: return count; } -static CLASS_DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave); +static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave); /* * Show link status of the bond interface. */ -static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf) +static ssize_t bonding_show_mii_status(struct device *d, + struct device_attribute *attr, + char *buf) { struct slave *curr; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); read_lock(&bond->curr_slave_lock); curr = bond->curr_active_slave; @@ -1211,16 +1262,18 @@ static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", (curr) ? "up" : "down") + 1; } -static CLASS_DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); +static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); /* * Show current 802.3ad aggregator ID. */ -static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_aggregator(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1231,16 +1284,18 @@ static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf) return count; } -static CLASS_DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL); +static DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL); /* * Show number of active 802.3ad ports. */ -static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_num_ports(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1251,16 +1306,18 @@ static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf) return count; } -static CLASS_DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL); +static DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL); /* * Show current 802.3ad actor key. */ -static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_actor_key(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1271,16 +1328,18 @@ static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf) return count; } -static CLASS_DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL); +static DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL); /* * Show current 802.3ad partner key. */ -static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_partner_key(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1291,16 +1350,18 @@ static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf) return count; } -static CLASS_DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL); +static DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL); /* * Show current 802.3ad partner mac. */ -static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_partner_mac(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1319,30 +1380,30 @@ static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf) return count; } -static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL); +static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL); static struct attribute *per_bond_attrs[] = { - &class_device_attr_slaves.attr, - &class_device_attr_mode.attr, - &class_device_attr_arp_validate.attr, - &class_device_attr_arp_interval.attr, - &class_device_attr_arp_ip_target.attr, - &class_device_attr_downdelay.attr, - &class_device_attr_updelay.attr, - &class_device_attr_lacp_rate.attr, - &class_device_attr_xmit_hash_policy.attr, - &class_device_attr_miimon.attr, - &class_device_attr_primary.attr, - &class_device_attr_use_carrier.attr, - &class_device_attr_active_slave.attr, - &class_device_attr_mii_status.attr, - &class_device_attr_ad_aggregator.attr, - &class_device_attr_ad_num_ports.attr, - &class_device_attr_ad_actor_key.attr, - &class_device_attr_ad_partner_key.attr, - &class_device_attr_ad_partner_mac.attr, + &dev_attr_slaves.attr, + &dev_attr_mode.attr, + &dev_attr_arp_validate.attr, + &dev_attr_arp_interval.attr, + &dev_attr_arp_ip_target.attr, + &dev_attr_downdelay.attr, + &dev_attr_updelay.attr, + &dev_attr_lacp_rate.attr, + &dev_attr_xmit_hash_policy.attr, + &dev_attr_miimon.attr, + &dev_attr_primary.attr, + &dev_attr_use_carrier.attr, + &dev_attr_active_slave.attr, + &dev_attr_mii_status.attr, + &dev_attr_ad_aggregator.attr, + &dev_attr_ad_num_ports.attr, + &dev_attr_ad_actor_key.attr, + &dev_attr_ad_partner_key.attr, + &dev_attr_ad_partner_mac.attr, NULL, }; @@ -1367,7 +1428,7 @@ int bond_create_sysfs(void) if (!firstbond) return -ENODEV; - netdev_class = firstbond->dev->class_dev.class; + netdev_class = firstbond->dev->dev.class; if (!netdev_class) return -ENODEV; @@ -1395,13 +1456,13 @@ int bond_create_sysfs_entry(struct bonding *bond) struct net_device *dev = bond->dev; int err; - err = sysfs_create_group(&(dev->class_dev.kobj), &bonding_group); + err = sysfs_create_group(&(dev->dev.kobj), &bonding_group); if (err) { printk(KERN_EMERG "eek! didn't create group!\n"); } if (expected_refcount < 1) - expected_refcount = atomic_read(&bond->dev->class_dev.kobj.kref.refcount); + expected_refcount = atomic_read(&bond->dev->dev.kobj.kref.refcount); return err; } @@ -1412,6 +1473,6 @@ void bond_destroy_sysfs_entry(struct bonding *bond) { struct net_device *dev = bond->dev; - sysfs_remove_group(&(dev->class_dev.kobj), &bonding_group); + sysfs_remove_group(&(dev->dev.kobj), &bonding_group); } diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 2194b567239f..0e9ba3c3faf7 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -1102,7 +1102,7 @@ static struct net_device * __init veth_probe_one(int vlan, } kobject_init(&port->kobject); - port->kobject.parent = &dev->class_dev.kobj; + port->kobject.parent = &dev->dev.kobj; port->kobject.ktype = &veth_port_ktype; kobject_set_name(&port->kobject, "veth_port"); if (0 != kobject_add(&port->kobject)) diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 25b559b5d5ed..2af204598144 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -27,8 +27,6 @@ #include "macb.h" -#define to_net_dev(class) container_of(class, struct net_device, class_dev) - #define RX_BUFFER_SIZE 128 #define RX_RING_SIZE 512 #define RX_RING_BYTES (sizeof(struct dma_desc) * RX_RING_SIZE) @@ -945,10 +943,10 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return ret; } -static ssize_t macb_mii_show(const struct class_device *cd, char *buf, +static ssize_t macb_mii_show(const struct device *_dev, char *buf, unsigned long addr) { - struct net_device *dev = to_net_dev(cd); + struct net_device *dev = to_net_dev(_dev); struct macb *bp = netdev_priv(dev); ssize_t ret = -EINVAL; @@ -962,11 +960,13 @@ static ssize_t macb_mii_show(const struct class_device *cd, char *buf, } #define MII_ENTRY(name, addr) \ -static ssize_t show_##name(struct class_device *cd, char *buf) \ +static ssize_t show_##name(struct device *_dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ - return macb_mii_show(cd, buf, addr); \ + return macb_mii_show(_dev, buf, addr); \ } \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) MII_ENTRY(bmcr, MII_BMCR); MII_ENTRY(bmsr, MII_BMSR); @@ -977,13 +977,13 @@ MII_ENTRY(lpa, MII_LPA); MII_ENTRY(expansion, MII_EXPANSION); static struct attribute *macb_mii_attrs[] = { - &class_device_attr_bmcr.attr, - &class_device_attr_bmsr.attr, - &class_device_attr_physid1.attr, - &class_device_attr_physid2.attr, - &class_device_attr_advertise.attr, - &class_device_attr_lpa.attr, - &class_device_attr_expansion.attr, + &dev_attr_bmcr.attr, + &dev_attr_bmsr.attr, + &dev_attr_physid1.attr, + &dev_attr_physid2.attr, + &dev_attr_advertise.attr, + &dev_attr_lpa.attr, + &dev_attr_expansion.attr, NULL, }; @@ -994,17 +994,17 @@ static struct attribute_group macb_mii_group = { static void macb_unregister_sysfs(struct net_device *net) { - struct class_device *class_dev = &net->class_dev; + struct device *_dev = &net->dev; - sysfs_remove_group(&class_dev->kobj, &macb_mii_group); + sysfs_remove_group(&_dev->kobj, &macb_mii_group); } static int macb_register_sysfs(struct net_device *net) { - struct class_device *class_dev = &net->class_dev; + struct device *_dev = &net->dev; int ret; - ret = sysfs_create_group(&class_dev->kobj, &macb_mii_group); + ret = sysfs_create_group(&_dev->kobj, &macb_mii_group); if (ret) printk(KERN_WARNING "%s: sysfs mii attribute registration failed: %d\n", diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 43af61438449..c95614131980 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1659,7 +1659,7 @@ smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strncpy(info->driver, CARDNAME, sizeof(info->driver)); strncpy(info->version, version, sizeof(info->version)); - strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info)); + strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); } static int smc911x_ethtool_nwayreset(struct net_device *dev) diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index e62a9586fb95..49f4b7712ebf 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1712,7 +1712,7 @@ smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strncpy(info->driver, CARDNAME, sizeof(info->driver)); strncpy(info->version, version, sizeof(info->version)); - strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info)); + strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); } static int smc_ethtool_nwayreset(struct net_device *dev) diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 04c19cefa1da..9077e6edde34 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -84,7 +84,7 @@ struct net_device * hostap_add_interface(struct local_info *local, if (strchr(dev->name, '%')) ret = dev_alloc_name(dev, dev->name); - SET_NETDEV_DEV(dev, mdev->class_dev.dev); + SET_NETDEV_DEV(dev, mdev->dev.parent); if (ret >= 0) ret = register_netdevice(dev); diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 936c888e03e1..656f216b857f 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -4293,8 +4293,8 @@ static void orinoco_get_drvinfo(struct net_device *dev, strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1); strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1); strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1); - if (dev->class_dev.dev) - strncpy(info->bus_info, dev->class_dev.dev->bus_id, + if (dev->dev.parent) + strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info) - 1); else snprintf(info->bus_info, sizeof(info->bus_info) - 1, diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index d08ae8d2726c..d1e502236b2a 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -332,7 +332,7 @@ orinoco_cs_config(struct pcmcia_device *link) /* Finally, report what we've done */ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id, + "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index cf2d1486b01d..af70460f008a 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -806,7 +806,7 @@ spectrum_cs_config(struct pcmcia_device *link) /* Finally, report what we've done */ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id, + "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index fea0d9db6846..2e37f5012788 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -529,10 +529,11 @@ struct net_device struct net_bridge_port *br_port; /* class/net/name entry */ - struct class_device class_dev; + struct device dev; /* space for optional statistics and wireless sysfs groups */ struct attribute_group *sysfs_groups[3]; }; +#define to_net_dev(d) container_of(d, struct net_device, dev) #define NETDEV_ALIGN 32 #define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1) @@ -548,7 +549,7 @@ static inline void *netdev_priv(struct net_device *dev) /* Set the sysfs physical device reference for the network logical device * if set prior to registration will cause a symlink during initialization. */ -#define SET_NETDEV_DEV(net, pdev) ((net)->class_dev.dev = (pdev)) +#define SET_NETDEV_DEV(net, pdev) ((net)->dev.parent = (pdev)) struct packet_type { __be16 type; /* This is really htons(ether_type). */ diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 55bb2634c088..2b7c2c7dad48 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -286,7 +286,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, kobject_init(&p->kobj); kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR); p->kobj.ktype = &brport_ktype; - p->kobj.parent = &(dev->class_dev.kobj); + p->kobj.parent = &(dev->dev.kobj); p->kobj.kset = NULL; return p; diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index de9d1a9473f2..ce10464716a7 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -21,18 +21,17 @@ #include "br_private.h" -#define to_class_dev(obj) container_of(obj,struct class_device,kobj) -#define to_net_dev(class) container_of(class, struct net_device, class_dev) +#define to_dev(obj) container_of(obj, struct device, kobj) #define to_bridge(cd) ((struct net_bridge *)(to_net_dev(cd)->priv)) /* * Common code for storing bridge parameters. */ -static ssize_t store_bridge_parm(struct class_device *cd, +static ssize_t store_bridge_parm(struct device *d, const char *buf, size_t len, void (*set)(struct net_bridge *, unsigned long)) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); char *endp; unsigned long val; @@ -50,9 +49,10 @@ static ssize_t store_bridge_parm(struct class_device *cd, } -static ssize_t show_forward_delay(struct class_device *cd, char *buf) +static ssize_t show_forward_delay(struct device *d, + struct device_attribute *attr, char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay)); } @@ -64,18 +64,20 @@ static void set_forward_delay(struct net_bridge *br, unsigned long val) br->bridge_forward_delay = delay; } -static ssize_t store_forward_delay(struct class_device *cd, const char *buf, - size_t len) +static ssize_t store_forward_delay(struct device *d, + struct device_attribute *attr, + const char *buf, size_t len) { - return store_bridge_parm(cd, buf, len, set_forward_delay); + return store_bridge_parm(d, buf, len, set_forward_delay); } -static CLASS_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR, - show_forward_delay, store_forward_delay); +static DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR, + show_forward_delay, store_forward_delay); -static ssize_t show_hello_time(struct class_device *cd, char *buf) +static ssize_t show_hello_time(struct device *d, struct device_attribute *attr, + char *buf) { return sprintf(buf, "%lu\n", - jiffies_to_clock_t(to_bridge(cd)->hello_time)); + jiffies_to_clock_t(to_bridge(d)->hello_time)); } static void set_hello_time(struct net_bridge *br, unsigned long val) @@ -86,19 +88,20 @@ static void set_hello_time(struct net_bridge *br, unsigned long val) br->bridge_hello_time = t; } -static ssize_t store_hello_time(struct class_device *cd, const char *buf, +static ssize_t store_hello_time(struct device *d, + struct device_attribute *attr, const char *buf, size_t len) { - return store_bridge_parm(cd, buf, len, set_hello_time); + return store_bridge_parm(d, buf, len, set_hello_time); } +static DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time, + store_hello_time); -static CLASS_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time, - store_hello_time); - -static ssize_t show_max_age(struct class_device *cd, char *buf) +static ssize_t show_max_age(struct device *d, struct device_attribute *attr, + char *buf) { return sprintf(buf, "%lu\n", - jiffies_to_clock_t(to_bridge(cd)->max_age)); + jiffies_to_clock_t(to_bridge(d)->max_age)); } static void set_max_age(struct net_bridge *br, unsigned long val) @@ -109,18 +112,17 @@ static void set_max_age(struct net_bridge *br, unsigned long val) br->bridge_max_age = t; } -static ssize_t store_max_age(struct class_device *cd, const char *buf, - size_t len) +static ssize_t store_max_age(struct device *d, struct device_attribute *attr, + const char *buf, size_t len) { - return store_bridge_parm(cd, buf, len, set_max_age); + return store_bridge_parm(d, buf, len, set_max_age); } +static DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age); -static CLASS_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, - store_max_age); - -static ssize_t show_ageing_time(struct class_device *cd, char *buf) +static ssize_t show_ageing_time(struct device *d, + struct device_attribute *attr, char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time)); } @@ -129,17 +131,19 @@ static void set_ageing_time(struct net_bridge *br, unsigned long val) br->ageing_time = clock_t_to_jiffies(val); } -static ssize_t store_ageing_time(struct class_device *cd, const char *buf, - size_t len) +static ssize_t store_ageing_time(struct device *d, + struct device_attribute *attr, + const char *buf, size_t len) { - return store_bridge_parm(cd, buf, len, set_ageing_time); + return store_bridge_parm(d, buf, len, set_ageing_time); } +static DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time, + store_ageing_time); -static CLASS_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time, - store_ageing_time); -static ssize_t show_stp_state(struct class_device *cd, char *buf) +static ssize_t show_stp_state(struct device *d, + struct device_attribute *attr, char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%d\n", br->stp_enabled); } @@ -148,18 +152,19 @@ static void set_stp_state(struct net_bridge *br, unsigned long val) br->stp_enabled = val; } -static ssize_t store_stp_state(struct class_device *cd, - const char *buf, size_t len) +static ssize_t store_stp_state(struct device *d, + struct device_attribute *attr, const char *buf, + size_t len) { - return store_bridge_parm(cd, buf, len, set_stp_state); + return store_bridge_parm(d, buf, len, set_stp_state); } +static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, + store_stp_state); -static CLASS_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, - store_stp_state); - -static ssize_t show_priority(struct class_device *cd, char *buf) +static ssize_t show_priority(struct device *d, struct device_attribute *attr, + char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%d\n", (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]); } @@ -169,92 +174,107 @@ static void set_priority(struct net_bridge *br, unsigned long val) br_stp_set_bridge_priority(br, (u16) val); } -static ssize_t store_priority(struct class_device *cd, +static ssize_t store_priority(struct device *d, struct device_attribute *attr, const char *buf, size_t len) { - return store_bridge_parm(cd, buf, len, set_priority); + return store_bridge_parm(d, buf, len, set_priority); } -static CLASS_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, - store_priority); +static DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority); -static ssize_t show_root_id(struct class_device *cd, char *buf) +static ssize_t show_root_id(struct device *d, struct device_attribute *attr, + char *buf) { - return br_show_bridge_id(buf, &to_bridge(cd)->designated_root); + return br_show_bridge_id(buf, &to_bridge(d)->designated_root); } -static CLASS_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL); +static DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL); -static ssize_t show_bridge_id(struct class_device *cd, char *buf) +static ssize_t show_bridge_id(struct device *d, struct device_attribute *attr, + char *buf) { - return br_show_bridge_id(buf, &to_bridge(cd)->bridge_id); + return br_show_bridge_id(buf, &to_bridge(d)->bridge_id); } -static CLASS_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL); +static DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL); -static ssize_t show_root_port(struct class_device *cd, char *buf) +static ssize_t show_root_port(struct device *d, struct device_attribute *attr, + char *buf) { - return sprintf(buf, "%d\n", to_bridge(cd)->root_port); + return sprintf(buf, "%d\n", to_bridge(d)->root_port); } -static CLASS_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL); +static DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL); -static ssize_t show_root_path_cost(struct class_device *cd, char *buf) +static ssize_t show_root_path_cost(struct device *d, + struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", to_bridge(cd)->root_path_cost); + return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost); } -static CLASS_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL); +static DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL); -static ssize_t show_topology_change(struct class_device *cd, char *buf) +static ssize_t show_topology_change(struct device *d, + struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", to_bridge(cd)->topology_change); + return sprintf(buf, "%d\n", to_bridge(d)->topology_change); } -static CLASS_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL); +static DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL); -static ssize_t show_topology_change_detected(struct class_device *cd, char *buf) +static ssize_t show_topology_change_detected(struct device *d, + struct device_attribute *attr, + char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%d\n", br->topology_change_detected); } -static CLASS_DEVICE_ATTR(topology_change_detected, S_IRUGO, show_topology_change_detected, NULL); +static DEVICE_ATTR(topology_change_detected, S_IRUGO, + show_topology_change_detected, NULL); -static ssize_t show_hello_timer(struct class_device *cd, char *buf) +static ssize_t show_hello_timer(struct device *d, + struct device_attribute *attr, char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer)); } -static CLASS_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL); +static DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL); -static ssize_t show_tcn_timer(struct class_device *cd, char *buf) +static ssize_t show_tcn_timer(struct device *d, struct device_attribute *attr, + char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer)); } -static CLASS_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL); +static DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL); -static ssize_t show_topology_change_timer(struct class_device *cd, char *buf) +static ssize_t show_topology_change_timer(struct device *d, + struct device_attribute *attr, + char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer)); } -static CLASS_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, NULL); +static DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, + NULL); -static ssize_t show_gc_timer(struct class_device *cd, char *buf) +static ssize_t show_gc_timer(struct device *d, struct device_attribute *attr, + char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer)); } -static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); +static DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); -static ssize_t show_group_addr(struct class_device *cd, char *buf) +static ssize_t show_group_addr(struct device *d, + struct device_attribute *attr, char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%x:%x:%x:%x:%x:%x\n", br->group_addr[0], br->group_addr[1], br->group_addr[2], br->group_addr[3], br->group_addr[4], br->group_addr[5]); } -static ssize_t store_group_addr(struct class_device *cd, const char *buf, - size_t len) +static ssize_t store_group_addr(struct device *d, + struct device_attribute *attr, + const char *buf, size_t len) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); unsigned new_addr[6]; int i; @@ -286,28 +306,28 @@ static ssize_t store_group_addr(struct class_device *cd, const char *buf, return len; } -static CLASS_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, - show_group_addr, store_group_addr); +static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, + show_group_addr, store_group_addr); static struct attribute *bridge_attrs[] = { - &class_device_attr_forward_delay.attr, - &class_device_attr_hello_time.attr, - &class_device_attr_max_age.attr, - &class_device_attr_ageing_time.attr, - &class_device_attr_stp_state.attr, - &class_device_attr_priority.attr, - &class_device_attr_bridge_id.attr, - &class_device_attr_root_id.attr, - &class_device_attr_root_path_cost.attr, - &class_device_attr_root_port.attr, - &class_device_attr_topology_change.attr, - &class_device_attr_topology_change_detected.attr, - &class_device_attr_hello_timer.attr, - &class_device_attr_tcn_timer.attr, - &class_device_attr_topology_change_timer.attr, - &class_device_attr_gc_timer.attr, - &class_device_attr_group_addr.attr, + &dev_attr_forward_delay.attr, + &dev_attr_hello_time.attr, + &dev_attr_max_age.attr, + &dev_attr_ageing_time.attr, + &dev_attr_stp_state.attr, + &dev_attr_priority.attr, + &dev_attr_bridge_id.attr, + &dev_attr_root_id.attr, + &dev_attr_root_path_cost.attr, + &dev_attr_root_port.attr, + &dev_attr_topology_change.attr, + &dev_attr_topology_change_detected.attr, + &dev_attr_hello_timer.attr, + &dev_attr_tcn_timer.attr, + &dev_attr_topology_change_timer.attr, + &dev_attr_gc_timer.attr, + &dev_attr_group_addr.attr, NULL }; @@ -325,8 +345,8 @@ static struct attribute_group bridge_group = { static ssize_t brforward_read(struct kobject *kobj, char *buf, loff_t off, size_t count) { - struct class_device *cdev = to_class_dev(kobj); - struct net_bridge *br = to_bridge(cdev); + struct device *dev = to_dev(kobj); + struct net_bridge *br = to_bridge(dev); int n; /* must read whole records */ @@ -363,7 +383,7 @@ static struct bin_attribute bridge_forward = { */ int br_sysfs_addbr(struct net_device *dev) { - struct kobject *brobj = &dev->class_dev.kobj; + struct kobject *brobj = &dev->dev.kobj; struct net_bridge *br = netdev_priv(dev); int err; @@ -395,9 +415,9 @@ int br_sysfs_addbr(struct net_device *dev) } return 0; out3: - sysfs_remove_bin_file(&dev->class_dev.kobj, &bridge_forward); + sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward); out2: - sysfs_remove_group(&dev->class_dev.kobj, &bridge_group); + sysfs_remove_group(&dev->dev.kobj, &bridge_group); out1: return err; @@ -405,7 +425,7 @@ int br_sysfs_addbr(struct net_device *dev) void br_sysfs_delbr(struct net_device *dev) { - struct kobject *kobj = &dev->class_dev.kobj; + struct kobject *kobj = &dev->dev.kobj; struct net_bridge *br = netdev_priv(dev); kobject_unregister(&br->ifobj); diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index c51c9e42aeb3..0bc2aef8f9f3 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -211,7 +211,7 @@ int br_sysfs_addif(struct net_bridge_port *p) struct brport_attribute **a; int err; - err = sysfs_create_link(&p->kobj, &br->dev->class_dev.kobj, + err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj, SYSFS_BRIDGE_PORT_LINK); if (err) goto out2; diff --git a/net/core/dev.c b/net/core/dev.c index e660cb57e42a..455d589683e8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -751,7 +751,7 @@ int dev_change_name(struct net_device *dev, char *newname) else strlcpy(dev->name, newname, IFNAMSIZ); - err = class_device_rename(&dev->class_dev, dev->name); + err = device_rename(&dev->dev, dev->name); if (!err) { hlist_del(&dev->name_hlist); hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); @@ -3221,8 +3221,8 @@ void free_netdev(struct net_device *dev) BUG_ON(dev->reg_state != NETREG_UNREGISTERED); dev->reg_state = NETREG_RELEASED; - /* will free via class release */ - class_device_put(&dev->class_dev); + /* will free via device release */ + put_device(&dev->dev); #else kfree((char *)dev - dev->padded); #endif diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index f47f319bb7dc..44db095a8f7e 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -18,9 +18,6 @@ #include #include -#define to_class_dev(obj) container_of(obj,struct class_device,kobj) -#define to_net_dev(class) container_of(class, struct net_device, class_dev) - static const char fmt_hex[] = "%#x\n"; static const char fmt_long_hex[] = "%#lx\n"; static const char fmt_dec[] = "%d\n"; @@ -32,10 +29,11 @@ static inline int dev_isalive(const struct net_device *dev) } /* use same locking rules as GIF* ioctl's */ -static ssize_t netdev_show(const struct class_device *cd, char *buf, +static ssize_t netdev_show(const struct device *dev, + struct device_attribute *attr, char *buf, ssize_t (*format)(const struct net_device *, char *)) { - struct net_device *net = to_net_dev(cd); + struct net_device *net = to_net_dev(dev); ssize_t ret = -EINVAL; read_lock(&dev_base_lock); @@ -52,14 +50,15 @@ static ssize_t format_##field(const struct net_device *net, char *buf) \ { \ return sprintf(buf, format_string, net->field); \ } \ -static ssize_t show_##field(struct class_device *cd, char *buf) \ +static ssize_t show_##field(struct device *dev, \ + struct device_attribute *attr, char *buf) \ { \ - return netdev_show(cd, buf, format_##field); \ + return netdev_show(dev, attr, buf, format_##field); \ } /* use same locking and permission rules as SIF* ioctl's */ -static ssize_t netdev_store(struct class_device *dev, +static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len, int (*set)(struct net_device *, unsigned long)) { @@ -104,7 +103,8 @@ static ssize_t format_addr(char *buf, const unsigned char *addr, int len) return cp - buf; } -static ssize_t show_address(struct class_device *dev, char *buf) +static ssize_t show_address(struct device *dev, struct device_attribute *attr, + char *buf) { struct net_device *net = to_net_dev(dev); ssize_t ret = -EINVAL; @@ -116,7 +116,8 @@ static ssize_t show_address(struct class_device *dev, char *buf) return ret; } -static ssize_t show_broadcast(struct class_device *dev, char *buf) +static ssize_t show_broadcast(struct device *dev, + struct device_attribute *attr, char *buf) { struct net_device *net = to_net_dev(dev); if (dev_isalive(net)) @@ -124,7 +125,8 @@ static ssize_t show_broadcast(struct class_device *dev, char *buf) return -EINVAL; } -static ssize_t show_carrier(struct class_device *dev, char *buf) +static ssize_t show_carrier(struct device *dev, + struct device_attribute *attr, char *buf) { struct net_device *netdev = to_net_dev(dev); if (netif_running(netdev)) { @@ -133,7 +135,8 @@ static ssize_t show_carrier(struct class_device *dev, char *buf) return -EINVAL; } -static ssize_t show_dormant(struct class_device *dev, char *buf) +static ssize_t show_dormant(struct device *dev, + struct device_attribute *attr, char *buf) { struct net_device *netdev = to_net_dev(dev); @@ -153,7 +156,8 @@ static const char *operstates[] = { "up" }; -static ssize_t show_operstate(struct class_device *dev, char *buf) +static ssize_t show_operstate(struct device *dev, + struct device_attribute *attr, char *buf) { const struct net_device *netdev = to_net_dev(dev); unsigned char operstate; @@ -178,9 +182,10 @@ static int change_mtu(struct net_device *net, unsigned long new_mtu) return dev_set_mtu(net, (int) new_mtu); } -static ssize_t store_mtu(struct class_device *dev, const char *buf, size_t len) +static ssize_t store_mtu(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) { - return netdev_store(dev, buf, len, change_mtu); + return netdev_store(dev, attr, buf, len, change_mtu); } NETDEVICE_SHOW(flags, fmt_hex); @@ -190,9 +195,10 @@ static int change_flags(struct net_device *net, unsigned long new_flags) return dev_change_flags(net, (unsigned) new_flags); } -static ssize_t store_flags(struct class_device *dev, const char *buf, size_t len) +static ssize_t store_flags(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) { - return netdev_store(dev, buf, len, change_flags); + return netdev_store(dev, attr, buf, len, change_flags); } NETDEVICE_SHOW(tx_queue_len, fmt_ulong); @@ -203,9 +209,11 @@ static int change_tx_queue_len(struct net_device *net, unsigned long new_len) return 0; } -static ssize_t store_tx_queue_len(struct class_device *dev, const char *buf, size_t len) +static ssize_t store_tx_queue_len(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) { - return netdev_store(dev, buf, len, change_tx_queue_len); + return netdev_store(dev, attr, buf, len, change_tx_queue_len); } NETDEVICE_SHOW(weight, fmt_dec); @@ -216,12 +224,13 @@ static int change_weight(struct net_device *net, unsigned long new_weight) return 0; } -static ssize_t store_weight(struct class_device *dev, const char *buf, size_t len) +static ssize_t store_weight(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) { - return netdev_store(dev, buf, len, change_weight); + return netdev_store(dev, attr, buf, len, change_weight); } -static struct class_device_attribute net_class_attributes[] = { +static struct device_attribute net_class_attributes[] = { __ATTR(addr_len, S_IRUGO, show_addr_len, NULL), __ATTR(iflink, S_IRUGO, show_iflink, NULL), __ATTR(ifindex, S_IRUGO, show_ifindex, NULL), @@ -242,10 +251,11 @@ static struct class_device_attribute net_class_attributes[] = { }; /* Show a given an attribute in the statistics group */ -static ssize_t netstat_show(const struct class_device *cd, char *buf, +static ssize_t netstat_show(const struct device *d, + struct device_attribute *attr, char *buf, unsigned long offset) { - struct net_device *dev = to_net_dev(cd); + struct net_device *dev = to_net_dev(d); struct net_device_stats *stats; ssize_t ret = -EINVAL; @@ -265,12 +275,13 @@ static ssize_t netstat_show(const struct class_device *cd, char *buf, /* generate a read-only statistics attribute */ #define NETSTAT_ENTRY(name) \ -static ssize_t show_##name(struct class_device *cd, char *buf) \ +static ssize_t show_##name(struct device *d, \ + struct device_attribute *attr, char *buf) \ { \ - return netstat_show(cd, buf, \ + return netstat_show(d, attr, buf, \ offsetof(struct net_device_stats, name)); \ } \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) NETSTAT_ENTRY(rx_packets); NETSTAT_ENTRY(tx_packets); @@ -297,29 +308,29 @@ NETSTAT_ENTRY(rx_compressed); NETSTAT_ENTRY(tx_compressed); static struct attribute *netstat_attrs[] = { - &class_device_attr_rx_packets.attr, - &class_device_attr_tx_packets.attr, - &class_device_attr_rx_bytes.attr, - &class_device_attr_tx_bytes.attr, - &class_device_attr_rx_errors.attr, - &class_device_attr_tx_errors.attr, - &class_device_attr_rx_dropped.attr, - &class_device_attr_tx_dropped.attr, - &class_device_attr_multicast.attr, - &class_device_attr_collisions.attr, - &class_device_attr_rx_length_errors.attr, - &class_device_attr_rx_over_errors.attr, - &class_device_attr_rx_crc_errors.attr, - &class_device_attr_rx_frame_errors.attr, - &class_device_attr_rx_fifo_errors.attr, - &class_device_attr_rx_missed_errors.attr, - &class_device_attr_tx_aborted_errors.attr, - &class_device_attr_tx_carrier_errors.attr, - &class_device_attr_tx_fifo_errors.attr, - &class_device_attr_tx_heartbeat_errors.attr, - &class_device_attr_tx_window_errors.attr, - &class_device_attr_rx_compressed.attr, - &class_device_attr_tx_compressed.attr, + &dev_attr_rx_packets.attr, + &dev_attr_tx_packets.attr, + &dev_attr_rx_bytes.attr, + &dev_attr_tx_bytes.attr, + &dev_attr_rx_errors.attr, + &dev_attr_tx_errors.attr, + &dev_attr_rx_dropped.attr, + &dev_attr_tx_dropped.attr, + &dev_attr_multicast.attr, + &dev_attr_collisions.attr, + &dev_attr_rx_length_errors.attr, + &dev_attr_rx_over_errors.attr, + &dev_attr_rx_crc_errors.attr, + &dev_attr_rx_frame_errors.attr, + &dev_attr_rx_fifo_errors.attr, + &dev_attr_rx_missed_errors.attr, + &dev_attr_tx_aborted_errors.attr, + &dev_attr_tx_carrier_errors.attr, + &dev_attr_tx_fifo_errors.attr, + &dev_attr_tx_heartbeat_errors.attr, + &dev_attr_tx_window_errors.attr, + &dev_attr_rx_compressed.attr, + &dev_attr_tx_compressed.attr, NULL }; @@ -331,11 +342,11 @@ static struct attribute_group netstat_group = { #ifdef WIRELESS_EXT /* helper function that does all the locking etc for wireless stats */ -static ssize_t wireless_show(struct class_device *cd, char *buf, +static ssize_t wireless_show(struct device *d, char *buf, ssize_t (*format)(const struct iw_statistics *, char *)) { - struct net_device *dev = to_net_dev(cd); + struct net_device *dev = to_net_dev(d); const struct iw_statistics *iw = NULL; ssize_t ret = -EINVAL; @@ -358,11 +369,12 @@ static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \ { \ return sprintf(buf, format_string, iw->field); \ } \ -static ssize_t show_iw_##name(struct class_device *cd, char *buf) \ +static ssize_t show_iw_##name(struct device *d, \ + struct device_attribute *attr, char *buf) \ { \ - return wireless_show(cd, buf, format_iw_##name); \ + return wireless_show(d, buf, format_iw_##name); \ } \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL) +static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL) WIRELESS_SHOW(status, status, fmt_hex); WIRELESS_SHOW(link, qual.qual, fmt_dec); @@ -376,16 +388,16 @@ WIRELESS_SHOW(retries, discard.retries, fmt_dec); WIRELESS_SHOW(beacon, miss.beacon, fmt_dec); static struct attribute *wireless_attrs[] = { - &class_device_attr_status.attr, - &class_device_attr_link.attr, - &class_device_attr_level.attr, - &class_device_attr_noise.attr, - &class_device_attr_nwid.attr, - &class_device_attr_crypt.attr, - &class_device_attr_fragment.attr, - &class_device_attr_retries.attr, - &class_device_attr_misc.attr, - &class_device_attr_beacon.attr, + &dev_attr_status.attr, + &dev_attr_link.attr, + &dev_attr_level.attr, + &dev_attr_noise.attr, + &dev_attr_nwid.attr, + &dev_attr_crypt.attr, + &dev_attr_fragment.attr, + &dev_attr_retries.attr, + &dev_attr_misc.attr, + &dev_attr_beacon.attr, NULL }; @@ -396,10 +408,10 @@ static struct attribute_group wireless_group = { #endif #ifdef CONFIG_HOTPLUG -static int netdev_uevent(struct class_device *cd, char **envp, +static int netdev_uevent(struct device *d, char **envp, int num_envp, char *buf, int size) { - struct net_device *dev = to_net_dev(cd); + struct net_device *dev = to_net_dev(d); int i = 0; int n; @@ -419,12 +431,11 @@ static int netdev_uevent(struct class_device *cd, char **envp, /* * netdev_release -- destroy and free a dead device. - * Called when last reference to class_device kobject is gone. + * Called when last reference to device kobject is gone. */ -static void netdev_release(struct class_device *cd) +static void netdev_release(struct device *d) { - struct net_device *dev - = container_of(cd, struct net_device, class_dev); + struct net_device *dev = to_net_dev(d); BUG_ON(dev->reg_state != NETREG_RELEASED); @@ -433,31 +444,31 @@ static void netdev_release(struct class_device *cd) static struct class net_class = { .name = "net", - .release = netdev_release, - .class_dev_attrs = net_class_attributes, + .dev_release = netdev_release, + .dev_attrs = net_class_attributes, #ifdef CONFIG_HOTPLUG - .uevent = netdev_uevent, + .dev_uevent = netdev_uevent, #endif }; void netdev_unregister_sysfs(struct net_device * net) { - class_device_del(&(net->class_dev)); + device_del(&(net->dev)); } /* Create sysfs entries for network device. */ int netdev_register_sysfs(struct net_device *net) { - struct class_device *class_dev = &(net->class_dev); + struct device *dev = &(net->dev); struct attribute_group **groups = net->sysfs_groups; - class_device_initialize(class_dev); - class_dev->class = &net_class; - class_dev->class_data = net; - class_dev->groups = groups; + device_initialize(dev); + dev->class = &net_class; + dev->platform_data = net; + dev->groups = groups; BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ); - strlcpy(class_dev->class_id, net->name, BUS_ID_SIZE); + strlcpy(dev->bus_id, net->name, BUS_ID_SIZE); if (net->get_stats) *groups++ = &netstat_group; @@ -467,7 +478,7 @@ int netdev_register_sysfs(struct net_device *net) *groups++ = &wireless_group; #endif - return class_device_add(class_dev); + return device_add(dev); } int netdev_sysfs_init(void) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index de7801d589e7..f3404ae9f190 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -268,7 +268,7 @@ nodata: struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int length, gfp_t gfp_mask) { - int node = dev->class_dev.dev ? dev_to_node(dev->class_dev.dev) : -1; + int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1; struct sk_buff *skb; skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, node); -- cgit v1.2.3 From f30c53a873d0d227493197064b8886af2d57bbd6 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 15 Jan 2007 20:22:02 +0100 Subject: MODULES: add the module name for built in kernel drivers Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- include/linux/device.h | 1 + include/linux/module.h | 2 +- kernel/module.c | 33 ++++++++++++++++++++++++--------- kernel/params.c | 12 +++++------- 4 files changed, 31 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/include/linux/device.h b/include/linux/device.h index f44247fe8135..da7221913114 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -126,6 +126,7 @@ struct device_driver { struct klist_node knode_bus; struct module * owner; + const char * mod_name; /* used for built-in modules */ int (*probe) (struct device * dev); int (*remove) (struct device * dev); diff --git a/include/linux/module.h b/include/linux/module.h index 10f771a49997..90dc2542978c 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -58,6 +58,7 @@ struct module_kobject { struct kobject kobj; struct module *mod; + struct kobject *drivers_dir; }; /* These are either module local, or the kernel's dummy ones. */ @@ -263,7 +264,6 @@ struct module struct module_attribute *modinfo_attrs; const char *version; const char *srcversion; - struct kobject *drivers_dir; /* Exported symbols */ const struct kernel_symbol *syms; diff --git a/kernel/module.c b/kernel/module.c index d0f2260a0210..0f4489af3e29 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1131,8 +1131,8 @@ static int mod_sysfs_setup(struct module *mod, if (err) goto out; - mod->drivers_dir = kobject_add_dir(&mod->mkobj.kobj, "drivers"); - if (!mod->drivers_dir) { + mod->mkobj.drivers_dir = kobject_add_dir(&mod->mkobj.kobj, "drivers"); + if (!mod->mkobj.drivers_dir) { err = -ENOMEM; goto out_unreg; } @@ -1151,7 +1151,7 @@ static int mod_sysfs_setup(struct module *mod, out_unreg_param: module_param_sysfs_remove(mod); out_unreg_drivers: - kobject_unregister(mod->drivers_dir); + kobject_unregister(mod->mkobj.drivers_dir); out_unreg: kobject_del(&mod->mkobj.kobj); kobject_put(&mod->mkobj.kobj); @@ -1163,7 +1163,7 @@ static void mod_kobject_remove(struct module *mod) { module_remove_modinfo_attrs(mod); module_param_sysfs_remove(mod); - kobject_unregister(mod->drivers_dir); + kobject_unregister(mod->mkobj.drivers_dir); kobject_unregister(&mod->mkobj.kobj); } @@ -2344,15 +2344,30 @@ void module_add_driver(struct module *mod, struct device_driver *drv) { char *driver_name; int no_warn; + struct module_kobject *mk = NULL; - if (!mod || !drv) + if (!drv) + return; + + if (mod) + mk = &mod->mkobj; + else if (drv->mod_name) { + struct kobject *mkobj; + + /* Lookup built-in module entry in /sys/modules */ + mkobj = kset_find_obj(&module_subsys.kset, drv->mod_name); + if (mkobj) + mk = container_of(mkobj, struct module_kobject, kobj); + } + + if (!mk) return; /* Don't check return codes; these calls are idempotent */ - no_warn = sysfs_create_link(&drv->kobj, &mod->mkobj.kobj, "module"); + no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module"); driver_name = make_driver_name(drv); if (driver_name) { - no_warn = sysfs_create_link(mod->drivers_dir, &drv->kobj, + no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj, driver_name); kfree(driver_name); } @@ -2367,10 +2382,10 @@ void module_remove_driver(struct device_driver *drv) return; sysfs_remove_link(&drv->kobj, "module"); - if (drv->owner && drv->owner->drivers_dir) { + if (drv->owner && drv->owner->mkobj.drivers_dir) { driver_name = make_driver_name(drv); if (driver_name) { - sysfs_remove_link(drv->owner->drivers_dir, + sysfs_remove_link(drv->owner->mkobj.drivers_dir, driver_name); kfree(driver_name); } diff --git a/kernel/params.c b/kernel/params.c index 718945da8f58..737b7c5e93aa 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -561,14 +561,12 @@ static void __init kernel_param_sysfs_setup(const char *name, mk->mod = THIS_MODULE; kobj_set_kset_s(mk, module_subsys); kobject_set_name(&mk->kobj, name); - ret = kobject_register(&mk->kobj); + kobject_init(&mk->kobj); + ret = kobject_add(&mk->kobj); BUG_ON(ret < 0); - - /* no need to keep the kobject if no parameter is exported */ - if (!param_sysfs_setup(mk, kparam, num_params, name_skip)) { - kobject_unregister(&mk->kobj); - kfree(mk); - } + param_sysfs_setup(mk, kparam, num_params, name_skip); + mk->drivers_dir = kobject_add_dir(&mk->kobj, "drivers"); + kobject_uevent(&mk->kobj, KOBJ_ADD); } /* -- cgit v1.2.3 From 725522b5453dd680412f2b6463a988e4fd148757 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Jan 2007 11:50:02 -0800 Subject: PCI: add the sysfs driver name to all modules This adds the module name to all PCI drivers, if they are built into the kernel or not. It will show up in /sys/modules/MODULE_NAME/drivers/ It also fixes up the IDE core, which was calling __pci_register_driver() directly. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/ide/setup-pci.c | 7 ++++--- drivers/pci/pci-driver.c | 4 +++- include/linux/ide.h | 4 ++-- include/linux/pci.h | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 695e23904d30..a52c80fe7d3e 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -783,10 +783,11 @@ static LIST_HEAD(ide_pci_drivers); * Returns are the same as for pci_register_driver */ -int __ide_pci_register_driver(struct pci_driver *driver, struct module *module) +int __ide_pci_register_driver(struct pci_driver *driver, struct module *module, + const char *mod_name) { if(!pre_init) - return __pci_register_driver(driver, module); + return __pci_register_driver(driver, module, mod_name); driver->driver.owner = module; list_add_tail(&driver->node, &ide_pci_drivers); return 0; @@ -862,6 +863,6 @@ void __init ide_scan_pcibus (int scan_direction) { list_del(l); d = list_entry(l, struct pci_driver, node); - __pci_register_driver(d, d->driver.owner); + __pci_register_driver(d, d->driver.owner, d->driver.mod_name); } } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 92d5e8db0de7..358766885260 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -422,7 +422,8 @@ static struct kobj_type pci_driver_kobj_type = { * If no error occurred, the driver remains registered even if * no device was claimed during registration. */ -int __pci_register_driver(struct pci_driver *drv, struct module *owner) +int __pci_register_driver(struct pci_driver *drv, struct module *owner, + const char *mod_name) { int error; @@ -430,6 +431,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner) drv->driver.name = drv->name; drv->driver.bus = &pci_bus_type; drv->driver.owner = owner; + drv->driver.mod_name = mod_name; drv->driver.kobj.ktype = &pci_driver_kobj_type; if (pci_multithread_probe) diff --git a/include/linux/ide.h b/include/linux/ide.h index e26a03981a94..827688f41d6c 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1192,8 +1192,8 @@ void ide_init_disk(struct gendisk *, ide_drive_t *); extern int ideprobe_init(void); extern void ide_scan_pcibus(int scan_direction) __init; -extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner); -#define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE) +extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner, const char *mod_name); +#define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE, KBUILD_MODNAME) void ide_pci_setup_ports(struct pci_dev *, struct ide_pci_device_s *, int, ata_index_t *); extern void ide_setup_pci_noise (struct pci_dev *dev, struct ide_pci_device_s *d); diff --git a/include/linux/pci.h b/include/linux/pci.h index f3c617eabd8d..cb899eb95d31 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -573,10 +573,11 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus, void pci_enable_bridges(struct pci_bus *bus); /* Proper probing supporting hot-pluggable devices */ -int __must_check __pci_register_driver(struct pci_driver *, struct module *); +int __must_check __pci_register_driver(struct pci_driver *, struct module *, + const char *mod_name); static inline int __must_check pci_register_driver(struct pci_driver *driver) { - return __pci_register_driver(driver, THIS_MODULE); + return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME); } void pci_unregister_driver(struct pci_driver *); -- cgit v1.2.3 From 4b315627e6b894156e235ac905786e7d46aab2e6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Jan 2007 11:50:02 -0800 Subject: SERIO: add the sysfs driver name to all modules This adds the module name to all SERIO drivers, if they are built into the kernel or not. It will show up in /sys/modules/MODULE_NAME/drivers/ Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/input/serio/serio.c | 6 ++++-- include/linux/serio.h | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index f0ce822c1028..17c8c63cbe1a 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -45,7 +45,7 @@ EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(__serio_register_port); EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_child_port); -EXPORT_SYMBOL(serio_register_driver); +EXPORT_SYMBOL(__serio_register_driver); EXPORT_SYMBOL(serio_unregister_driver); EXPORT_SYMBOL(serio_open); EXPORT_SYMBOL(serio_close); @@ -789,12 +789,14 @@ static void serio_attach_driver(struct serio_driver *drv) drv->driver.name, error); } -int serio_register_driver(struct serio_driver *drv) +int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name) { int manual_bind = drv->manual_bind; int error; drv->driver.bus = &serio_bus; + drv->driver.owner = owner; + drv->driver.mod_name = mod_name; /* * Temporarily disable automatic binding because probing diff --git a/include/linux/serio.h b/include/linux/serio.h index 0f478a8791a2..ac2c70e7f760 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -86,6 +86,11 @@ static inline void serio_register_port(struct serio *serio) void serio_unregister_port(struct serio *serio); void serio_unregister_child_port(struct serio *serio); +int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name); +static inline int serio_register_driver(struct serio_driver *drv) +{ + return __serio_register_driver(drv, THIS_MODULE, KBUILD_MODNAME); +} int serio_register_driver(struct serio_driver *drv); void serio_unregister_driver(struct serio_driver *drv); -- cgit v1.2.3 From 80f745fb1b0fb11383cbb8df2c36aaaa0399b6e6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Jan 2007 11:50:02 -0800 Subject: USB: add the sysfs driver name to all modules This adds the module name to all USB drivers, if they are built into the kernel or not. It will show up in /sys/modules/MODULE_NAME/drivers/ Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 4 +++- include/linux/usb.h | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d6eb5ce1dd1d..d505926aa9cc 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -750,7 +750,8 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver); * usb_register_dev() to enable that functionality. This function no longer * takes care of that. */ -int usb_register_driver(struct usb_driver *new_driver, struct module *owner) +int usb_register_driver(struct usb_driver *new_driver, struct module *owner, + const char *mod_name) { int retval = 0; @@ -763,6 +764,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner) new_driver->drvwrap.driver.probe = usb_probe_interface; new_driver->drvwrap.driver.remove = usb_unbind_interface; new_driver->drvwrap.driver.owner = owner; + new_driver->drvwrap.driver.mod_name = mod_name; spin_lock_init(&new_driver->dynids.lock); INIT_LIST_HEAD(&new_driver->dynids.list); diff --git a/include/linux/usb.h b/include/linux/usb.h index aab5b1b72021..733f38de4978 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -868,10 +868,11 @@ struct usb_class_driver { * use these in module_init()/module_exit() * and don't forget MODULE_DEVICE_TABLE(usb, ...) */ -extern int usb_register_driver(struct usb_driver *, struct module *); +extern int usb_register_driver(struct usb_driver *, struct module *, + const char *); static inline int usb_register(struct usb_driver *driver) { - return usb_register_driver(driver, THIS_MODULE); + return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME); } extern void usb_deregister(struct usb_driver *); -- cgit v1.2.3 From 270a6c4cad809e92d7b81adde92d0b3d94eeb8ee Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 18 Jan 2007 13:26:15 +0100 Subject: /sys/modules/*/holders /sys/module/usbcore/ |-- drivers | |-- usb:hub -> ../../../subsystem/usb/drivers/hub | |-- usb:usb -> ../../../subsystem/usb/drivers/usb | `-- usb:usbfs -> ../../../subsystem/usb/drivers/usbfs |-- holders | |-- ehci_hcd -> ../../../module/ehci_hcd | |-- uhci_hcd -> ../../../module/uhci_hcd | |-- usb_storage -> ../../../module/usb_storage | `-- usbhid -> ../../../module/usbhid |-- initstate Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- include/linux/module.h | 1 + kernel/module.c | 37 +++++++++++++++++++++++++++++++------ kernel/params.c | 17 ++++++++++++++++- 3 files changed, 48 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/module.h b/include/linux/module.h index 90dc2542978c..419d3ef293dd 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -264,6 +264,7 @@ struct module struct module_attribute *modinfo_attrs; const char *version; const char *srcversion; + struct kobject *holders_dir; /* Exported symbols */ const struct kernel_symbol *syms; diff --git a/kernel/module.c b/kernel/module.c index 9de4209f6a67..8a94e054230c 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -537,6 +537,8 @@ static int already_uses(struct module *a, struct module *b) static int use_module(struct module *a, struct module *b) { struct module_use *use; + int no_warn; + if (b == NULL || already_uses(a, b)) return 1; if (!strong_try_module_get(b)) @@ -552,6 +554,7 @@ static int use_module(struct module *a, struct module *b) use->module_which_uses = a; list_add(&use->list, &b->modules_which_use_me); + no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name); return 1; } @@ -569,6 +572,7 @@ static void module_unload_free(struct module *mod) module_put(i); list_del(&use->list); kfree(use); + sysfs_remove_link(i->holders_dir, mod->name); /* There can be at most one match. */ break; } @@ -1106,9 +1110,7 @@ static void module_remove_modinfo_attrs(struct module *mod) kfree(mod->modinfo_attrs); } -static int mod_sysfs_setup(struct module *mod, - struct kernel_param *kparam, - unsigned int num_params) +static int mod_sysfs_init(struct module *mod) { int err; @@ -1125,15 +1127,30 @@ static int mod_sysfs_setup(struct module *mod, kobj_set_kset_s(&mod->mkobj, module_subsys); mod->mkobj.mod = mod; - /* delay uevent until full sysfs population */ kobject_init(&mod->mkobj.kobj); + +out: + return err; +} + +static int mod_sysfs_setup(struct module *mod, + struct kernel_param *kparam, + unsigned int num_params) +{ + int err; + + /* delay uevent until full sysfs population */ err = kobject_add(&mod->mkobj.kobj); if (err) goto out; + mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders"); + if (!mod->holders_dir) + goto out_unreg; + err = module_param_sysfs_setup(mod, kparam, num_params); if (err) - goto out_unreg_drivers; + goto out_unreg_holders; err = module_add_modinfo_attrs(mod); if (err) @@ -1144,7 +1161,9 @@ static int mod_sysfs_setup(struct module *mod, out_unreg_param: module_param_sysfs_remove(mod); -out_unreg_drivers: +out_unreg_holders: + kobject_unregister(mod->holders_dir); +out_unreg: kobject_del(&mod->mkobj.kobj); kobject_put(&mod->mkobj.kobj); out: @@ -1157,6 +1176,8 @@ static void mod_kobject_remove(struct module *mod) module_param_sysfs_remove(mod); if (mod->mkobj.drivers_dir) kobject_unregister(mod->mkobj.drivers_dir); + if (mod->holders_dir) + kobject_unregister(mod->holders_dir); kobject_unregister(&mod->mkobj.kobj); } @@ -1761,6 +1782,10 @@ static struct module *load_module(void __user *umod, /* Now we've moved module, initialize linked lists, etc. */ module_unload_init(mod); + /* Initialize kobject, so we can reference it. */ + if (mod_sysfs_init(mod) != 0) + goto cleanup; + /* Set up license info based on the info section */ set_license(mod, get_modinfo(sechdrs, infoindex, "license")); diff --git a/kernel/params.c b/kernel/params.c index cbaac85942d5..553cf7d6a4be 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -30,6 +30,8 @@ #define DEBUGP(fmt, a...) #endif +static struct kobj_type module_ktype; + static inline char dash2underscore(char c) { if (c == '-') @@ -671,6 +673,19 @@ static struct sysfs_ops module_sysfs_ops = { .store = module_attr_store, }; +static int uevent_filter(struct kset *kset, struct kobject *kobj) +{ + struct kobj_type *ktype = get_ktype(kobj); + + if (ktype == &module_ktype) + return 1; + return 0; +} + +static struct kset_uevent_ops module_uevent_ops = { + .filter = uevent_filter, +}; + #else static struct sysfs_ops module_sysfs_ops = { .show = NULL, @@ -682,7 +697,7 @@ static struct kobj_type module_ktype = { .sysfs_ops = &module_sysfs_ops, }; -decl_subsys(module, &module_ktype, NULL); +decl_subsys(module, &module_ktype, &module_uevent_ops); /* * param_sysfs_init - wrapper for built-in params support -- cgit v1.2.3 From bf0acc330229554c695e4f95e5aa2d2c4f12de1f Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Wed, 17 Jan 2007 17:51:18 +0100 Subject: SYSFS: Fix missing include of list.h in sysfs.h Sysfs.h uses definitions (e.g. struct list_head s_sibling) from list.h but does not include it. Signed-off-by: Frank Haverkamp Signed-off-by: Greg Kroah-Hartman --- include/linux/sysfs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 2129d1b6c874..eee485957c0c 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -11,6 +11,7 @@ #define _SYSFS_H_ #include +#include #include struct kobject; -- cgit v1.2.3 From f9f852df2faf76a2667949ddb4947d4b8f99f02f Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 7 Oct 2006 21:54:55 +0200 Subject: Driver core: add device_type to struct device This allows us to add type specific attributes, uevent vars and release funtions. A subsystem can carry different types of devices like the "block" subsys has disks and partitions. Both types create a different set of attributes, but belong to the same subsystem. This corresponds to the low level objects: kobject -> device (object/device data) kobj_type -> device_type (type of object/device we are embedded in) kset -> class/bus (list of objects/devices of a subsystem) Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 57 ++++++++++++++++++++++++++++++-------------- drivers/usb/input/hid-lgff.c | 4 ++-- include/linux/device.h | 8 +++++++ 3 files changed, 49 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/core.c b/drivers/base/core.c index 7a5336f7df89..34ac18778d8a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -95,6 +95,8 @@ static void device_release(struct kobject * kobj) if (dev->release) dev->release(dev); + else if (dev->type && dev->type->release) + dev->type->release(dev); else if (dev->class && dev->class->dev_release) dev->class->dev_release(dev); else { @@ -206,19 +208,25 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, 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); - if (retval) { - pr_debug ("%s - uevent() returned %d\n", + if (retval) + pr_debug ("%s: bus uevent() returned %d\n", __FUNCTION__, retval); - } } 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); - if (retval) { - pr_debug("%s - dev_uevent() returned %d\n", - __FUNCTION__, retval); - } + if (retval) + pr_debug("%s: class uevent() returned %d\n", + __FUNCTION__, retval); + } + + 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); + if (retval) + pr_debug("%s: dev_type uevent() returned %d\n", + __FUNCTION__, retval); } return retval; @@ -269,37 +277,50 @@ static void device_remove_groups(struct device *dev) static int device_add_attrs(struct device *dev) { struct class *class = dev->class; + struct device_type *type = dev->type; int error = 0; int i; - if (!class) - return 0; - - if (class->dev_attrs) { + if (class && class->dev_attrs) { for (i = 0; attr_name(class->dev_attrs[i]); i++) { error = device_create_file(dev, &class->dev_attrs[i]); if (error) break; } + if (error) + while (--i >= 0) + device_remove_file(dev, &class->dev_attrs[i]); } - if (error) - while (--i >= 0) - device_remove_file(dev, &class->dev_attrs[i]); + + if (type && type->attrs) { + for (i = 0; attr_name(type->attrs[i]); i++) { + error = device_create_file(dev, &type->attrs[i]); + if (error) + break; + } + if (error) + while (--i >= 0) + device_remove_file(dev, &type->attrs[i]); + } + return error; } static void device_remove_attrs(struct device *dev) { struct class *class = dev->class; + struct device_type *type = dev->type; int i; - if (!class) - return; - - if (class->dev_attrs) { + if (class && class->dev_attrs) { for (i = 0; attr_name(class->dev_attrs[i]); i++) device_remove_file(dev, &class->dev_attrs[i]); } + + if (type && type->attrs) { + for (i = 0; attr_name(type->attrs[i]); i++) + device_remove_file(dev, &type->attrs[i]); + } } diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index e47466268565..4f4fc3be192e 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -32,7 +32,7 @@ #include #include "usbhid.h" -struct device_type { +struct dev_type { u16 idVendor; u16 idProduct; const signed short *ff; @@ -48,7 +48,7 @@ static const signed short ff_joystick[] = { -1 }; -static const struct device_type devices[] = { +static const struct dev_type devices[] = { { 0x046d, 0xc211, ff_rumble }, { 0x046d, 0xc219, ff_rumble }, { 0x046d, 0xc283, ff_joystick }, diff --git a/include/linux/device.h b/include/linux/device.h index da7221913114..e1e164f81eea 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -328,6 +328,13 @@ extern struct class_device *class_device_create(struct class *cls, __attribute__((format(printf,5,6))); extern void class_device_destroy(struct class *cls, dev_t devt); +struct device_type { + struct device_attribute *attrs; + int (*uevent)(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size); + void (*release)(struct device *dev); +}; + /* interface for exporting device attributes */ struct device_attribute { struct attribute attr; @@ -356,6 +363,7 @@ struct device { struct kobject kobj; char bus_id[BUS_ID_SIZE]; /* position on parent bus */ + struct device_type *type; unsigned is_registered:1; struct device_attribute uevent_attr; struct device_attribute *devt_attr; -- cgit v1.2.3 From b7a3e813fb84624166f034e25234f98de5846bfc Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 7 Oct 2006 21:54:55 +0200 Subject: Driver core: allow to delay the uevent at device creation time For the block subsystem, we want to delay all uevents until the disk has been scanned and allpartitons are already created before the first event is sent out. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 3 ++- include/linux/device.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/core.c b/drivers/base/core.c index 34ac18778d8a..e13614241c9e 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -589,7 +589,8 @@ int device_add(struct device *dev) goto PMError; if ((error = bus_add_device(dev))) goto BusError; - kobject_uevent(&dev->kobj, KOBJ_ADD); + if (!dev->uevent_suppress) + kobject_uevent(&dev->kobj, KOBJ_ADD); if ((error = bus_attach_device(dev))) goto AttachError; if (parent) diff --git a/include/linux/device.h b/include/linux/device.h index e1e164f81eea..5ca1cdba563a 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -399,9 +399,10 @@ struct device { /* class_device migration path */ struct list_head node; - struct class *class; /* optional*/ + struct class *class; dev_t devt; /* dev_t, creates the sysfs "dev" */ struct attribute_group **groups; /* optional groups */ + int uevent_suppress; void (*release)(struct device * dev); }; -- cgit v1.2.3 From b592fcfe7f06c15ec11774b5be7ce0de3aa86e73 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 24 Jan 2007 12:35:52 -0700 Subject: sysfs: Shadow directory support The problem. When implementing a network namespace I need to be able to have multiple network devices with the same name. Currently this is a problem for /sys/class/net/*. What I want is a separate /sys/class/net directory in sysfs for each network namespace, and I want to name each of them /sys/class/net. I looked and the VFS actually allows that. All that is needed is for /sys/class/net to implement a follow link method to redirect lookups to the real directory you want. Implementing a follow link method that is sensitive to the current network namespace turns out to be 3 lines of code so it looks like a clean approach. Modifying sysfs so it doesn't get in my was is a bit trickier. I am calling the concept of multiple directories all at the same path in the filesystem shadow directories. With the directory entry really at that location the shadow master. The following patch modifies sysfs so it can handle a directory structure slightly different from the kobject tree so I can implement the shadow directories for handling /sys/class/net/. Signed-off-by: Eric W. Biederman Cc: Maneesh Soni Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 207 ++++++++++++++++++++++++++++++++++++++++-------- fs/sysfs/group.c | 1 + fs/sysfs/inode.c | 10 +++ fs/sysfs/mount.c | 2 +- fs/sysfs/sysfs.h | 5 ++ include/linux/kobject.h | 4 + include/linux/sysfs.h | 23 +++++- lib/kobject.c | 42 ++++++++-- 8 files changed, 249 insertions(+), 45 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 9ff04491e3ea..9dcdf556c99c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -33,8 +33,7 @@ static struct dentry_operations sysfs_dentry_ops = { /* * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent */ -static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd, - void * element) +static struct sysfs_dirent * __sysfs_new_dirent(void * element) { struct sysfs_dirent * sd; @@ -46,12 +45,28 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd, atomic_set(&sd->s_count, 1); atomic_set(&sd->s_event, 1); INIT_LIST_HEAD(&sd->s_children); - list_add(&sd->s_sibling, &parent_sd->s_children); + INIT_LIST_HEAD(&sd->s_sibling); sd->s_element = element; return sd; } +static void __sysfs_list_dirent(struct sysfs_dirent *parent_sd, + struct sysfs_dirent *sd) +{ + if (sd) + list_add(&sd->s_sibling, &parent_sd->s_children); +} + +static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent *parent_sd, + void * element) +{ + struct sysfs_dirent *sd; + sd = __sysfs_new_dirent(element); + __sysfs_list_dirent(parent_sd, sd); + return sd; +} + /* * * Return -EEXIST if there is already a sysfs element with the same name for @@ -78,14 +93,14 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd, } -int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, - void * element, umode_t mode, int type) +static struct sysfs_dirent * +__sysfs_make_dirent(struct dentry *dentry, void *element, mode_t mode, int type) { struct sysfs_dirent * sd; - sd = sysfs_new_dirent(parent_sd, element); + sd = __sysfs_new_dirent(element); if (!sd) - return -ENOMEM; + goto out; sd->s_mode = mode; sd->s_type = type; @@ -95,7 +110,19 @@ int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, dentry->d_op = &sysfs_dentry_ops; } - return 0; +out: + return sd; +} + +int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, + void * element, umode_t mode, int type) +{ + struct sysfs_dirent *sd; + + sd = __sysfs_make_dirent(dentry, element, mode, type); + __sysfs_list_dirent(parent_sd, sd); + + return sd ? 0 : -ENOMEM; } static int init_dir(struct inode * inode) @@ -166,11 +193,11 @@ int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d) /** * sysfs_create_dir - create a directory for an object. - * @parent: parent parent object. * @kobj: object we're creating directory for. + * @shadow_parent: parent parent object. */ -int sysfs_create_dir(struct kobject * kobj) +int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent) { struct dentry * dentry = NULL; struct dentry * parent; @@ -178,7 +205,9 @@ int sysfs_create_dir(struct kobject * kobj) BUG_ON(!kobj); - if (kobj->parent) + if (shadow_parent) + parent = shadow_parent; + else if (kobj->parent) parent = kobj->parent->dentry; else if (sysfs_mount && sysfs_mount->mnt_sb) parent = sysfs_mount->mnt_sb->s_root; @@ -299,21 +328,12 @@ void sysfs_remove_subdir(struct dentry * d) } -/** - * sysfs_remove_dir - remove an object's directory. - * @kobj: object. - * - * 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_dir(struct kobject * kobj) +static void __sysfs_remove_dir(struct dentry *dentry) { - struct dentry * dentry = dget(kobj->dentry); struct sysfs_dirent * parent_sd; struct sysfs_dirent * sd, * tmp; + dget(dentry); if (!dentry) return; @@ -334,32 +354,60 @@ void sysfs_remove_dir(struct kobject * kobj) * Drop reference from dget() on entrance. */ dput(dentry); +} + +/** + * sysfs_remove_dir - remove an object's directory. + * @kobj: object. + * + * 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_dir(struct kobject * kobj) +{ + __sysfs_remove_dir(kobj->dentry); kobj->dentry = NULL; } -int sysfs_rename_dir(struct kobject * kobj, const char *new_name) +int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent, + const char *new_name) { int error = 0; - struct dentry * new_dentry, * parent; + struct dentry * new_dentry; - if (!strcmp(kobject_name(kobj), new_name)) - return -EINVAL; - - if (!kobj->parent) - return -EINVAL; + if (!new_parent) + return -EFAULT; down_write(&sysfs_rename_sem); - parent = kobj->parent->dentry; + mutex_lock(&new_parent->d_inode->i_mutex); - mutex_lock(&parent->d_inode->i_mutex); - - new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); + new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name)); if (!IS_ERR(new_dentry)) { - if (!new_dentry->d_inode) { + /* By allowing two different directories with the + * same d_parent we allow this routine to move + * between different shadows of the same directory + */ + if (kobj->dentry->d_parent->d_inode != new_parent->d_inode) + return -EINVAL; + else if (new_dentry->d_parent->d_inode != new_parent->d_inode) + error = -EINVAL; + else if (new_dentry == kobj->dentry) + error = -EINVAL; + else if (!new_dentry->d_inode) { error = kobject_set_name(kobj, "%s", new_name); if (!error) { + struct sysfs_dirent *sd, *parent_sd; + d_add(new_dentry, NULL); d_move(kobj->dentry, new_dentry); + + sd = kobj->dentry->d_fsdata; + parent_sd = new_parent->d_fsdata; + + list_del_init(&sd->s_sibling); + list_add(&sd->s_sibling, &parent_sd->s_children); } else d_drop(new_dentry); @@ -367,7 +415,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) error = -EEXIST; dput(new_dentry); } - mutex_unlock(&parent->d_inode->i_mutex); + mutex_unlock(&new_parent->d_inode->i_mutex); up_write(&sysfs_rename_sem); return error; @@ -546,6 +594,95 @@ 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 inode *inode; + struct inode_operations *i_op; + + inode = kobj->dentry->d_inode; + if (inode->i_op != &sysfs_dir_inode_operations) + 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 dentry *sysfs_create_shadow_dir(struct kobject *kobj) +{ + struct sysfs_dirent *sd; + struct dentry *parent, *dir, *shadow; + struct inode *inode; + + dir = kobj->dentry; + inode = dir->d_inode; + parent = dir->d_parent; + shadow = ERR_PTR(-EINVAL); + if (!sysfs_is_shadowed_inode(inode)) + goto out; + + shadow = d_alloc(parent, &dir->d_name); + if (!shadow) + goto nomem; + + sd = __sysfs_make_dirent(shadow, kobj, inode->i_mode, SYSFS_DIR); + if (!sd) + goto nomem; + + d_instantiate(shadow, igrab(inode)); + inc_nlink(inode); + inc_nlink(parent->d_inode); + shadow->d_op = &sysfs_dentry_ops; + + dget(shadow); /* Extra count - pin the dentry in core */ + +out: + return shadow; +nomem: + dput(shadow); + shadow = ERR_PTR(-ENOMEM); + goto out; +} + +/** + * sysfs_remove_shadow_dir - remove an object's directory. + * @shadow: dentry 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 dentry *shadow) +{ + __sysfs_remove_dir(shadow); +} + 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 46a277b0838e..b20951c93761 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "sysfs.h" diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index dbd820f9aeed..542d2bcc73df 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -33,6 +33,16 @@ static 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 a1a58b97f322..f6a87a824883 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -23,7 +23,7 @@ static void sysfs_clear_inode(struct inode *inode); static struct super_operations sysfs_ops = { .statfs = simple_statfs, - .drop_inode = generic_delete_inode, + .drop_inode = sysfs_delete_inode, .clear_inode = sysfs_clear_inode, }; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 39c623fdc277..fe1cbfd208ed 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -2,6 +2,7 @@ extern struct vfsmount * sysfs_mount; extern struct kmem_cache *sysfs_dir_cachep; +extern void sysfs_delete_inode(struct inode *inode); extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); @@ -112,3 +113,7 @@ static inline void sysfs_put(struct sysfs_dirent * sd) 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 76538fcf2c4e..b850e0310538 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -74,9 +74,13 @@ 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 *, struct dentry *); 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 dentry *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 eee485957c0c..192de3afa96b 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -16,6 +16,7 @@ struct kobject; struct module; +struct nameidata; struct attribute { const char * name; @@ -89,13 +90,13 @@ struct sysfs_dirent { #ifdef CONFIG_SYSFS extern int __must_check -sysfs_create_dir(struct kobject *); +sysfs_create_dir(struct kobject *, struct dentry *); extern void sysfs_remove_dir(struct kobject *); extern int __must_check -sysfs_rename_dir(struct kobject *, const char *new_name); +sysfs_rename_dir(struct kobject *, struct dentry *, const char *new_name); extern int __must_check sysfs_move_dir(struct kobject *, struct kobject *); @@ -127,11 +128,17 @@ int __must_check sysfs_create_group(struct kobject *, void sysfs_remove_group(struct kobject *, const struct attribute_group *); 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 dentry *sysfs_create_shadow_dir(struct kobject *kobj); +extern void sysfs_remove_shadow_dir(struct dentry *dir); + extern int __must_check sysfs_init(void); #else /* CONFIG_SYSFS */ -static inline int sysfs_create_dir(struct kobject * k) +static inline int sysfs_create_dir(struct kobject * k, struct dentry *shadow) { return 0; } @@ -141,7 +148,9 @@ static inline void sysfs_remove_dir(struct kobject * k) ; } -static inline int sysfs_rename_dir(struct kobject * k, const char *new_name) +static inline int sysfs_rename_dir(struct kobject * k, + struct dentry *new_parent, + const char *new_name) { return 0; } @@ -205,6 +214,12 @@ 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 74b8dbca150e..c2917ffe8bf1 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) +static int create_dir(struct kobject * kobj, struct dentry *shadow_parent) { int error = 0; if (kobject_name(kobj)) { - error = sysfs_create_dir(kobj); + error = sysfs_create_dir(kobj, shadow_parent); if (!error) { if ((error = populate_dir(kobj))) sysfs_remove_dir(kobj); @@ -158,9 +158,10 @@ static void unlink(struct kobject * kobj) /** * kobject_add - add an object to the hierarchy. * @kobj: object. + * @shadow_parent: sysfs directory to add to. */ -int kobject_add(struct kobject * kobj) +int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent) { int error = 0; struct kobject * parent; @@ -191,7 +192,7 @@ int kobject_add(struct kobject * kobj) } kobj->parent = parent; - error = create_dir(kobj); + error = create_dir(kobj, shadow_parent); if (error) { /* unlink does the kobject_put() for us */ unlink(kobj); @@ -212,6 +213,15 @@ int kobject_add(struct kobject * kobj) 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. @@ -304,7 +314,29 @@ int kobject_rename(struct kobject * kobj, const char *new_name) kobj = kobject_get(kobj); if (!kobj) return -EINVAL; - error = sysfs_rename_dir(kobj, new_name); + if (!kobj->parent) + return -EINVAL; + error = sysfs_rename_dir(kobj, kobj->parent->dentry, new_name); + kobject_put(kobj); + + return error; +} + +/** + * kobject_rename - change the name of an object + * @kobj: object in question. + * @new_name: object's new name + */ + +int kobject_shadow_rename(struct kobject * kobj, struct dentry *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; -- cgit v1.2.3 From 7bc3d635628db100c024aca7f836a18188e9bb62 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 19 Jun 2006 23:59:31 -0700 Subject: USB: move usb_device_class class devices to be real devices This moves the usb class devices that control the usbfs nodes to show up in the proper place in the larger device tree. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 24 ++++++++++++------------ include/linux/usb.h | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 4b3a6ab29bd3..74be846fc029 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -522,19 +522,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig static struct usb_device *usbdev_lookup_minor(int minor) { - struct class_device *class_dev; - struct usb_device *dev = NULL; + struct device *device; + struct usb_device *udev = NULL; down(&usb_device_class->sem); - list_for_each_entry(class_dev, &usb_device_class->children, node) { - if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { - dev = class_dev->class_data; + list_for_each_entry(device, &usb_device_class->devices, node) { + if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { + udev = device->platform_data; break; } } up(&usb_device_class->sem); - return dev; + return udev; }; /* @@ -1596,19 +1596,19 @@ static int usbdev_add(struct usb_device *dev) { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); - dev->class_dev = class_device_create(usb_device_class, NULL, - MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, + dev->usbfs_dev = device_create(usb_device_class, &dev->dev, + MKDEV(USB_DEVICE_MAJOR, minor), "usbdev%d.%d", dev->bus->busnum, dev->devnum); - if (IS_ERR(dev->class_dev)) - return PTR_ERR(dev->class_dev); + if (IS_ERR(dev->usbfs_dev)) + return PTR_ERR(dev->usbfs_dev); - dev->class_dev->class_data = dev; + dev->usbfs_dev->platform_data = dev; return 0; } static void usbdev_remove(struct usb_device *dev) { - class_device_unregister(dev->class_dev); + device_unregister(dev->usbfs_dev); } static int usbdev_notify(struct notifier_block *self, unsigned long action, diff --git a/include/linux/usb.h b/include/linux/usb.h index aab5b1b72021..f18ced001924 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -372,7 +372,7 @@ struct usb_device { char *serial; /* iSerialNumber string, if present */ struct list_head filelist; - struct class_device *class_dev; + struct device *usbfs_dev; struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ /* -- cgit v1.2.3 From 0873c76485c126a4df70a6961fd354b21b7987f7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 20 Jun 2006 13:09:50 -0700 Subject: USB: convert usb class devices to real devices Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/file.c | 13 ++++++------- include/linux/usb.h | 5 +++-- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index f794f07cfb33..01c857ac27af 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -194,14 +194,13 @@ int usb_register_dev(struct usb_interface *intf, ++temp; else temp = name; - intf->class_dev = class_device_create(usb_class->class, NULL, - MKDEV(USB_MAJOR, minor), - &intf->dev, "%s", temp); - if (IS_ERR(intf->class_dev)) { + intf->usb_dev = device_create(usb_class->class, &intf->dev, + MKDEV(USB_MAJOR, minor), "%s", temp); + if (IS_ERR(intf->usb_dev)) { spin_lock (&minor_lock); usb_minors[intf->minor] = NULL; spin_unlock (&minor_lock); - retval = PTR_ERR(intf->class_dev); + retval = PTR_ERR(intf->usb_dev); } exit: return retval; @@ -242,8 +241,8 @@ void usb_deregister_dev(struct usb_interface *intf, spin_unlock (&minor_lock); snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); - class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); - intf->class_dev = NULL; + device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); + intf->usb_dev = NULL; intf->minor = -1; destroy_usb_class(); } diff --git a/include/linux/usb.h b/include/linux/usb.h index f18ced001924..d6bf1297d886 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -107,7 +107,8 @@ enum usb_interface_condition { * @needs_remote_wakeup: flag set when the driver requires remote-wakeup * capability during autosuspend. * @dev: driver model's view of this device - * @class_dev: driver model's class view of this device. + * @usb_dev: if an interface is bound to the USB major, this will point + * to the sysfs representation for that device. * @pm_usage_cnt: PM usage counter for this interface; autosuspend is not * allowed unless the counter is 0. * @@ -152,7 +153,7 @@ struct usb_interface { unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */ struct device dev; /* interface specific device info */ - struct class_device *class_dev; + struct device *usb_dev; /* pointer to the usb class's device, if any */ int pm_usage_cnt; /* usage counter for autosuspend */ }; #define to_usb_interface(d) container_of(d, struct usb_interface, dev) -- cgit v1.2.3 From 5f848137744106ee737f559454ce5adfceb38347 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sat, 16 Dec 2006 15:34:53 -0800 Subject: USB: becomes This moves to to reduce some of the clutter of usb header files. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/chips/isp1301_omap.c | 2 +- drivers/usb/atm/speedtch.c | 2 +- drivers/usb/gadget/at91_udc.c | 2 +- drivers/usb/gadget/config.c | 2 +- drivers/usb/gadget/epautoconf.c | 2 +- drivers/usb/gadget/ether.c | 2 +- drivers/usb/gadget/file_storage.c | 2 +- drivers/usb/gadget/gmidi.c | 2 +- drivers/usb/gadget/goku_udc.c | 2 +- drivers/usb/gadget/lh7a40x_udc.h | 2 +- drivers/usb/gadget/net2280.c | 2 +- drivers/usb/gadget/omap_udc.c | 2 +- drivers/usb/gadget/pxa2xx_udc.c | 2 +- drivers/usb/gadget/serial.c | 2 +- drivers/usb/gadget/usbstring.c | 2 +- drivers/usb/gadget/zero.c | 2 +- drivers/usb/storage/onetouch.c | 1 - include/linux/Kbuild | 2 +- include/linux/usb.h | 2 +- include/linux/usb/Kbuild | 5 + include/linux/usb/ch9.h | 562 ++++++++++++++++++++++++++++++++++++++ include/linux/usb_ch9.h | 562 -------------------------------------- include/linux/usb_gadgetfs.h | 2 +- 23 files changed, 586 insertions(+), 582 deletions(-) create mode 100644 include/linux/usb/Kbuild create mode 100644 include/linux/usb/ch9.h delete mode 100644 include/linux/usb_ch9.h (limited to 'include/linux') diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index ccdf3e90862b..9fafadb92510 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 8ed6c75adf0f..638b8009b3bc 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include "usbatm.h" diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 812c733ba8ce..5a72743606fd 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 83b4866df9af..d18901b92cda 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 53d584589c26..f28af06905a5 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index d15bf22b9a03..ca8e0ebc79e8 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -47,7 +47,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 72f2ae96fbf3..027b31505265 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -253,7 +253,7 @@ #include #include -#include +#include #include #include "gadget_chips.h" diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index f1a679656c96..d08a8d0e6427 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index d0ef1d6b3fac..e873cf488246 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h index e3bb78524c88..b3fe197e1eeb 100644 --- a/drivers/usb/gadget/lh7a40x_udc.h +++ b/drivers/usb/gadget/lh7a40x_udc.h @@ -49,7 +49,7 @@ #include #include -#include +#include #include /* diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 569eb8ccf232..7617ff7bd5ac 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -63,7 +63,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 cdcfd42843d4..140104341db4 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 b78de9694665..0d225369847d 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -56,7 +56,7 @@ #include #endif -#include +#include #include #include diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index f8a3ec64635d..6c742a909225 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -43,7 +43,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index b1735767660b..3459ea6c6c0b 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 40710ea1b490..ebe04e0d2879 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -84,7 +84,7 @@ #include #include -#include +#include #include #include "gadget_chips.h" diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index e565d3d2ab29..6d3dad3d1dae 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include "usb.h" #include "onetouch.h" diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 157db77a7170..683513e310de 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -11,6 +11,7 @@ header-y += netfilter_arp/ header-y += netfilter_bridge/ header-y += netfilter_ipv4/ header-y += netfilter_ipv6/ +header-y += usb/ header-y += affs_hardblocks.h header-y += aio_abi.h @@ -326,7 +327,6 @@ unifdef-y += udp.h unifdef-y += uinput.h unifdef-y += uio.h unifdef-y += unistd.h -unifdef-y += usb_ch9.h unifdef-y += usbdevice_fs.h unifdef-y += user.h unifdef-y += utsname.h diff --git a/include/linux/usb.h b/include/linux/usb.h index d6bf1297d886..f3b21636c9df 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -2,7 +2,7 @@ #define __LINUX_USB_H #include -#include +#include #define USB_MAJOR 180 #define USB_DEVICE_MAJOR 189 diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild new file mode 100644 index 000000000000..43f160cfe003 --- /dev/null +++ b/include/linux/usb/Kbuild @@ -0,0 +1,5 @@ +unifdef-y += audio.h +unifdef-y += cdc.h +unifdef-y += ch9.h +unifdef-y += midi.h + diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h new file mode 100644 index 000000000000..c720d107ff29 --- /dev/null +++ b/include/linux/usb/ch9.h @@ -0,0 +1,562 @@ +/* + * This file holds USB constants and structures that are needed for USB + * device APIs. These are used by the USB device model, which is defined + * in chapter 9 of the USB 2.0 specification. Linux has several APIs in C + * that need these: + * + * - the master/host side Linux-USB kernel driver API; + * - the "usbfs" user space API; and + * - the Linux "gadget" slave/device/peripheral side driver API. + * + * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems + * act either as a USB master/host or as a USB slave/device. That means + * the master and slave side APIs benefit from working well together. + * + * There's also "Wireless USB", using low power short range radios for + * peripheral interconnection but otherwise building on the USB framework. + */ + +#ifndef __LINUX_USB_CH9_H +#define __LINUX_USB_CH9_H + +#include /* __u8 etc */ + +/*-------------------------------------------------------------------------*/ + +/* CONTROL REQUEST SUPPORT */ + +/* + * USB directions + * + * This bit flag is used in endpoint descriptors' bEndpointAddress field. + * It's also one of three fields in control requests bRequestType. + */ +#define USB_DIR_OUT 0 /* to device */ +#define USB_DIR_IN 0x80 /* to host */ + +/* + * USB types, the second of three bRequestType fields + */ +#define USB_TYPE_MASK (0x03 << 5) +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +/* + * USB recipients, the third of three bRequestType fields + */ +#define USB_RECIP_MASK 0x1f +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 +/* From Wireless USB 1.0 */ +#define USB_RECIP_PORT 0x04 +#define USB_RECIP_RPIPE 0x05 + +/* + * Standard requests, for the bRequest field of a SETUP packet. + * + * These are qualified by the bRequestType field, so that for example + * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved + * by a GET_STATUS request. + */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */ +#define USB_REQ_GET_ENCRYPTION 0x0E +#define USB_REQ_RPIPE_ABORT 0x0E +#define USB_REQ_SET_HANDSHAKE 0x0F +#define USB_REQ_RPIPE_RESET 0x0F +#define USB_REQ_GET_HANDSHAKE 0x10 +#define USB_REQ_SET_CONNECTION 0x11 +#define USB_REQ_SET_SECURITY_DATA 0x12 +#define USB_REQ_GET_SECURITY_DATA 0x13 +#define USB_REQ_SET_WUSB_DATA 0x14 +#define USB_REQ_LOOPBACK_DATA_WRITE 0x15 +#define USB_REQ_LOOPBACK_DATA_READ 0x16 +#define USB_REQ_SET_INTERFACE_DS 0x17 + +/* + * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and + * are read as a bit array returned by USB_REQ_GET_STATUS. (So there + * are at most sixteen features of each type.) + */ +#define USB_DEVICE_SELF_POWERED 0 /* (read only) */ +#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */ +#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */ +#define USB_DEVICE_BATTERY 2 /* (wireless) */ +#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */ +#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/ +#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */ +#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */ +#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */ + +#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ + + +/** + * struct usb_ctrlrequest - SETUP data for a USB device control request + * @bRequestType: matches the USB bmRequestType field + * @bRequest: matches the USB bRequest field + * @wValue: matches the USB wValue field (le16 byte order) + * @wIndex: matches the USB wIndex field (le16 byte order) + * @wLength: matches the USB wLength field (le16 byte order) + * + * This structure is used to send control requests to a USB device. It matches + * the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the + * USB spec for a fuller description of the different fields, and what they are + * used for. + * + * Note that the driver for any interface can issue control requests. + * For most devices, interfaces don't coordinate with each other, so + * such requests may be made at any time. + */ +struct usb_ctrlrequest { + __u8 bRequestType; + __u8 bRequest; + __le16 wValue; + __le16 wIndex; + __le16 wLength; +} __attribute__ ((packed)); + +/*-------------------------------------------------------------------------*/ + +/* + * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or + * (rarely) accepted by SET_DESCRIPTOR. + * + * Note that all multi-byte values here are encoded in little endian + * byte order "on the wire". But when exposed through Linux-USB APIs, + * they've been converted to cpu byte order. + */ + +/* + * Descriptor types ... USB 2.0 spec table 9.5 + */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE_QUALIFIER 0x06 +#define USB_DT_OTHER_SPEED_CONFIG 0x07 +#define USB_DT_INTERFACE_POWER 0x08 +/* these are from a minor usb 2.0 revision (ECN) */ +#define USB_DT_OTG 0x09 +#define USB_DT_DEBUG 0x0a +#define USB_DT_INTERFACE_ASSOCIATION 0x0b +/* these are from the Wireless USB spec */ +#define USB_DT_SECURITY 0x0c +#define USB_DT_KEY 0x0d +#define USB_DT_ENCRYPTION_TYPE 0x0e +#define USB_DT_BOS 0x0f +#define USB_DT_DEVICE_CAPABILITY 0x10 +#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11 +#define USB_DT_WIRE_ADAPTER 0x21 +#define USB_DT_RPIPE 0x22 + +/* conventional codes for class-specific descriptors */ +#define USB_DT_CS_DEVICE 0x21 +#define USB_DT_CS_CONFIG 0x22 +#define USB_DT_CS_STRING 0x23 +#define USB_DT_CS_INTERFACE 0x24 +#define USB_DT_CS_ENDPOINT 0x25 + +/* All standard descriptors have these 2 fields at the beginning */ +struct usb_descriptor_header { + __u8 bLength; + __u8 bDescriptorType; +} __attribute__ ((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE: Device descriptor */ +struct usb_device_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 bcdUSB; + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + __u8 bMaxPacketSize0; + __le16 idVendor; + __le16 idProduct; + __le16 bcdDevice; + __u8 iManufacturer; + __u8 iProduct; + __u8 iSerialNumber; + __u8 bNumConfigurations; +} __attribute__ ((packed)); + +#define USB_DT_DEVICE_SIZE 18 + + +/* + * Device and/or Interface Class codes + * as found in bDeviceClass or bInterfaceClass + * and defined by www.usb.org documents + */ +#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PHYSICAL 5 +#define USB_CLASS_STILL_IMAGE 6 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_CDC_DATA 0x0a +#define USB_CLASS_CSCID 0x0b /* chip+ smart card */ +#define USB_CLASS_CONTENT_SEC 0x0d /* content security */ +#define USB_CLASS_VIDEO 0x0e +#define USB_CLASS_WIRELESS_CONTROLLER 0xe0 +#define USB_CLASS_APP_SPEC 0xfe +#define USB_CLASS_VENDOR_SPEC 0xff + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_CONFIG: Configuration descriptor information. + * + * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the + * descriptor type is different. Highspeed-capable devices can look + * different depending on what speed they're currently running. Only + * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG + * descriptors. + */ +struct usb_config_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 wTotalLength; + __u8 bNumInterfaces; + __u8 bConfigurationValue; + __u8 iConfiguration; + __u8 bmAttributes; + __u8 bMaxPower; +} __attribute__ ((packed)); + +#define USB_DT_CONFIG_SIZE 9 + +/* from config descriptor bmAttributes */ +#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */ +#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */ +#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */ +#define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_STRING: String descriptor */ +struct usb_string_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 wData[1]; /* UTF-16LE encoded */ +} __attribute__ ((packed)); + +/* note that "string" zero is special, it holds language codes that + * the device supports, not Unicode characters. + */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_INTERFACE: Interface descriptor */ +struct usb_interface_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bInterfaceNumber; + __u8 bAlternateSetting; + __u8 bNumEndpoints; + __u8 bInterfaceClass; + __u8 bInterfaceSubClass; + __u8 bInterfaceProtocol; + __u8 iInterface; +} __attribute__ ((packed)); + +#define USB_DT_INTERFACE_SIZE 9 + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_ENDPOINT: Endpoint descriptor */ +struct usb_endpoint_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bEndpointAddress; + __u8 bmAttributes; + __le16 wMaxPacketSize; + __u8 bInterval; + + /* NOTE: these two are _only_ in audio endpoints. */ + /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ + __u8 bRefresh; + __u8 bSynchAddress; +} __attribute__ ((packed)); + +#define USB_DT_ENDPOINT_SIZE 7 +#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ + + +/* + * Endpoints + */ +#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ +#define USB_ENDPOINT_DIR_MASK 0x80 + +#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ +#define USB_ENDPOINT_XFER_CONTROL 0 +#define USB_ENDPOINT_XFER_ISOC 1 +#define USB_ENDPOINT_XFER_BULK 2 +#define USB_ENDPOINT_XFER_INT 3 +#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80 + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ +struct usb_qualifier_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 bcdUSB; + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + __u8 bMaxPacketSize0; + __u8 bNumConfigurations; + __u8 bRESERVED; +} __attribute__ ((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_OTG (from OTG 1.0a supplement) */ +struct usb_otg_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bmAttributes; /* support for HNP, SRP, etc */ +} __attribute__ ((packed)); + +/* from usb_otg_descriptor.bmAttributes */ +#define USB_OTG_SRP (1 << 0) +#define USB_OTG_HNP (1 << 1) /* swap host/device roles */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEBUG: for special highspeed devices, replacing serial console */ +struct usb_debug_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + /* bulk endpoints with 8 byte maxpacket */ + __u8 bDebugInEndpoint; + __u8 bDebugOutEndpoint; +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */ +struct usb_interface_assoc_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bFirstInterface; + __u8 bInterfaceCount; + __u8 bFunctionClass; + __u8 bFunctionSubClass; + __u8 bFunctionProtocol; + __u8 iFunction; +} __attribute__ ((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_SECURITY: group of wireless security descriptors, including + * encryption types available for setting up a CC/association. + */ +struct usb_security_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 wTotalLength; + __u8 bNumEncryptionTypes; +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_KEY: used with {GET,SET}_SECURITY_DATA; only public keys + * may be retrieved. + */ +struct usb_key_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 tTKID[3]; + __u8 bReserved; + __u8 bKeyData[0]; +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_ENCRYPTION_TYPE: bundled in DT_SECURITY groups */ +struct usb_encryption_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bEncryptionType; +#define USB_ENC_TYPE_UNSECURE 0 +#define USB_ENC_TYPE_WIRED 1 /* non-wireless mode */ +#define USB_ENC_TYPE_CCM_1 2 /* aes128/cbc session */ +#define USB_ENC_TYPE_RSA_1 3 /* rsa3072/sha1 auth */ + __u8 bEncryptionValue; /* use in SET_ENCRYPTION */ + __u8 bAuthKeyIndex; +}; + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_BOS: group of wireless capabilities */ +struct usb_bos_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 wTotalLength; + __u8 bNumDeviceCaps; +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE_CAPABILITY: grouped with BOS */ +struct usb_dev_cap_header { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDevCapabilityType; +}; + +#define USB_CAP_TYPE_WIRELESS_USB 1 + +struct usb_wireless_cap_descriptor { /* Ultra Wide Band */ + __u8 bLength; + __u8 bDescriptorType; + __u8 bDevCapabilityType; + + __u8 bmAttributes; +#define USB_WIRELESS_P2P_DRD (1 << 1) +#define USB_WIRELESS_BEACON_MASK (3 << 2) +#define USB_WIRELESS_BEACON_SELF (1 << 2) +#define USB_WIRELESS_BEACON_DIRECTED (2 << 2) +#define USB_WIRELESS_BEACON_NONE (3 << 2) + __le16 wPHYRates; /* bit rates, Mbps */ +#define USB_WIRELESS_PHY_53 (1 << 0) /* always set */ +#define USB_WIRELESS_PHY_80 (1 << 1) +#define USB_WIRELESS_PHY_107 (1 << 2) /* always set */ +#define USB_WIRELESS_PHY_160 (1 << 3) +#define USB_WIRELESS_PHY_200 (1 << 4) /* always set */ +#define USB_WIRELESS_PHY_320 (1 << 5) +#define USB_WIRELESS_PHY_400 (1 << 6) +#define USB_WIRELESS_PHY_480 (1 << 7) + __u8 bmTFITXPowerInfo; /* TFI power levels */ + __u8 bmFFITXPowerInfo; /* FFI power levels */ + __le16 bmBandGroup; + __u8 bReserved; +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with + * each endpoint descriptor for a wireless device + */ +struct usb_wireless_ep_comp_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bMaxBurst; + __u8 bMaxSequence; + __le16 wMaxStreamDelay; + __le16 wOverTheAirPacketSize; + __u8 bOverTheAirInterval; + __u8 bmCompAttributes; +#define USB_ENDPOINT_SWITCH_MASK 0x03 /* in bmCompAttributes */ +#define USB_ENDPOINT_SWITCH_NO 0 +#define USB_ENDPOINT_SWITCH_SWITCH 1 +#define USB_ENDPOINT_SWITCH_SCALE 2 +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless + * host and a device for connection set up, mutual authentication, and + * exchanging short lived session keys. The handshake depends on a CC. + */ +struct usb_handshake { + __u8 bMessageNumber; + __u8 bStatus; + __u8 tTKID[3]; + __u8 bReserved; + __u8 CDID[16]; + __u8 nonce[16]; + __u8 MIC[8]; +}; + +/*-------------------------------------------------------------------------*/ + +/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC). + * A CC may also be set up using non-wireless secure channels (including + * wired USB!), and some devices may support CCs with multiple hosts. + */ +struct usb_connection_context { + __u8 CHID[16]; /* persistent host id */ + __u8 CDID[16]; /* device id (unique w/in host context) */ + __u8 CK[16]; /* connection key */ +}; + +/*-------------------------------------------------------------------------*/ + +/* USB 2.0 defines three speeds, here's how Linux identifies them */ + +enum usb_device_speed { + USB_SPEED_UNKNOWN = 0, /* enumerating */ + USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ + USB_SPEED_HIGH, /* usb 2.0 */ + USB_SPEED_VARIABLE, /* wireless (usb 2.5) */ +}; + +enum usb_device_state { + /* NOTATTACHED isn't in the USB spec, and this state acts + * the same as ATTACHED ... but it's clearer this way. + */ + USB_STATE_NOTATTACHED = 0, + + /* chapter 9 and authentication (wireless) device states */ + USB_STATE_ATTACHED, + USB_STATE_POWERED, /* wired */ + USB_STATE_UNAUTHENTICATED, /* auth */ + USB_STATE_RECONNECTING, /* auth */ + USB_STATE_DEFAULT, /* limited function */ + USB_STATE_ADDRESS, + USB_STATE_CONFIGURED, /* most functions */ + + USB_STATE_SUSPENDED + + /* NOTE: there are actually four different SUSPENDED + * states, returning to POWERED, DEFAULT, ADDRESS, or + * CONFIGURED respectively when SOF tokens flow again. + */ +}; + +#endif /* __LINUX_USB_CH9_H */ diff --git a/include/linux/usb_ch9.h b/include/linux/usb_ch9.h deleted file mode 100644 index c720d107ff29..000000000000 --- a/include/linux/usb_ch9.h +++ /dev/null @@ -1,562 +0,0 @@ -/* - * This file holds USB constants and structures that are needed for USB - * device APIs. These are used by the USB device model, which is defined - * in chapter 9 of the USB 2.0 specification. Linux has several APIs in C - * that need these: - * - * - the master/host side Linux-USB kernel driver API; - * - the "usbfs" user space API; and - * - the Linux "gadget" slave/device/peripheral side driver API. - * - * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems - * act either as a USB master/host or as a USB slave/device. That means - * the master and slave side APIs benefit from working well together. - * - * There's also "Wireless USB", using low power short range radios for - * peripheral interconnection but otherwise building on the USB framework. - */ - -#ifndef __LINUX_USB_CH9_H -#define __LINUX_USB_CH9_H - -#include /* __u8 etc */ - -/*-------------------------------------------------------------------------*/ - -/* CONTROL REQUEST SUPPORT */ - -/* - * USB directions - * - * This bit flag is used in endpoint descriptors' bEndpointAddress field. - * It's also one of three fields in control requests bRequestType. - */ -#define USB_DIR_OUT 0 /* to device */ -#define USB_DIR_IN 0x80 /* to host */ - -/* - * USB types, the second of three bRequestType fields - */ -#define USB_TYPE_MASK (0x03 << 5) -#define USB_TYPE_STANDARD (0x00 << 5) -#define USB_TYPE_CLASS (0x01 << 5) -#define USB_TYPE_VENDOR (0x02 << 5) -#define USB_TYPE_RESERVED (0x03 << 5) - -/* - * USB recipients, the third of three bRequestType fields - */ -#define USB_RECIP_MASK 0x1f -#define USB_RECIP_DEVICE 0x00 -#define USB_RECIP_INTERFACE 0x01 -#define USB_RECIP_ENDPOINT 0x02 -#define USB_RECIP_OTHER 0x03 -/* From Wireless USB 1.0 */ -#define USB_RECIP_PORT 0x04 -#define USB_RECIP_RPIPE 0x05 - -/* - * Standard requests, for the bRequest field of a SETUP packet. - * - * These are qualified by the bRequestType field, so that for example - * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved - * by a GET_STATUS request. - */ -#define USB_REQ_GET_STATUS 0x00 -#define USB_REQ_CLEAR_FEATURE 0x01 -#define USB_REQ_SET_FEATURE 0x03 -#define USB_REQ_SET_ADDRESS 0x05 -#define USB_REQ_GET_DESCRIPTOR 0x06 -#define USB_REQ_SET_DESCRIPTOR 0x07 -#define USB_REQ_GET_CONFIGURATION 0x08 -#define USB_REQ_SET_CONFIGURATION 0x09 -#define USB_REQ_GET_INTERFACE 0x0A -#define USB_REQ_SET_INTERFACE 0x0B -#define USB_REQ_SYNCH_FRAME 0x0C - -#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */ -#define USB_REQ_GET_ENCRYPTION 0x0E -#define USB_REQ_RPIPE_ABORT 0x0E -#define USB_REQ_SET_HANDSHAKE 0x0F -#define USB_REQ_RPIPE_RESET 0x0F -#define USB_REQ_GET_HANDSHAKE 0x10 -#define USB_REQ_SET_CONNECTION 0x11 -#define USB_REQ_SET_SECURITY_DATA 0x12 -#define USB_REQ_GET_SECURITY_DATA 0x13 -#define USB_REQ_SET_WUSB_DATA 0x14 -#define USB_REQ_LOOPBACK_DATA_WRITE 0x15 -#define USB_REQ_LOOPBACK_DATA_READ 0x16 -#define USB_REQ_SET_INTERFACE_DS 0x17 - -/* - * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and - * are read as a bit array returned by USB_REQ_GET_STATUS. (So there - * are at most sixteen features of each type.) - */ -#define USB_DEVICE_SELF_POWERED 0 /* (read only) */ -#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */ -#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */ -#define USB_DEVICE_BATTERY 2 /* (wireless) */ -#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */ -#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/ -#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */ -#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */ -#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */ - -#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ - - -/** - * struct usb_ctrlrequest - SETUP data for a USB device control request - * @bRequestType: matches the USB bmRequestType field - * @bRequest: matches the USB bRequest field - * @wValue: matches the USB wValue field (le16 byte order) - * @wIndex: matches the USB wIndex field (le16 byte order) - * @wLength: matches the USB wLength field (le16 byte order) - * - * This structure is used to send control requests to a USB device. It matches - * the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the - * USB spec for a fuller description of the different fields, and what they are - * used for. - * - * Note that the driver for any interface can issue control requests. - * For most devices, interfaces don't coordinate with each other, so - * such requests may be made at any time. - */ -struct usb_ctrlrequest { - __u8 bRequestType; - __u8 bRequest; - __le16 wValue; - __le16 wIndex; - __le16 wLength; -} __attribute__ ((packed)); - -/*-------------------------------------------------------------------------*/ - -/* - * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or - * (rarely) accepted by SET_DESCRIPTOR. - * - * Note that all multi-byte values here are encoded in little endian - * byte order "on the wire". But when exposed through Linux-USB APIs, - * they've been converted to cpu byte order. - */ - -/* - * Descriptor types ... USB 2.0 spec table 9.5 - */ -#define USB_DT_DEVICE 0x01 -#define USB_DT_CONFIG 0x02 -#define USB_DT_STRING 0x03 -#define USB_DT_INTERFACE 0x04 -#define USB_DT_ENDPOINT 0x05 -#define USB_DT_DEVICE_QUALIFIER 0x06 -#define USB_DT_OTHER_SPEED_CONFIG 0x07 -#define USB_DT_INTERFACE_POWER 0x08 -/* these are from a minor usb 2.0 revision (ECN) */ -#define USB_DT_OTG 0x09 -#define USB_DT_DEBUG 0x0a -#define USB_DT_INTERFACE_ASSOCIATION 0x0b -/* these are from the Wireless USB spec */ -#define USB_DT_SECURITY 0x0c -#define USB_DT_KEY 0x0d -#define USB_DT_ENCRYPTION_TYPE 0x0e -#define USB_DT_BOS 0x0f -#define USB_DT_DEVICE_CAPABILITY 0x10 -#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11 -#define USB_DT_WIRE_ADAPTER 0x21 -#define USB_DT_RPIPE 0x22 - -/* conventional codes for class-specific descriptors */ -#define USB_DT_CS_DEVICE 0x21 -#define USB_DT_CS_CONFIG 0x22 -#define USB_DT_CS_STRING 0x23 -#define USB_DT_CS_INTERFACE 0x24 -#define USB_DT_CS_ENDPOINT 0x25 - -/* All standard descriptors have these 2 fields at the beginning */ -struct usb_descriptor_header { - __u8 bLength; - __u8 bDescriptorType; -} __attribute__ ((packed)); - - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_DEVICE: Device descriptor */ -struct usb_device_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __le16 bcdUSB; - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - __u8 bMaxPacketSize0; - __le16 idVendor; - __le16 idProduct; - __le16 bcdDevice; - __u8 iManufacturer; - __u8 iProduct; - __u8 iSerialNumber; - __u8 bNumConfigurations; -} __attribute__ ((packed)); - -#define USB_DT_DEVICE_SIZE 18 - - -/* - * Device and/or Interface Class codes - * as found in bDeviceClass or bInterfaceClass - * and defined by www.usb.org documents - */ -#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ -#define USB_CLASS_AUDIO 1 -#define USB_CLASS_COMM 2 -#define USB_CLASS_HID 3 -#define USB_CLASS_PHYSICAL 5 -#define USB_CLASS_STILL_IMAGE 6 -#define USB_CLASS_PRINTER 7 -#define USB_CLASS_MASS_STORAGE 8 -#define USB_CLASS_HUB 9 -#define USB_CLASS_CDC_DATA 0x0a -#define USB_CLASS_CSCID 0x0b /* chip+ smart card */ -#define USB_CLASS_CONTENT_SEC 0x0d /* content security */ -#define USB_CLASS_VIDEO 0x0e -#define USB_CLASS_WIRELESS_CONTROLLER 0xe0 -#define USB_CLASS_APP_SPEC 0xfe -#define USB_CLASS_VENDOR_SPEC 0xff - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_CONFIG: Configuration descriptor information. - * - * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the - * descriptor type is different. Highspeed-capable devices can look - * different depending on what speed they're currently running. Only - * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG - * descriptors. - */ -struct usb_config_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __le16 wTotalLength; - __u8 bNumInterfaces; - __u8 bConfigurationValue; - __u8 iConfiguration; - __u8 bmAttributes; - __u8 bMaxPower; -} __attribute__ ((packed)); - -#define USB_DT_CONFIG_SIZE 9 - -/* from config descriptor bmAttributes */ -#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */ -#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */ -#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */ -#define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */ - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_STRING: String descriptor */ -struct usb_string_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __le16 wData[1]; /* UTF-16LE encoded */ -} __attribute__ ((packed)); - -/* note that "string" zero is special, it holds language codes that - * the device supports, not Unicode characters. - */ - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_INTERFACE: Interface descriptor */ -struct usb_interface_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u8 bInterfaceNumber; - __u8 bAlternateSetting; - __u8 bNumEndpoints; - __u8 bInterfaceClass; - __u8 bInterfaceSubClass; - __u8 bInterfaceProtocol; - __u8 iInterface; -} __attribute__ ((packed)); - -#define USB_DT_INTERFACE_SIZE 9 - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_ENDPOINT: Endpoint descriptor */ -struct usb_endpoint_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u8 bEndpointAddress; - __u8 bmAttributes; - __le16 wMaxPacketSize; - __u8 bInterval; - - /* NOTE: these two are _only_ in audio endpoints. */ - /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ - __u8 bRefresh; - __u8 bSynchAddress; -} __attribute__ ((packed)); - -#define USB_DT_ENDPOINT_SIZE 7 -#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ - - -/* - * Endpoints - */ -#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ -#define USB_ENDPOINT_DIR_MASK 0x80 - -#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ -#define USB_ENDPOINT_XFER_CONTROL 0 -#define USB_ENDPOINT_XFER_ISOC 1 -#define USB_ENDPOINT_XFER_BULK 2 -#define USB_ENDPOINT_XFER_INT 3 -#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80 - - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ -struct usb_qualifier_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __le16 bcdUSB; - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - __u8 bMaxPacketSize0; - __u8 bNumConfigurations; - __u8 bRESERVED; -} __attribute__ ((packed)); - - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_OTG (from OTG 1.0a supplement) */ -struct usb_otg_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u8 bmAttributes; /* support for HNP, SRP, etc */ -} __attribute__ ((packed)); - -/* from usb_otg_descriptor.bmAttributes */ -#define USB_OTG_SRP (1 << 0) -#define USB_OTG_HNP (1 << 1) /* swap host/device roles */ - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_DEBUG: for special highspeed devices, replacing serial console */ -struct usb_debug_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - /* bulk endpoints with 8 byte maxpacket */ - __u8 bDebugInEndpoint; - __u8 bDebugOutEndpoint; -}; - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */ -struct usb_interface_assoc_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u8 bFirstInterface; - __u8 bInterfaceCount; - __u8 bFunctionClass; - __u8 bFunctionSubClass; - __u8 bFunctionProtocol; - __u8 iFunction; -} __attribute__ ((packed)); - - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_SECURITY: group of wireless security descriptors, including - * encryption types available for setting up a CC/association. - */ -struct usb_security_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __le16 wTotalLength; - __u8 bNumEncryptionTypes; -}; - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_KEY: used with {GET,SET}_SECURITY_DATA; only public keys - * may be retrieved. - */ -struct usb_key_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u8 tTKID[3]; - __u8 bReserved; - __u8 bKeyData[0]; -}; - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_ENCRYPTION_TYPE: bundled in DT_SECURITY groups */ -struct usb_encryption_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u8 bEncryptionType; -#define USB_ENC_TYPE_UNSECURE 0 -#define USB_ENC_TYPE_WIRED 1 /* non-wireless mode */ -#define USB_ENC_TYPE_CCM_1 2 /* aes128/cbc session */ -#define USB_ENC_TYPE_RSA_1 3 /* rsa3072/sha1 auth */ - __u8 bEncryptionValue; /* use in SET_ENCRYPTION */ - __u8 bAuthKeyIndex; -}; - - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_BOS: group of wireless capabilities */ -struct usb_bos_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __le16 wTotalLength; - __u8 bNumDeviceCaps; -}; - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_DEVICE_CAPABILITY: grouped with BOS */ -struct usb_dev_cap_header { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; -}; - -#define USB_CAP_TYPE_WIRELESS_USB 1 - -struct usb_wireless_cap_descriptor { /* Ultra Wide Band */ - __u8 bLength; - __u8 bDescriptorType; - __u8 bDevCapabilityType; - - __u8 bmAttributes; -#define USB_WIRELESS_P2P_DRD (1 << 1) -#define USB_WIRELESS_BEACON_MASK (3 << 2) -#define USB_WIRELESS_BEACON_SELF (1 << 2) -#define USB_WIRELESS_BEACON_DIRECTED (2 << 2) -#define USB_WIRELESS_BEACON_NONE (3 << 2) - __le16 wPHYRates; /* bit rates, Mbps */ -#define USB_WIRELESS_PHY_53 (1 << 0) /* always set */ -#define USB_WIRELESS_PHY_80 (1 << 1) -#define USB_WIRELESS_PHY_107 (1 << 2) /* always set */ -#define USB_WIRELESS_PHY_160 (1 << 3) -#define USB_WIRELESS_PHY_200 (1 << 4) /* always set */ -#define USB_WIRELESS_PHY_320 (1 << 5) -#define USB_WIRELESS_PHY_400 (1 << 6) -#define USB_WIRELESS_PHY_480 (1 << 7) - __u8 bmTFITXPowerInfo; /* TFI power levels */ - __u8 bmFFITXPowerInfo; /* FFI power levels */ - __le16 bmBandGroup; - __u8 bReserved; -}; - -/*-------------------------------------------------------------------------*/ - -/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with - * each endpoint descriptor for a wireless device - */ -struct usb_wireless_ep_comp_descriptor { - __u8 bLength; - __u8 bDescriptorType; - - __u8 bMaxBurst; - __u8 bMaxSequence; - __le16 wMaxStreamDelay; - __le16 wOverTheAirPacketSize; - __u8 bOverTheAirInterval; - __u8 bmCompAttributes; -#define USB_ENDPOINT_SWITCH_MASK 0x03 /* in bmCompAttributes */ -#define USB_ENDPOINT_SWITCH_NO 0 -#define USB_ENDPOINT_SWITCH_SWITCH 1 -#define USB_ENDPOINT_SWITCH_SCALE 2 -}; - -/*-------------------------------------------------------------------------*/ - -/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless - * host and a device for connection set up, mutual authentication, and - * exchanging short lived session keys. The handshake depends on a CC. - */ -struct usb_handshake { - __u8 bMessageNumber; - __u8 bStatus; - __u8 tTKID[3]; - __u8 bReserved; - __u8 CDID[16]; - __u8 nonce[16]; - __u8 MIC[8]; -}; - -/*-------------------------------------------------------------------------*/ - -/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC). - * A CC may also be set up using non-wireless secure channels (including - * wired USB!), and some devices may support CCs with multiple hosts. - */ -struct usb_connection_context { - __u8 CHID[16]; /* persistent host id */ - __u8 CDID[16]; /* device id (unique w/in host context) */ - __u8 CK[16]; /* connection key */ -}; - -/*-------------------------------------------------------------------------*/ - -/* USB 2.0 defines three speeds, here's how Linux identifies them */ - -enum usb_device_speed { - USB_SPEED_UNKNOWN = 0, /* enumerating */ - USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ - USB_SPEED_HIGH, /* usb 2.0 */ - USB_SPEED_VARIABLE, /* wireless (usb 2.5) */ -}; - -enum usb_device_state { - /* NOTATTACHED isn't in the USB spec, and this state acts - * the same as ATTACHED ... but it's clearer this way. - */ - USB_STATE_NOTATTACHED = 0, - - /* chapter 9 and authentication (wireless) device states */ - USB_STATE_ATTACHED, - USB_STATE_POWERED, /* wired */ - USB_STATE_UNAUTHENTICATED, /* auth */ - USB_STATE_RECONNECTING, /* auth */ - USB_STATE_DEFAULT, /* limited function */ - USB_STATE_ADDRESS, - USB_STATE_CONFIGURED, /* most functions */ - - USB_STATE_SUSPENDED - - /* NOTE: there are actually four different SUSPENDED - * states, returning to POWERED, DEFAULT, ADDRESS, or - * CONFIGURED respectively when SOF tokens flow again. - */ -}; - -#endif /* __LINUX_USB_CH9_H */ diff --git a/include/linux/usb_gadgetfs.h b/include/linux/usb_gadgetfs.h index b53d6ae8e55e..8086d5a9b94e 100644 --- a/include/linux/usb_gadgetfs.h +++ b/include/linux/usb_gadgetfs.h @@ -2,7 +2,7 @@ #include #include -#include +#include /* * Filesystem based user-mode API to USB Gadget controller hardware -- cgit v1.2.3 From e7d8712c15e087ba6201e5988d618ee03dfe693c Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 12 Dec 2006 15:12:30 -0800 Subject: USB: define USB_CLASS_MISC in Add USB_CLASS_MISC to Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/ch9.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index c720d107ff29..ae7833749fa2 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -224,6 +224,7 @@ struct usb_device_descriptor { #define USB_CLASS_CONTENT_SEC 0x0d /* content security */ #define USB_CLASS_VIDEO 0x0e #define USB_CLASS_WIRELESS_CONTROLLER 0xe0 +#define USB_CLASS_MISC 0xef #define USB_CLASS_APP_SPEC 0xfe #define USB_CLASS_VENDOR_SPEC 0xff -- cgit v1.2.3 From 93bacefc4cc0b53e1cb6a336d43847154fdf6886 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 17 Dec 2006 21:50:23 +0100 Subject: USB serial: add dynamic id support to usb-serial core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to Johannes Hölzl for fixing a few things and getting it all working properly. This adds support for dynamic usb ids to the usb serial core. The file "new_id" will show up under the usb serial driver, not the usb driver associated with the usb-serial driver (yeah, it can be a bit confusing at first glance...) This patch also modifies the USB core to allow the usb-serial core to reuse much of the dynamic id logic. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Johannes Hölzl --- drivers/usb/core/driver.c | 35 +++++++++++++++++--------------- drivers/usb/serial/bus.c | 45 +++++++++++++++++++++++++++++++++++++++++ drivers/usb/serial/usb-serial.c | 41 ++++++++++++++++++++++++++++++++----- include/linux/usb.h | 12 +++++++++++ include/linux/usb/serial.h | 5 +++++ 5 files changed, 117 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d6eb5ce1dd1d..0c0c03a4e031 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -28,24 +28,16 @@ #include "hcd.h" #include "usb.h" -static int usb_match_one_id(struct usb_interface *interface, - const struct usb_device_id *id); - -struct usb_dynid { - struct list_head node; - struct usb_device_id id; -}; - #ifdef CONFIG_HOTPLUG /* * Adds a new dynamic USBdevice ID to this driver, * and cause the driver to probe for all devices again. */ -static ssize_t store_new_id(struct device_driver *driver, - const char *buf, size_t count) +ssize_t usb_store_new_id(struct usb_dynids *dynids, + struct device_driver *driver, + const char *buf, size_t count) { - struct usb_driver *usb_drv = to_usb_driver(driver); struct usb_dynid *dynid; u32 idVendor = 0; u32 idProduct = 0; @@ -65,9 +57,9 @@ static ssize_t store_new_id(struct device_driver *driver, dynid->id.idProduct = idProduct; dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE; - spin_lock(&usb_drv->dynids.lock); - list_add_tail(&usb_drv->dynids.list, &dynid->node); - spin_unlock(&usb_drv->dynids.lock); + spin_lock(&dynids->lock); + list_add_tail(&dynids->list, &dynid->node); + spin_unlock(&dynids->lock); if (get_driver(driver)) { retval = driver_attach(driver); @@ -78,6 +70,15 @@ static ssize_t store_new_id(struct device_driver *driver, return retval; return count; } +EXPORT_SYMBOL_GPL(usb_store_new_id); + +static ssize_t store_new_id(struct device_driver *driver, + const char *buf, size_t count) +{ + struct usb_driver *usb_drv = to_usb_driver(driver); + + return usb_store_new_id(&usb_drv->dynids, driver, buf, count); +} static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); static int usb_create_newid_file(struct usb_driver *usb_drv) @@ -365,8 +366,8 @@ void usb_driver_release_interface(struct usb_driver *driver, EXPORT_SYMBOL(usb_driver_release_interface); /* returns 0 if no match, 1 if match */ -static int usb_match_one_id(struct usb_interface *interface, - const struct usb_device_id *id) +int usb_match_one_id(struct usb_interface *interface, + const struct usb_device_id *id) { struct usb_host_interface *intf; struct usb_device *dev; @@ -432,6 +433,8 @@ static int usb_match_one_id(struct usb_interface *interface, return 1; } +EXPORT_SYMBOL_GPL(usb_match_one_id); + /** * usb_match_id - find first usb_device_id matching device or interface * @interface: the interface of interest diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 6542f220468f..c08a38402b93 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -103,11 +103,52 @@ exit: return retval; } +#ifdef CONFIG_HOTPLUG +static ssize_t store_new_id(struct device_driver *driver, + const char *buf, size_t count) +{ + struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver); + ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count); + + if (retval >= 0 && usb_drv->usb_driver != NULL) + retval = usb_store_new_id(&usb_drv->usb_driver->dynids, + &usb_drv->usb_driver->drvwrap.driver, + buf, count); + return retval; +} + +static struct driver_attribute drv_attrs[] = { + __ATTR(new_id, S_IWUSR, NULL, store_new_id), + __ATTR_NULL, +}; + +static void free_dynids(struct usb_serial_driver *drv) +{ + struct usb_dynid *dynid, *n; + + spin_lock(&drv->dynids.lock); + list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { + list_del(&dynid->node); + kfree(dynid); + } + spin_unlock(&drv->dynids.lock); +} + +#else +static struct driver_attribute drv_attrs[] = { + __ATTR_NULL, +}; +static inline void free_dynids(struct usb_driver *drv) +{ +} +#endif + struct bus_type usb_serial_bus_type = { .name = "usb-serial", .match = usb_serial_device_match, .probe = usb_serial_device_probe, .remove = usb_serial_device_remove, + .drv_attrs = drv_attrs, }; int usb_serial_bus_register(struct usb_serial_driver *driver) @@ -115,6 +156,9 @@ int usb_serial_bus_register(struct usb_serial_driver *driver) int retval; driver->driver.bus = &usb_serial_bus_type; + spin_lock_init(&driver->dynids.lock); + INIT_LIST_HEAD(&driver->dynids.list); + retval = driver_register(&driver->driver); return retval; @@ -122,6 +166,7 @@ int usb_serial_bus_register(struct usb_serial_driver *driver) void usb_serial_bus_deregister(struct usb_serial_driver *driver) { + free_dynids(driver); driver_unregister(&driver->driver); } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 716f6806cc89..90beb5c50e59 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -596,6 +596,39 @@ static struct usb_serial * create_serial (struct usb_device *dev, return serial; } +static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf, + struct usb_serial_driver *drv) +{ + struct usb_dynid *dynid; + + spin_lock(&drv->dynids.lock); + list_for_each_entry(dynid, &drv->dynids.list, node) { + if (usb_match_one_id(intf, &dynid->id)) { + spin_unlock(&drv->dynids.lock); + return &dynid->id; + } + } + spin_unlock(&drv->dynids.lock); + return NULL; +} + +static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv, + struct usb_interface *intf) +{ + const struct usb_device_id *id; + + id = usb_match_id(intf, drv->id_table); + if (id) { + dbg("static descriptor matches"); + goto exit; + } + id = match_dynamic_id(intf, drv); + if (id) + dbg("dynamic descriptor matches"); +exit: + return id; +} + static struct usb_serial_driver *search_serial_device(struct usb_interface *iface) { struct list_head *p; @@ -605,11 +638,9 @@ static struct usb_serial_driver *search_serial_device(struct usb_interface *ifac /* 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 = usb_match_id(iface, t->id_table); - if (id != NULL) { - dbg("descriptor matches"); + id = get_iface_id(t, iface); + if (id) return t; - } } return NULL; @@ -661,7 +692,7 @@ int usb_serial_probe(struct usb_interface *interface, return -EIO; } - id = usb_match_id(interface, type->id_table); + id = get_iface_id(type, interface); retval = type->probe(serial, id); module_put(type->driver.owner); diff --git a/include/linux/usb.h b/include/linux/usb.h index f3b21636c9df..3cb9285df2d1 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -476,6 +476,8 @@ extern void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface); const struct usb_device_id *usb_match_id(struct usb_interface *interface, const struct usb_device_id *id); +extern int usb_match_one_id(struct usb_interface *interface, + const struct usb_device_id *id); extern struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor); @@ -724,11 +726,21 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor /* ----------------------------------------------------------------------- */ +/* Stuff for dynamic usb ids */ struct usb_dynids { spinlock_t lock; struct list_head list; }; +struct usb_dynid { + struct list_head node; + struct usb_device_id id; +}; + +extern ssize_t usb_store_new_id(struct usb_dynids *dynids, + struct device_driver *driver, + const char *buf, size_t count); + /** * struct usbdrv_wrap - wrapper for driver-model structure * @driver: The driver-model core driver structure. diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 10f99e5f1a97..33dcd8576696 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -179,6 +179,9 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data) * memory structure allocation at this point in time. * @shutdown: pointer to the driver's shutdown function. This will be * called when the device is removed from the system. + * @usb_driver: pointer to the struct usb_driver that controls this + * device. This is necessary to allow dynamic ids to be added to + * the driver from sysfs. * * This structure is defines a USB Serial driver. It provides all of * the information that the USB serial core code needs. If the function @@ -202,6 +205,8 @@ struct usb_serial_driver { struct list_head driver_list; struct device_driver driver; + struct usb_driver *usb_driver; + struct usb_dynids dynids; int (*probe) (struct usb_serial *serial, const struct usb_device_id *id); int (*attach) (struct usb_serial *serial); -- cgit v1.2.3 From a8ef36bc0a5fe973bddaa54a5a07cda29e04a602 Mon Sep 17 00:00:00 2001 From: Sarah Bailey Date: Sat, 23 Dec 2006 23:14:58 -0800 Subject: USB: Add usb_endpoint_xfer_control to usb.h Added a function to check if an endpoint is a control endpoint. There were similar functions for bulk, interrupt, and isoc, but not for control endpoints. Signed-off-by: Sarah Bailey Signed-off-by: Greg Kroah-Hartman --- include/linux/usb.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'include/linux') diff --git a/include/linux/usb.h b/include/linux/usb.h index 3cb9285df2d1..1c56386de709 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -556,6 +556,18 @@ static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *e USB_ENDPOINT_XFER_BULK); } +/** + * usb_endpoint_xfer_control - check if the endpoint has control transfer type + * @epd: endpoint to be checked + * + * Returns true if the endpoint is of type control, otherwise it returns false. + */ +static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd) +{ + return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_CONTROL); +} + /** * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type * @epd: endpoint to be checked -- cgit v1.2.3 From 4a1a4d8b87389e35c3af04c0d0a95f6a0391b964 Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Mon, 15 Jan 2007 20:11:52 -0800 Subject: USB: ps3 controller hid quirk Add the USB HID quirk HID_QUIRK_SONY_PS3_CONTROLLER. This sends an HID_REQ_GET_REPORT to the the PS3 controller to put the device into 'operational mode'. Signed-off-by: Geoff Levand Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/input/hid-core.c | 35 +++++++++++++++++++++++++++++++++++ include/linux/hid.h | 1 + 2 files changed, 36 insertions(+) (limited to 'include/linux') diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index e07a30490726..84983d1b7164 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -768,6 +768,9 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_PANTHERLORD 0x0810 #define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001 +#define USB_VENDOR_ID_SONY 0x054c +#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 + /* * Alphabetically sorted blacklist by quirk type. */ @@ -949,6 +952,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, + { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER }, + { 0, 0 } }; @@ -1013,6 +1018,32 @@ static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize) } } +/* + * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller + * to "operational". Without this, the ps3 controller will not report any + * events. + */ +static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum) +{ + int result; + char *buf = kmalloc(18, GFP_KERNEL); + + if (!buf) + return; + + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + HID_REQ_GET_REPORT, + USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, + (3 << 8) | 0xf2, ifnum, buf, 17, + USB_CTRL_GET_TIMEOUT); + + if (result < 0) + err("%s failed: %d\n", __func__, result); + + kfree(buf); +} + static struct hid_device *usb_hid_configure(struct usb_interface *intf) { struct usb_host_interface *interface = intf->cur_altsetting; @@ -1303,6 +1334,10 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) if ((hid->claimed & HID_CLAIMED_INPUT)) hid_ff_init(hid); + if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER) + hid_fixup_sony_ps3_controller(interface_to_usbdev(intf), + intf->cur_altsetting->desc.bInterfaceNumber); + printk(KERN_INFO); if (hid->claimed & HID_CLAIMED_INPUT) diff --git a/include/linux/hid.h b/include/linux/hid.h index 93173fe45634..d26b08f461f2 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -266,6 +266,7 @@ struct hid_item { #define HID_QUIRK_BAD_RELATIVE_KEYS 0x00010000 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00020000 #define HID_QUIRK_IGNORE_MOUSE 0x00040000 +#define HID_QUIRK_SONY_PS3_CONTROLLER 0x00080000 /* * This is the global environment of the parser. This information is -- cgit v1.2.3 From 896fbd7199035958013d106329843d8ae9618753 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 16 Jan 2007 11:57:13 -0500 Subject: usbcore: remove unused bandwith-related code This patch (as841) removes from usbcore a couple of support routines meant to help with bandwidth allocation. With the changes to uhci-hcd in the previous patch, these routines are no longer used anywhere. Also removed is the CONFIG_USB_BANDWIDTH option; it no longer does anything and is no longer needed since the HCDs now handle bandwidth issues correctly. Signed-off-by: Alan Stern Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/Kconfig | 13 ----- drivers/usb/core/hcd.c | 137 ----------------------------------------------- drivers/usb/core/hcd.h | 6 --- drivers/usb/core/urb.c | 1 - include/linux/usb.h | 1 - 5 files changed, 158 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 3e66b2a9974a..2fc0f88a3d86 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -33,19 +33,6 @@ config USB_DEVICEFS Most users want to say Y here. -config USB_BANDWIDTH - bool "Enforce USB bandwidth allocation (EXPERIMENTAL)" - depends on USB && EXPERIMENTAL - help - If you say Y here, the USB subsystem enforces USB bandwidth - allocation and will prevent some device opens from succeeding - if they would cause USB bandwidth usage to go above 90% of - the bus bandwidth. - - If you say N here, these conditions will cause warning messages - about USB bandwidth usage to be logged and some devices or - drivers may not work correctly. - config USB_DYNAMIC_MINORS bool "Dynamic USB minor allocation (EXPERIMENTAL)" depends on USB && EXPERIMENTAL diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 10064af65d17..b26c19e8d19f 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -45,8 +45,6 @@ #include "hub.h" -// #define USB_BANDWIDTH_MESSAGES - /*-------------------------------------------------------------------------*/ /* @@ -891,136 +889,6 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount) } EXPORT_SYMBOL (usb_calc_bus_time); -/* - * usb_check_bandwidth(): - * - * old_alloc is from host_controller->bandwidth_allocated in microseconds; - * bustime is from calc_bus_time(), but converted to microseconds. - * - * returns if successful, - * or -ENOSPC if bandwidth request fails. - * - * FIXME: - * This initial implementation does not use Endpoint.bInterval - * in managing bandwidth allocation. - * It probably needs to be expanded to use Endpoint.bInterval. - * This can be done as a later enhancement (correction). - * - * This will also probably require some kind of - * frame allocation tracking...meaning, for example, - * that if multiple drivers request interrupts every 10 USB frames, - * they don't all have to be allocated at - * frame numbers N, N+10, N+20, etc. Some of them could be at - * N+11, N+21, N+31, etc., and others at - * N+12, N+22, N+32, etc. - * - * Similarly for isochronous transfers... - * - * Individual HCDs can schedule more directly ... this logic - * is not correct for high speed transfers. - */ -int usb_check_bandwidth (struct usb_device *dev, struct urb *urb) -{ - unsigned int pipe = urb->pipe; - long bustime; - int is_in = usb_pipein (pipe); - int is_iso = usb_pipeisoc (pipe); - int old_alloc = dev->bus->bandwidth_allocated; - int new_alloc; - - - bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso, - usb_maxpacket (dev, pipe, !is_in))); - if (is_iso) - bustime /= urb->number_of_packets; - - new_alloc = old_alloc + (int) bustime; - if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) { -#ifdef DEBUG - char *mode = -#ifdef CONFIG_USB_BANDWIDTH - ""; -#else - "would have "; -#endif - dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n", - mode, old_alloc, bustime, new_alloc); -#endif -#ifdef CONFIG_USB_BANDWIDTH - bustime = -ENOSPC; /* report error */ -#endif - } - - return bustime; -} -EXPORT_SYMBOL (usb_check_bandwidth); - - -/** - * usb_claim_bandwidth - records bandwidth for a periodic transfer - * @dev: source/target of request - * @urb: request (urb->dev == dev) - * @bustime: bandwidth consumed, in (average) microseconds per frame - * @isoc: true iff the request is isochronous - * - * Bus bandwidth reservations are recorded purely for diagnostic purposes. - * HCDs are expected not to overcommit periodic bandwidth, and to record such - * reservations whenever endpoints are added to the periodic schedule. - * - * FIXME averaging per-frame is suboptimal. Better to sum over the HCD's - * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable - * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how - * large its periodic schedule is. - */ -void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc) -{ - dev->bus->bandwidth_allocated += bustime; - if (isoc) - dev->bus->bandwidth_isoc_reqs++; - else - dev->bus->bandwidth_int_reqs++; - urb->bandwidth = bustime; - -#ifdef USB_BANDWIDTH_MESSAGES - dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n", - bustime, - isoc ? "ISOC" : "INTR", - dev->bus->bandwidth_allocated, - dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); -#endif -} -EXPORT_SYMBOL (usb_claim_bandwidth); - - -/** - * usb_release_bandwidth - reverses effect of usb_claim_bandwidth() - * @dev: source/target of request - * @urb: request (urb->dev == dev) - * @isoc: true iff the request is isochronous - * - * This records that previously allocated bandwidth has been released. - * Bandwidth is released when endpoints are removed from the host controller's - * periodic schedule. - */ -void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc) -{ - dev->bus->bandwidth_allocated -= urb->bandwidth; - if (isoc) - dev->bus->bandwidth_isoc_reqs--; - else - dev->bus->bandwidth_int_reqs--; - -#ifdef USB_BANDWIDTH_MESSAGES - dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n", - urb->bandwidth, - isoc ? "ISOC" : "INTR", - dev->bus->bandwidth_allocated, - dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); -#endif - urb->bandwidth = 0; -} -EXPORT_SYMBOL (usb_release_bandwidth); - /*-------------------------------------------------------------------------*/ @@ -1034,11 +902,6 @@ static void urb_unlink (struct urb *urb) { unsigned long flags; - /* Release any periodic transfer bandwidth */ - if (urb->bandwidth) - usb_release_bandwidth (urb->dev, urb, - usb_pipeisoc (urb->pipe)); - /* clear all state linking urb to this dev (and hcd) */ spin_lock_irqsave (&hcd_data_lock, flags); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index 8f8df0d4382e..2a269ca20517 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -308,10 +308,6 @@ extern void usb_destroy_configuration(struct usb_device *dev); #define NS_TO_US(ns) ((ns + 500L) / 1000L) /* convert & round nanoseconds to microseconds */ -extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, - int bustime, int isoc); -extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, - int isoc); /* * Full/low speed bandwidth allocation constants/support. @@ -324,8 +320,6 @@ extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, #define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L) #define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L) -extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb); - /* * Ceiling [nano/micro]seconds (typical) for that many bytes at high speed * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 9801d08edacf..a4fa3e66c307 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -235,7 +235,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) urb->status = -EINPROGRESS; urb->actual_length = 0; - urb->bandwidth = 0; /* Lots of sanity checks, so HCDs can rely on clean data * and don't need to duplicate tests diff --git a/include/linux/usb.h b/include/linux/usb.h index 1c56386de709..3b08ab39550f 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1110,7 +1110,6 @@ struct urb struct kref kref; /* reference count of the URB */ spinlock_t lock; /* lock for the URB */ void *hcpriv; /* private data for host controller */ - int bandwidth; /* bandwidth for INT/ISO request */ atomic_t use_count; /* concurrent submissions counter */ u8 reject; /* submissions will fail */ -- cgit v1.2.3 From c87deff776feacd05a7411097e8c8c57e549e638 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Mon, 18 Dec 2006 10:31:06 +0900 Subject: PCI : Add selected_regions funcs This patch adds the following changes into generic PCI code especially for PCI legacy I/O port free drivers. - Added new pci_request_selected_regions() and pci_release_selected_regions() for PCI legacy I/O port free drivers in order to request/release only the selected regions. - Added helper routine pci_select_bars() which makes proper mask of BARs from the specified resource type. This would be very helpful for users of pci_enable_device_bars(). Signed-off-by: Kenji Kaneshige Signed-off-by: Hidetoshi Seto Cc: Inaky Perez-Gonzalez Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci.c | 80 +++++++++++++++++++++++++++++++++++++++++------------ include/linux/pci.h | 3 ++ 2 files changed, 66 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 287b685aaa5c..599978631a46 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -921,6 +921,47 @@ err_out: return -EBUSY; } +/** + * pci_release_selected_regions - Release selected PCI I/O and memory resources + * @pdev: PCI device whose resources were previously reserved + * @bars: Bitmask of BARs to be released + * + * Release selected PCI I/O and memory resources previously reserved. + * Call this function only after all use of the PCI regions has ceased. + */ +void pci_release_selected_regions(struct pci_dev *pdev, int bars) +{ + int i; + + for (i = 0; i < 6; i++) + if (bars & (1 << i)) + pci_release_region(pdev, i); +} + +/** + * pci_request_selected_regions - Reserve selected PCI I/O and memory resources + * @pdev: PCI device whose resources are to be reserved + * @bars: Bitmask of BARs to be requested + * @res_name: Name to be associated with resource + */ +int pci_request_selected_regions(struct pci_dev *pdev, int bars, + const char *res_name) +{ + int i; + + for (i = 0; i < 6; i++) + if (bars & (1 << i)) + if(pci_request_region(pdev, i, res_name)) + goto err_out; + return 0; + +err_out: + while(--i >= 0) + if (bars & (1 << i)) + pci_release_region(pdev, i); + + return -EBUSY; +} /** * pci_release_regions - Release reserved PCI I/O and memory resources @@ -933,10 +974,7 @@ err_out: void pci_release_regions(struct pci_dev *pdev) { - int i; - - for (i = 0; i < 6; i++) - pci_release_region(pdev, i); + pci_release_selected_regions(pdev, (1 << 6) - 1); } /** @@ -954,18 +992,7 @@ void pci_release_regions(struct pci_dev *pdev) */ int pci_request_regions(struct pci_dev *pdev, const char *res_name) { - int i; - - for (i = 0; i < 6; i++) - if(pci_request_region(pdev, i, res_name)) - goto err_out; - return 0; - -err_out: - while(--i >= 0) - pci_release_region(pdev, i); - - return -EBUSY; + return pci_request_selected_regions(pdev, ((1 << 6) - 1), res_name); } /** @@ -1148,7 +1175,23 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) return 0; } #endif - + +/** + * pci_select_bars - Make BAR mask from the type of resource + * @pdev: the PCI device for which BAR mask is made + * @flags: resource type mask to be selected + * + * This helper routine makes bar mask from the type of resource. + */ +int pci_select_bars(struct pci_dev *dev, unsigned long flags) +{ + int i, bars = 0; + for (i = 0; i < PCI_NUM_RESOURCES; i++) + if (pci_resource_flags(dev, i) & flags) + bars |= (1 << i); + return bars; +} + static int __devinit pci_init(void) { struct pci_dev *dev = NULL; @@ -1197,6 +1240,8 @@ EXPORT_SYMBOL(pci_release_regions); EXPORT_SYMBOL(pci_request_regions); EXPORT_SYMBOL(pci_release_region); EXPORT_SYMBOL(pci_request_region); +EXPORT_SYMBOL(pci_release_selected_regions); +EXPORT_SYMBOL(pci_request_selected_regions); EXPORT_SYMBOL(pci_set_master); EXPORT_SYMBOL(pci_set_mwi); EXPORT_SYMBOL(pci_clear_mwi); @@ -1205,6 +1250,7 @@ EXPORT_SYMBOL(pci_set_dma_mask); EXPORT_SYMBOL(pci_set_consistent_dma_mask); EXPORT_SYMBOL(pci_assign_resource); EXPORT_SYMBOL(pci_find_parent_resource); +EXPORT_SYMBOL(pci_select_bars); EXPORT_SYMBOL(pci_set_power_state); EXPORT_SYMBOL(pci_save_state); diff --git a/include/linux/pci.h b/include/linux/pci.h index f3c617eabd8d..df875626b71a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -533,6 +533,7 @@ void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); int __must_check pci_assign_resource(struct pci_dev *dev, int i); int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i); void pci_restore_bars(struct pci_dev *dev); +int pci_select_bars(struct pci_dev *dev, unsigned long flags); /* ROM control related routines */ void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size); @@ -561,6 +562,8 @@ int __must_check pci_request_regions(struct pci_dev *, const char *); void pci_release_regions(struct pci_dev *); int __must_check pci_request_region(struct pci_dev *, int, const char *); void pci_release_region(struct pci_dev *, int); +int pci_request_selected_regions(struct pci_dev *, int, const char *); +void pci_release_selected_regions(struct pci_dev *, int); /* drivers/pci/bus.c */ int __must_check pci_bus_alloc_resource(struct pci_bus *bus, -- cgit v1.2.3 From a7369f1f6533b9efc3209d1df103537bbbf24b8c Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 12 Dec 2006 16:55:59 -0600 Subject: PCI: define inline for test of channel error state Add very simple routine to indicate the pci channel error state. Signed-off-by: Linas Vepstas Signed-off-by: Greg Kroah-Hartman --- include/linux/pci.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pci.h b/include/linux/pci.h index df875626b71a..79856b3c714a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -181,6 +181,11 @@ struct pci_dev { #define to_pci_dev(n) container_of(n, struct pci_dev, dev) #define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL) +static inline int pci_channel_offline(struct pci_dev *pdev) +{ + return (pdev->error_state != pci_channel_io_normal); +} + static inline struct pci_cap_saved_state *pci_find_saved_cap( struct pci_dev *pci_dev,char cap) { -- cgit v1.2.3 From fd9b37cc4e32533214f77b34ea03ee85f6e0a4d2 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 17 Nov 2006 15:21:45 +0100 Subject: PCI: remove pci_find_device_reverse() This patch removes the no longer used pci_find_device_reverse(). Signed-off-by: Adrian Bunk Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/pci/search.c | 38 -------------------------------------- include/linux/pci.h | 1 - 2 files changed, 39 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/search.c b/drivers/pci/search.c index b2653c4afe9e..ff98eaddaa73 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -357,43 +357,6 @@ exit: return dev; } -/** - * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id - * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids - * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids - * @from: Previous PCI device found in search, or %NULL for new search. - * - * Iterates through the list of known PCI devices in the reverse order of - * pci_find_device(). - * If a PCI device is found with a matching @vendor and @device, a pointer to - * its device structure is returned. Otherwise, %NULL is returned. - * A new search is initiated by passing %NULL as the @from argument. - * Otherwise if @from is not %NULL, searches continue from previous device - * on the global list. - */ -struct pci_dev * -pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from) -{ - struct list_head *n; - struct pci_dev *dev; - - WARN_ON(in_interrupt()); - down_read(&pci_bus_sem); - n = from ? from->global_list.prev : pci_devices.prev; - - while (n && (n != &pci_devices)) { - dev = pci_dev_g(n); - if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && - (device == PCI_ANY_ID || dev->device == device)) - goto exit; - n = n->prev; - } - dev = NULL; -exit: - up_read(&pci_bus_sem); - return dev; -} - /** * pci_get_class - begin or continue searching for a PCI device by class * @class: search for a PCI device with this class designation @@ -469,7 +432,6 @@ EXPORT_SYMBOL(pci_dev_present); EXPORT_SYMBOL(pci_find_present); EXPORT_SYMBOL(pci_find_device); -EXPORT_SYMBOL(pci_find_device_reverse); EXPORT_SYMBOL(pci_find_slot); /* For boot time work */ EXPORT_SYMBOL(pci_find_bus); diff --git a/include/linux/pci.h b/include/linux/pci.h index 79856b3c714a..23d2a37f3c9f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -469,7 +469,6 @@ extern void pci_sort_breadthfirst(void); /* Generic PCI functions exported to card drivers */ struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from); -struct pci_dev *pci_find_device_reverse (unsigned int vendor, unsigned int device, const struct pci_dev *from); struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); int pci_find_capability (struct pci_dev *dev, int cap); int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap); -- cgit v1.2.3 From 429538ad3eeffec4199d8adddd1e9e4c80b2c08b Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 18 Nov 2006 01:06:29 +0100 Subject: PCI: mark pci_find_device() as __deprecated On Fri, Nov 17, 2006 at 09:32:36AM -0500, Alan Cox wrote: > > Soon we should deprecate pci_find_device as well So let's mark it as __deprecated now, which also has the side effect that noone can later whine that removing it might break some shiny external modules. Oh, and if anything starts complaining "But this adds some warnings to my kernel build!", he should either first fix the 200 kB (sic) of warnings I'm getting in 2.6.19-rc5-mm2 starting at MODPOST or go to hell. Signed-off-by: Adrian Bunk Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- include/linux/pci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/pci.h b/include/linux/pci.h index 23d2a37f3c9f..cf2c8a35a1df 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -468,7 +468,7 @@ extern void pci_sort_breadthfirst(void); /* Generic PCI functions exported to card drivers */ -struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from); +struct pci_dev __deprecated *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from); struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); int pci_find_capability (struct pci_dev *dev, int cap); int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap); -- cgit v1.2.3 From 8255cf35d503db7c1b26ae53b6b7f23ada82316f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 6 Jan 2007 21:48:41 +0100 Subject: PCI: make isa_bridge Alpha-only Since isa_bridge is neither assigned any value !NULL nor used on !Alpha, there's no reason for providing it. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- arch/alpha/kernel/pci.c | 4 ++++ drivers/pci/pci.c | 6 ------ include/asm-alpha/pci.h | 2 ++ include/linux/pci.h | 6 ------ 4 files changed, 6 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 3c10b9a1ddf5..ab642a4f08de 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -575,3 +575,7 @@ void pci_iounmap(struct pci_dev *dev, void __iomem * addr) EXPORT_SYMBOL(pci_iomap); EXPORT_SYMBOL(pci_iounmap); + +/* FIXME: Some boxes have multiple ISA bridges! */ +struct pci_dev *isa_bridge; +EXPORT_SYMBOL(isa_bridge); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index caeeacc7b070..e91dcc05b790 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1224,12 +1224,6 @@ early_param("pci", pci_setup); device_initcall(pci_init); -#if defined(CONFIG_ISA) || defined(CONFIG_EISA) -/* FIXME: Some boxes have multiple ISA bridges! */ -struct pci_dev *isa_bridge; -EXPORT_SYMBOL(isa_bridge); -#endif - EXPORT_SYMBOL_GPL(pci_restore_bars); EXPORT_SYMBOL(pci_enable_device_bars); EXPORT_SYMBOL(pci_enable_device); diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h index 4e115f368d5f..85aa1127c903 100644 --- a/include/asm-alpha/pci.h +++ b/include/asm-alpha/pci.h @@ -293,4 +293,6 @@ struct pci_dev *alpha_gendev_to_pci(struct device *dev); #define IOBASE_ROOT_BUS 5 #define IOBASE_FROM_HOSE 0x10000 +extern struct pci_dev *isa_bridge; + #endif /* __ALPHA_PCI_H */ diff --git a/include/linux/pci.h b/include/linux/pci.h index cf2c8a35a1df..d69dfd7d0e0b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -618,10 +618,6 @@ enum pci_dma_burst_strategy { strategy_parameter byte boundaries */ }; -#if defined(CONFIG_ISA) || defined(CONFIG_EISA) -extern struct pci_dev *isa_bridge; -#endif - struct msix_entry { u16 vector; /* kernel uses to write allocated vector */ u16 entry; /* driver uses to specify entry, OS writes */ @@ -729,8 +725,6 @@ static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { static inline pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { return PCI_D0; } static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) { return 0; } -#define isa_bridge ((struct pci_dev *)NULL) - #define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0) static inline void pci_block_user_cfg_access(struct pci_dev *dev) { } -- cgit v1.2.3 From c54c18790700b8b2a503945d729aa425c25691fe Mon Sep 17 00:00:00 2001 From: Satoru Takeuchi Date: Thu, 18 Jan 2007 13:50:05 +0900 Subject: PCI: cleanup MSI code Cleanup MSI code as follows: - fix some types - fix strange local variable definition - delete unnecessary blank line - add comment to #endif which is far from corresponding #ifdef Signed-off-by: Satoru Takeuchi Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 9 +++++---- include/linux/msi.h | 3 +-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index ed3f7e1a563c..e87e8efb9bb4 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -49,8 +49,8 @@ static void msi_set_mask_bit(unsigned int irq, int flag) switch (entry->msi_attrib.type) { case PCI_CAP_ID_MSI: if (entry->msi_attrib.maskbit) { - int pos; - u32 mask_bits; + int pos; + u32 mask_bits; pos = (long)entry->mask_base; pci_read_config_dword(entry->dev, pos, &mask_bits); @@ -162,6 +162,7 @@ void unmask_msi_irq(unsigned int irq) } static int msi_free_irq(struct pci_dev* dev, int irq); + static int msi_init(void) { static int status = -ENOMEM; @@ -291,7 +292,7 @@ static int msi_lookup_irq(struct pci_dev *dev, int type) continue; spin_unlock_irqrestore(&msi_lock, flags); /* This pre-assigned MSI irq for this device - already exits. Override dev->irq with this irq */ + already exists. Override dev->irq with this irq */ dev->irq = irq; return 0; } @@ -458,7 +459,7 @@ void pci_restore_msix_state(struct pci_dev *dev) pci_write_config_word(dev, msi_control_reg(pos), save); enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); } -#endif +#endif /* CONFIG_PM */ /** * msi_capability_init - configure device's MSI capability structure diff --git a/include/linux/msi.h b/include/linux/msi.h index c7ef94343673..b99976b1536e 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -7,11 +7,10 @@ struct msi_msg { u32 data; /* 16 bits of msi message data */ }; -/* Heper functions */ +/* Helper functions */ extern void mask_msi_irq(unsigned int irq); extern void unmask_msi_irq(unsigned int irq); extern void read_msi_msg(unsigned int irq, struct msi_msg *msg); - extern void write_msi_msg(unsigned int irq, struct msi_msg *msg); struct msi_desc { -- cgit v1.2.3 From 0fcfdabbdbedb3bdc63f29209aeeac805df78a92 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 25 Jan 2007 19:34:08 +1100 Subject: MSI: Remove pci_scan_msi_device() pci_scan_msi_device() doesn't do anything anymore, so remove it. Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/pci_64.c | 2 -- drivers/pci/msi.c | 6 ------ drivers/pci/probe.c | 1 - include/linux/pci.h | 2 -- 4 files changed, 11 deletions(-) (limited to 'include/linux') diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 01f18c683407..2b52b087aaa8 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -381,8 +381,6 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, pci_device_add(dev, bus); - /* XXX pci_scan_msi_device(dev); */ - return dev; } EXPORT_SYMBOL(of_create_pci_dev); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 3776531586d1..6cfa6be9a6d5 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -294,12 +294,6 @@ static int msi_lookup_irq(struct pci_dev *dev, int type) return -EACCES; } -void pci_scan_msi_device(struct pci_dev *dev) -{ - if (!dev) - return; -} - #ifdef CONFIG_PM int pci_save_msi_state(struct pci_dev *dev) { diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 9d7788428642..2fe1d690eb13 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -945,7 +945,6 @@ pci_scan_single_device(struct pci_bus *bus, int devfn) return NULL; pci_device_add(dev, bus); - pci_scan_msi_device(dev); return dev; } diff --git a/include/linux/pci.h b/include/linux/pci.h index d69dfd7d0e0b..29765e2b1e0a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -625,7 +625,6 @@ struct msix_entry { #ifndef CONFIG_PCI_MSI -static inline void pci_scan_msi_device(struct pci_dev *dev) {} static inline int pci_enable_msi(struct pci_dev *dev) {return -1;} static inline void pci_disable_msi(struct pci_dev *dev) {} static inline int pci_enable_msix(struct pci_dev* dev, @@ -633,7 +632,6 @@ static inline int pci_enable_msix(struct pci_dev* dev, static inline void pci_disable_msix(struct pci_dev *dev) {} static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {} #else -extern void pci_scan_msi_device(struct pci_dev *dev); extern int pci_enable_msi(struct pci_dev *dev); extern void pci_disable_msi(struct pci_dev *dev); extern int pci_enable_msix(struct pci_dev* dev, -- cgit v1.2.3 From ded86d8d37736df67ddeec4ae00e2ec1a5a90b3c Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 28 Jan 2007 12:42:52 -0700 Subject: msi: Kill msi_lookup_irq The function msi_lookup_irq was horrible. As a side effect of running it changed dev->irq, and then the callers would need to change it back. In addition it does a global scan through all of the irqs, which seems to be the sole justification of the msi_lock. To remove the neede for msi_lookup_irq I added first_msi_irq to struct pci_dev. Then depending on the context I replaced msi_lookup_irq with dev->first_msi_irq, dev->msi_enabled, or dev->msix_enabled. msi_enabled and msix_enabled were already present in pci_dev for other reasons. Signed-off-by: Eric W. Biederman Acked-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 149 +++++++++++++++++++++------------------------------- include/linux/pci.h | 3 ++ 2 files changed, 62 insertions(+), 90 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 067ae9917fd6..b945470bef18 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -272,28 +272,6 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type) pci_intx(dev, 1); /* enable intx */ } -static int msi_lookup_irq(struct pci_dev *dev, int type) -{ - int irq; - unsigned long flags; - - spin_lock_irqsave(&msi_lock, flags); - for (irq = 0; irq < NR_IRQS; irq++) { - if (!msi_desc[irq] || msi_desc[irq]->dev != dev || - msi_desc[irq]->msi_attrib.type != type || - msi_desc[irq]->msi_attrib.default_irq != dev->irq) - continue; - spin_unlock_irqrestore(&msi_lock, flags); - /* This pre-assigned MSI irq for this device - already exists. Override dev->irq with this irq */ - dev->irq = irq; - return 0; - } - spin_unlock_irqrestore(&msi_lock, flags); - - return -EACCES; -} - #ifdef CONFIG_PM static int __pci_save_msi_state(struct pci_dev *dev) { @@ -364,11 +342,13 @@ static void __pci_restore_msi_state(struct pci_dev *dev) static int __pci_save_msix_state(struct pci_dev *dev) { int pos; - int temp; int irq, head, tail = 0; u16 control; struct pci_cap_saved_state *save_state; + if (!dev->msix_enabled) + return 0; + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); if (pos <= 0 || dev->no_msi) return 0; @@ -386,13 +366,7 @@ static int __pci_save_msix_state(struct pci_dev *dev) *((u16 *)&save_state->data[0]) = control; /* save the table */ - temp = dev->irq; - if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { - kfree(save_state); - return -EINVAL; - } - - irq = head = dev->irq; + irq = head = dev->first_msi_irq; while (head != tail) { struct msi_desc *entry; @@ -402,7 +376,6 @@ static int __pci_save_msix_state(struct pci_dev *dev) tail = msi_desc[irq]->link.tail; irq = tail; } - dev->irq = temp; save_state->cap_nr = PCI_CAP_ID_MSIX; pci_add_saved_cap(dev, save_state); @@ -428,9 +401,11 @@ static void __pci_restore_msix_state(struct pci_dev *dev) int pos; int irq, head, tail = 0; struct msi_desc *entry; - int temp; struct pci_cap_saved_state *save_state; + if (!dev->msix_enabled) + return; + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX); if (!save_state) return; @@ -443,10 +418,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev) return; /* route the table */ - temp = dev->irq; - if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) - return; - irq = head = dev->irq; + irq = head = dev->first_msi_irq; while (head != tail) { entry = msi_desc[irq]; write_msi_msg(irq, &entry->msg_save); @@ -454,7 +426,6 @@ static void __pci_restore_msix_state(struct pci_dev *dev) tail = msi_desc[irq]->link.tail; irq = tail; } - dev->irq = temp; pci_write_config_word(dev, msi_control_reg(pos), save); enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); @@ -524,6 +495,7 @@ static int msi_capability_init(struct pci_dev *dev) return status; } + dev->first_msi_irq = irq; attach_msi_entry(entry, irq); /* Set MSI enabled bits */ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); @@ -620,6 +592,7 @@ static int msix_capability_init(struct pci_dev *dev, avail = -EBUSY; return avail; } + dev->first_msi_irq = entries[0].vector; /* Set MSI-X enabled bits */ enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); @@ -667,13 +640,11 @@ int pci_msi_supported(struct pci_dev * dev) **/ int pci_enable_msi(struct pci_dev* dev) { - int pos, temp, status; + int pos, status; if (pci_msi_supported(dev) < 0) return -EINVAL; - temp = dev->irq; - status = msi_init(); if (status < 0) return status; @@ -682,15 +653,14 @@ int pci_enable_msi(struct pci_dev* dev) if (!pos) return -EINVAL; - WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI)); + WARN_ON(!!dev->msi_enabled); /* Check whether driver already requested for MSI-X irqs */ pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); - if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { + if (pos > 0 && dev->msix_enabled) { printk(KERN_INFO "PCI: %s: Can't enable MSI. " - "Device already has MSI-X irq assigned\n", + "Device already has MSI-X enabled\n", pci_name(dev)); - dev->irq = temp; return -EINVAL; } status = msi_capability_init(dev); @@ -709,6 +679,9 @@ void pci_disable_msi(struct pci_dev* dev) if (!dev) return; + if (!dev->msi_enabled) + return; + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); if (!pos) return; @@ -717,28 +690,30 @@ void pci_disable_msi(struct pci_dev* dev) if (!(control & PCI_MSI_FLAGS_ENABLE)) return; + disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); spin_lock_irqsave(&msi_lock, flags); - entry = msi_desc[dev->irq]; + entry = msi_desc[dev->first_msi_irq]; if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { spin_unlock_irqrestore(&msi_lock, flags); return; } - if (irq_has_action(dev->irq)) { + if (irq_has_action(dev->first_msi_irq)) { spin_unlock_irqrestore(&msi_lock, flags); printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without " "free_irq() on MSI irq %d\n", - pci_name(dev), dev->irq); - BUG_ON(irq_has_action(dev->irq)); + pci_name(dev), dev->first_msi_irq); + BUG_ON(irq_has_action(dev->first_msi_irq)); } else { default_irq = entry->msi_attrib.default_irq; spin_unlock_irqrestore(&msi_lock, flags); - msi_free_irq(dev, dev->irq); + msi_free_irq(dev, dev->first_msi_irq); /* Restore dev->irq to its default pin-assertion irq */ dev->irq = default_irq; } + dev->first_msi_irq = 0; } static int msi_free_irq(struct pci_dev* dev, int irq) @@ -797,7 +772,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq) int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) { int status, pos, nr_entries; - int i, j, temp; + int i, j; u16 control; if (!entries || pci_msi_supported(dev) < 0) @@ -825,16 +800,14 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) return -EINVAL; /* duplicate entry */ } } - temp = dev->irq; - WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)); + WARN_ON(!!dev->msix_enabled); /* Check whether driver already requested for MSI irq */ if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 && - !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) { + dev->msi_enabled) { printk(KERN_INFO "PCI: %s: Can't enable MSI-X. " "Device already has an MSI irq assigned\n", pci_name(dev)); - dev->irq = temp; return -EINVAL; } status = msix_capability_init(dev, entries, nvec); @@ -843,7 +816,9 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) void pci_disable_msix(struct pci_dev* dev) { - int pos, temp; + int irq, head, tail = 0, warning = 0; + unsigned long flags; + int pos; u16 control; if (!pci_msi_enable) @@ -851,6 +826,9 @@ void pci_disable_msix(struct pci_dev* dev) if (!dev) return; + if (!dev->msix_enabled) + return; + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); if (!pos) return; @@ -861,31 +839,25 @@ void pci_disable_msix(struct pci_dev* dev) disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); - temp = dev->irq; - if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { - int irq, head, tail = 0, warning = 0; - unsigned long flags; - - irq = head = dev->irq; - dev->irq = temp; /* Restore pin IRQ */ - while (head != tail) { - spin_lock_irqsave(&msi_lock, flags); - tail = msi_desc[irq]->link.tail; - spin_unlock_irqrestore(&msi_lock, flags); - if (irq_has_action(irq)) - warning = 1; - else if (irq != head) /* Release MSI-X irq */ - msi_free_irq(dev, irq); - irq = tail; - } - msi_free_irq(dev, irq); - if (warning) { - printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without " - "free_irq() on all MSI-X irqs\n", - pci_name(dev)); - BUG_ON(warning > 0); - } + irq = head = dev->first_msi_irq; + while (head != tail) { + spin_lock_irqsave(&msi_lock, flags); + tail = msi_desc[irq]->link.tail; + spin_unlock_irqrestore(&msi_lock, flags); + if (irq_has_action(irq)) + warning = 1; + else if (irq != head) /* Release MSI-X irq */ + msi_free_irq(dev, irq); + irq = tail; + } + msi_free_irq(dev, irq); + if (warning) { + printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without " + "free_irq() on all MSI-X irqs\n", + pci_name(dev)); + BUG_ON(warning > 0); } + dev->first_msi_irq = 0; } /** @@ -899,30 +871,28 @@ void pci_disable_msix(struct pci_dev* dev) **/ void msi_remove_pci_irq_vectors(struct pci_dev* dev) { - int pos, temp; + int pos; unsigned long flags; if (!pci_msi_enable || !dev) return; - temp = dev->irq; /* Save IOAPIC IRQ */ pos = pci_find_capability(dev, PCI_CAP_ID_MSI); - if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) { - if (irq_has_action(dev->irq)) { + if (pos > 0 && dev->msi_enabled) { + if (irq_has_action(dev->first_msi_irq)) { printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " "called without free_irq() on MSI irq %d\n", - pci_name(dev), dev->irq); - BUG_ON(irq_has_action(dev->irq)); + pci_name(dev), dev->first_msi_irq); + BUG_ON(irq_has_action(dev->first_msi_irq)); } else /* Release MSI irq assigned to this device */ - msi_free_irq(dev, dev->irq); - dev->irq = temp; /* Restore IOAPIC IRQ */ + msi_free_irq(dev, dev->first_msi_irq); } pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); - if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) { + if (pos > 0 && dev->msix_enabled) { int irq, head, tail = 0, warning = 0; void __iomem *base = NULL; - irq = head = dev->irq; + irq = head = dev->first_msi_irq; while (head != tail) { spin_lock_irqsave(&msi_lock, flags); tail = msi_desc[irq]->link.tail; @@ -942,7 +912,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) pci_name(dev)); BUG_ON(warning > 0); } - dev->irq = temp; /* Restore IOAPIC IRQ */ } } diff --git a/include/linux/pci.h b/include/linux/pci.h index 29765e2b1e0a..1507f8cc45fd 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -174,6 +174,9 @@ struct pci_dev { struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */ int rom_attr_enabled; /* has display of the rom attribute been enabled? */ struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ +#ifdef CONFIG_PCI_MSI + unsigned int first_msi_irq; +#endif }; #define pci_dev_g(n) list_entry(n, struct pci_dev, global_list) -- cgit v1.2.3 From 5b912c108c8b1fcecbfe13d6d9a183db97b682d3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 28 Jan 2007 12:52:03 -0700 Subject: msi: Kill the msi_desc array. We need to be able to get from an irq number to a struct msi_desc. The msi_desc array in msi.c had several short comings the big one was that it could not be used outside of msi.c. Using irq_data in struct irq_desc almost worked except on some architectures irq_data needs to be used for something else. So this patch adds a msi_desc pointer to irq_desc, adds the appropriate wrappers and changes all of the msi code to use them. The dynamic_irq_init/cleanup code was tweaked to ensure the new field is left in a well defined state. Signed-off-by: Eric W. Biederman Acked-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/ia64/sn/kernel/msi_sn.c | 2 +- drivers/pci/msi.c | 44 +++++++++++++++++++++----------------------- include/linux/irq.h | 4 ++++ kernel/irq/chip.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 24 deletions(-) (limited to 'include/linux') diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c index b3a435fd70fb..31fbb859b67e 100644 --- a/arch/ia64/sn/kernel/msi_sn.c +++ b/arch/ia64/sn/kernel/msi_sn.c @@ -74,7 +74,7 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); - entry = get_irq_data(irq); + entry = get_irq_msi(irq); if (!entry->msi_attrib.is_64) return -EINVAL; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 55fe83dfd77b..52c253c5ad3d 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -24,7 +24,6 @@ #include "pci.h" #include "msi.h" -static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; static struct kmem_cache* msi_cachep; static int pci_msi_enable = 1; @@ -43,7 +42,7 @@ static void msi_set_mask_bit(unsigned int irq, int flag) { struct msi_desc *entry; - entry = msi_desc[irq]; + entry = get_irq_msi(irq); BUG_ON(!entry || !entry->dev); switch (entry->msi_attrib.type) { case PCI_CAP_ID_MSI: @@ -73,7 +72,7 @@ static void msi_set_mask_bit(unsigned int irq, int flag) void read_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_data(irq); + struct msi_desc *entry = get_irq_msi(irq); switch(entry->msi_attrib.type) { case PCI_CAP_ID_MSI: { @@ -112,7 +111,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg) void write_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_data(irq); + struct msi_desc *entry = get_irq_msi(irq); switch (entry->msi_attrib.type) { case PCI_CAP_ID_MSI: { @@ -208,7 +207,7 @@ static int create_msi_irq(void) return -EBUSY; } - set_irq_data(irq, entry); + set_irq_msi(irq, entry); return irq; } @@ -217,9 +216,9 @@ static void destroy_msi_irq(unsigned int irq) { struct msi_desc *entry; - entry = get_irq_data(irq); + entry = get_irq_msi(irq); set_irq_chip(irq, NULL); - set_irq_data(irq, NULL); + set_irq_msi(irq, NULL); destroy_irq(irq); kmem_cache_free(msi_cachep, entry); } @@ -360,10 +359,10 @@ static int __pci_save_msix_state(struct pci_dev *dev) while (head != tail) { struct msi_desc *entry; - entry = msi_desc[irq]; + entry = get_irq_msi(irq); read_msi_msg(irq, &entry->msg_save); - tail = msi_desc[irq]->link.tail; + tail = entry->link.tail; irq = tail; } @@ -410,10 +409,10 @@ static void __pci_restore_msix_state(struct pci_dev *dev) /* route the table */ irq = head = dev->first_msi_irq; while (head != tail) { - entry = msi_desc[irq]; + entry = get_irq_msi(irq); write_msi_msg(irq, &entry->msg_save); - tail = msi_desc[irq]->link.tail; + tail = entry->link.tail; irq = tail; } @@ -451,7 +450,7 @@ static int msi_capability_init(struct pci_dev *dev) if (irq < 0) return irq; - entry = get_irq_data(irq); + entry = get_irq_msi(irq); entry->link.head = irq; entry->link.tail = irq; entry->msi_attrib.type = PCI_CAP_ID_MSI; @@ -486,7 +485,7 @@ static int msi_capability_init(struct pci_dev *dev) } dev->first_msi_irq = irq; - msi_desc[irq] = entry; + set_irq_msi(irq, entry); /* Set MSI enabled bits */ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); @@ -535,7 +534,7 @@ static int msix_capability_init(struct pci_dev *dev, if (irq < 0) break; - entry = get_irq_data(irq); + entry = get_irq_msi(irq); j = entries[i].entry; entries[i].vector = irq; entry->msi_attrib.type = PCI_CAP_ID_MSIX; @@ -565,7 +564,7 @@ static int msix_capability_init(struct pci_dev *dev, break; } - msi_desc[irq] = entry; + set_irq_msi(irq, entry); } if (i != nvec) { int avail = i - 1; @@ -682,7 +681,7 @@ void pci_disable_msi(struct pci_dev* dev) disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); - entry = msi_desc[dev->first_msi_irq]; + entry = get_irq_msi(dev->first_msi_irq); if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { return; } @@ -709,7 +708,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq) arch_teardown_msi_irq(irq); - entry = msi_desc[irq]; + entry = get_irq_msi(irq); if (!entry || entry->dev != dev) { return -EINVAL; } @@ -717,10 +716,9 @@ static int msi_free_irq(struct pci_dev* dev, int irq) entry_nr = entry->msi_attrib.entry_nr; head = entry->link.head; base = entry->mask_base; - msi_desc[entry->link.head]->link.tail = entry->link.tail; - msi_desc[entry->link.tail]->link.head = entry->link.head; + get_irq_msi(entry->link.head)->link.tail = entry->link.tail; + get_irq_msi(entry->link.tail)->link.head = entry->link.head; entry->dev = NULL; - msi_desc[irq] = NULL; destroy_msi_irq(irq); @@ -821,7 +819,7 @@ void pci_disable_msix(struct pci_dev* dev) irq = head = dev->first_msi_irq; while (head != tail) { - tail = msi_desc[irq]->link.tail; + tail = get_irq_msi(irq)->link.tail; if (irq_has_action(irq)) warning = 1; else if (irq != head) /* Release MSI-X irq */ @@ -867,8 +865,8 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) irq = head = dev->first_msi_irq; while (head != tail) { - tail = msi_desc[irq]->link.tail; - base = msi_desc[irq]->mask_base; + tail = get_irq_msi(irq)->link.tail; + base = get_irq_msi(irq)->mask_base; if (irq_has_action(irq)) warning = 1; else if (irq != head) /* Release MSI-X irq */ diff --git a/include/linux/irq.h b/include/linux/irq.h index 52fc4052a0ae..5504b671357f 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -68,6 +68,7 @@ typedef void fastcall (*irq_flow_handler_t)(unsigned int irq, #define IRQ_MOVE_PENDING 0x40000000 /* need to re-target IRQ destination */ struct proc_dir_entry; +struct msi_desc; /** * struct irq_chip - hardware interrupt chip descriptor @@ -148,6 +149,7 @@ struct irq_chip { struct irq_desc { irq_flow_handler_t handle_irq; struct irq_chip *chip; + struct msi_desc *msi_desc; void *handler_data; void *chip_data; struct irqaction *action; /* IRQ action list */ @@ -373,10 +375,12 @@ extern int set_irq_chip(unsigned int irq, struct irq_chip *chip); extern int set_irq_data(unsigned int irq, void *data); extern int set_irq_chip_data(unsigned int irq, void *data); extern int set_irq_type(unsigned int irq, unsigned int type); +extern int set_irq_msi(unsigned int irq, struct msi_desc *entry); #define get_irq_chip(irq) (irq_desc[irq].chip) #define get_irq_chip_data(irq) (irq_desc[irq].chip_data) #define get_irq_data(irq) (irq_desc[irq].handler_data) +#define get_irq_msi(irq) (irq_desc[irq].msi_desc) #endif /* CONFIG_GENERIC_HARDIRQS */ diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index d27b25855743..475e8a71bcdc 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -39,6 +39,7 @@ void dynamic_irq_init(unsigned int irq) desc->chip = &no_irq_chip; desc->handle_irq = handle_bad_irq; desc->depth = 1; + desc->msi_desc = NULL; desc->handler_data = NULL; desc->chip_data = NULL; desc->action = NULL; @@ -74,6 +75,9 @@ void dynamic_irq_cleanup(unsigned int irq) WARN_ON(1); return; } + desc->msi_desc = NULL; + desc->handler_data = NULL; + desc->chip_data = NULL; desc->handle_irq = handle_bad_irq; desc->chip = &no_irq_chip; spin_unlock_irqrestore(&desc->lock, flags); @@ -161,6 +165,30 @@ int set_irq_data(unsigned int irq, void *data) } EXPORT_SYMBOL(set_irq_data); +/** + * set_irq_data - set irq type data for an irq + * @irq: Interrupt number + * @data: Pointer to interrupt specific data + * + * Set the hardware irq controller data for an irq + */ +int set_irq_msi(unsigned int irq, struct msi_desc *entry) +{ + struct irq_desc *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR + "Trying to install msi data for IRQ%d\n", irq); + return -EINVAL; + } + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock, flags); + desc->msi_desc = entry; + spin_unlock_irqrestore(&desc->lock, flags); + return 0; +} + /** * set_irq_chip_data - set irq chip data for an irq * @irq: Interrupt number -- cgit v1.2.3 From f7feaca77d6ad6bcfcc88ac54e3188970448d6fe Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 28 Jan 2007 12:56:37 -0700 Subject: msi: Make MSI useable more architectures The arch hooks arch_setup_msi_irq and arch_teardown_msi_irq are now responsible for allocating and freeing the linux irq in addition to setting up the the linux irq to work with the interrupt. arch_setup_msi_irq now takes a pci_device and a msi_desc and returns an irq. With this change in place this code should be useable by all platforms except those that won't let the OS touch the hardware like ppc RTAS. Signed-off-by: Eric W. Biederman Acked-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/i386/kernel/io_apic.c | 17 +++++++--- arch/ia64/kernel/msi_ia64.c | 19 +++++++---- arch/ia64/sn/kernel/msi_sn.c | 20 +++++++---- arch/x86_64/kernel/io_apic.c | 17 +++++++--- drivers/pci/msi.c | 80 ++++++++++++-------------------------------- include/asm-ia64/machvec.h | 3 +- include/linux/msi.h | 2 +- 7 files changed, 75 insertions(+), 83 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 6a3875f81a0a..5592fa6e1fa1 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -2606,25 +2606,32 @@ static struct irq_chip msi_chip = { .retrigger = ioapic_retrigger_irq, }; -int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) +int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) { struct msi_msg msg; - int ret; + int irq, ret; + irq = create_irq(); + if (irq < 0) + return irq; + + set_irq_msi(irq, desc); ret = msi_compose_msg(dev, irq, &msg); - if (ret < 0) + if (ret < 0) { + destroy_irq(irq); return ret; + } write_msi_msg(irq, &msg); set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); - return 0; + return irq; } void arch_teardown_msi_irq(unsigned int irq) { - return; + destroy_irq(irq); } #endif /* CONFIG_PCI_MSI */ diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c index 822e59a1b822..0d05450c91c4 100644 --- a/arch/ia64/kernel/msi_ia64.c +++ b/arch/ia64/kernel/msi_ia64.c @@ -64,12 +64,17 @@ static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask) } #endif /* CONFIG_SMP */ -int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) +int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) { struct msi_msg msg; unsigned long dest_phys_id; - unsigned int vector; + unsigned int irq, vector; + irq = create_irq(); + if (irq < 0) + return irq; + + set_irq_msi(irq, desc); dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); vector = irq; @@ -89,12 +94,12 @@ int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) write_msi_msg(irq, &msg); set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq); - return 0; + return irq; } void ia64_teardown_msi_irq(unsigned int irq) { - return; /* no-op */ + destroy_irq(irq); } static void ia64_ack_msi_irq(unsigned int irq) @@ -126,12 +131,12 @@ static struct irq_chip ia64_msi_chip = { }; -int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) +int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) { if (platform_setup_msi_irq) - return platform_setup_msi_irq(irq, pdev); + return platform_setup_msi_irq(pdev, desc); - return ia64_setup_msi_irq(irq, pdev); + return ia64_setup_msi_irq(pdev, desc); } void arch_teardown_msi_irq(unsigned int irq) diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c index 31fbb859b67e..ea3dc38d73fd 100644 --- a/arch/ia64/sn/kernel/msi_sn.c +++ b/arch/ia64/sn/kernel/msi_sn.c @@ -59,13 +59,12 @@ void sn_teardown_msi_irq(unsigned int irq) sn_intr_free(nasid, widget, sn_irq_info); sn_msi_info[irq].sn_irq_info = NULL; - return; + destroy_irq(irq); } -int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) +int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry) { struct msi_msg msg; - struct msi_desc *entry; int widget; int status; nasid_t nasid; @@ -73,8 +72,8 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) struct sn_irq_info *sn_irq_info; struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); + int irq; - entry = get_irq_msi(irq); if (!entry->msi_attrib.is_64) return -EINVAL; @@ -84,6 +83,11 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) if (provider == NULL || provider->dma_map_consistent == NULL) return -EINVAL; + irq = create_irq(); + if (irq < 0) + return irq; + + set_irq_msi(irq, entry); /* * Set up the vector plumbing. Let the prom (via sn_intr_alloc) * decide which cpu to direct this msi at by default. @@ -95,12 +99,15 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) SWIN_WIDGETNUM(bussoft->bs_base); sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); - if (! sn_irq_info) + if (! sn_irq_info) { + destroy_irq(irq); return -ENOMEM; + } status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1); if (status) { kfree(sn_irq_info); + destroy_irq(irq); return -ENOMEM; } @@ -121,6 +128,7 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) if (! bus_addr) { sn_intr_free(nasid, widget, sn_irq_info); kfree(sn_irq_info); + destroy_irq(irq); return -ENOMEM; } @@ -139,7 +147,7 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) write_msi_msg(irq, &msg); set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq); - return 0; + return irq; } #ifdef CONFIG_SMP diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index d7bad90a5ad8..6be6730acb5c 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -1956,24 +1956,31 @@ static struct irq_chip msi_chip = { .retrigger = ioapic_retrigger_irq, }; -int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) +int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) { struct msi_msg msg; - int ret; + int irq, ret; + irq = create_irq(); + if (irq < 0) + return irq; + + set_irq_msi(irq, desc); ret = msi_compose_msg(dev, irq, &msg); - if (ret < 0) + if (ret < 0) { + destroy_irq(irq); return ret; + } write_msi_msg(irq, &msg); set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge"); - return 0; + return irq; } void arch_teardown_msi_irq(unsigned int irq) { - return; + destroy_irq(irq); } #endif /* CONFIG_PCI_MSI */ diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 52c253c5ad3d..68555c11f556 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -192,37 +192,6 @@ static struct msi_desc* alloc_msi_entry(void) return entry; } -static int create_msi_irq(void) -{ - struct msi_desc *entry; - int irq; - - entry = alloc_msi_entry(); - if (!entry) - return -ENOMEM; - - irq = create_irq(); - if (irq < 0) { - kmem_cache_free(msi_cachep, entry); - return -EBUSY; - } - - set_irq_msi(irq, entry); - - return irq; -} - -static void destroy_msi_irq(unsigned int irq) -{ - struct msi_desc *entry; - - entry = get_irq_msi(irq); - set_irq_chip(irq, NULL); - set_irq_msi(irq, NULL); - destroy_irq(irq); - kmem_cache_free(msi_cachep, entry); -} - static void enable_msi_mode(struct pci_dev *dev, int pos, int type) { u16 control; @@ -438,7 +407,6 @@ void pci_restore_msi_state(struct pci_dev *dev) **/ static int msi_capability_init(struct pci_dev *dev) { - int status; struct msi_desc *entry; int pos, irq; u16 control; @@ -446,13 +414,10 @@ static int msi_capability_init(struct pci_dev *dev) pos = pci_find_capability(dev, PCI_CAP_ID_MSI); pci_read_config_word(dev, msi_control_reg(pos), &control); /* MSI Entry Initialization */ - irq = create_msi_irq(); - if (irq < 0) - return irq; + entry = alloc_msi_entry(); + if (!entry) + return -ENOMEM; - entry = get_irq_msi(irq); - entry->link.head = irq; - entry->link.tail = irq; entry->msi_attrib.type = PCI_CAP_ID_MSI; entry->msi_attrib.is_64 = is_64bit_address(control); entry->msi_attrib.entry_nr = 0; @@ -478,14 +443,16 @@ static int msi_capability_init(struct pci_dev *dev) maskbits); } /* Configure MSI capability structure */ - status = arch_setup_msi_irq(irq, dev); - if (status < 0) { - destroy_msi_irq(irq); - return status; + irq = arch_setup_msi_irq(dev, entry); + if (irq < 0) { + kmem_cache_free(msi_cachep, entry); + return irq; } - + entry->link.head = irq; + entry->link.tail = irq; dev->first_msi_irq = irq; set_irq_msi(irq, entry); + /* Set MSI enabled bits */ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); @@ -507,7 +474,6 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries, int nvec) { struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; - int status; int irq, pos, i, j, nr_entries, temp = 0; unsigned long phys_addr; u32 table_offset; @@ -530,13 +496,11 @@ static int msix_capability_init(struct pci_dev *dev, /* MSI-X Table Initialization */ for (i = 0; i < nvec; i++) { - irq = create_msi_irq(); - if (irq < 0) + entry = alloc_msi_entry(); + if (!entry) break; - entry = get_irq_msi(irq); j = entries[i].entry; - entries[i].vector = irq; entry->msi_attrib.type = PCI_CAP_ID_MSIX; entry->msi_attrib.is_64 = 1; entry->msi_attrib.entry_nr = j; @@ -545,6 +509,14 @@ static int msix_capability_init(struct pci_dev *dev, entry->msi_attrib.pos = pos; entry->dev = dev; entry->mask_base = base; + + /* Configure MSI-X capability structure */ + irq = arch_setup_msi_irq(dev, entry); + if (irq < 0) { + kmem_cache_free(msi_cachep, entry); + break; + } + entries[i].vector = irq; if (!head) { entry->link.head = irq; entry->link.tail = irq; @@ -557,12 +529,6 @@ static int msix_capability_init(struct pci_dev *dev, } temp = irq; tail = entry; - /* Configure MSI-X capability structure */ - status = arch_setup_msi_irq(irq, dev); - if (status < 0) { - destroy_msi_irq(irq); - break; - } set_irq_msi(irq, entry); } @@ -706,8 +672,6 @@ static int msi_free_irq(struct pci_dev* dev, int irq) int head, entry_nr, type; void __iomem *base; - arch_teardown_msi_irq(irq); - entry = get_irq_msi(irq); if (!entry || entry->dev != dev) { return -EINVAL; @@ -718,9 +682,9 @@ static int msi_free_irq(struct pci_dev* dev, int irq) base = entry->mask_base; get_irq_msi(entry->link.head)->link.tail = entry->link.tail; get_irq_msi(entry->link.tail)->link.head = entry->link.head; - entry->dev = NULL; - destroy_msi_irq(irq); + arch_teardown_msi_irq(irq); + kmem_cache_free(msi_cachep, entry); if (type == PCI_CAP_ID_MSIX) { writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE + diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h index a3891eb3f217..3c96ac19154e 100644 --- a/include/asm-ia64/machvec.h +++ b/include/asm-ia64/machvec.h @@ -21,6 +21,7 @@ struct mm_struct; struct pci_bus; struct task_struct; struct pci_dev; +struct msi_desc; typedef void ia64_mv_setup_t (char **); typedef void ia64_mv_cpu_init_t (void); @@ -79,7 +80,7 @@ typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *); typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *); typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *); -typedef int ia64_mv_setup_msi_irq_t (unsigned int irq, struct pci_dev *pdev); +typedef int ia64_mv_setup_msi_irq_t (struct pci_dev *pdev, struct msi_desc *); typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq); static inline void diff --git a/include/linux/msi.h b/include/linux/msi.h index b99976b1536e..74c8a2ecc9dd 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -41,7 +41,7 @@ struct msi_desc { /* * The arch hook for setup up msi irqs */ -int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev); +int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc); void arch_teardown_msi_irq(unsigned int irq); -- cgit v1.2.3 From 07b2463046247ce580ff9b37e91394f2f6424768 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 7 Feb 2007 21:34:08 -0800 Subject: Revert "Driver core: convert SPI code to use struct device" This reverts commit 2943ecf2ed32632473c06f1975db47a7aa98c10f. This should go through the SPI maintainer, it was my fault that it did not. Especially as it conflicts with other patches he has pending. Signed-off-by: Greg Kroah-Hartman --- drivers/spi/pxa2xx_spi.c | 2 +- drivers/spi/spi.c | 32 ++++++++++++++++---------------- drivers/spi/spi_bitbang.c | 6 +++--- drivers/spi/spi_butterfly.c | 4 ++-- include/linux/spi/spi.h | 10 +++++----- 5 files changed, 27 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index dccdc50b0296..8b41f9cc2560 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -1234,7 +1234,7 @@ static int init_queue(struct driver_data *drv_data) INIT_WORK(&drv_data->pump_messages, pump_messages); drv_data->workqueue = create_singlethread_workqueue( - drv_data->master->dev.parent->bus_id); + drv_data->master->cdev.dev->bus_id); if (drv_data->workqueue == NULL) return -EBUSY; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 35d8c01b42ac..6307428d2c94 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -193,7 +193,7 @@ struct spi_device *__init_or_module spi_new_device(struct spi_master *master, struct spi_board_info *chip) { struct spi_device *proxy; - struct device *dev = &master->dev; + struct device *dev = master->cdev.dev; int status; /* NOTE: caller did any chip->bus_num checks necessary */ @@ -215,7 +215,7 @@ spi_new_device(struct spi_master *master, struct spi_board_info *chip) proxy->modalias = chip->modalias; snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id, - "%s.%u", master->dev.bus_id, + "%s.%u", master->cdev.class_id, chip->chip_select); proxy->dev.parent = dev; proxy->dev.bus = &spi_bus_type; @@ -290,7 +290,7 @@ static void __init_or_module scan_boardinfo(struct spi_master *master) { struct boardinfo *bi; - struct device *dev = master->dev.parent; + struct device *dev = master->cdev.dev; down(&board_lock); list_for_each_entry(bi, &board_list, list) { @@ -319,18 +319,18 @@ scan_boardinfo(struct spi_master *master) /*-------------------------------------------------------------------------*/ -static void spi_master_release(struct device *dev) +static void spi_master_release(struct class_device *cdev) { struct spi_master *master; - master = container_of(dev, struct spi_master, dev); + master = container_of(cdev, struct spi_master, cdev); kfree(master); } static struct class spi_master_class = { .name = "spi_master", .owner = THIS_MODULE, - .dev_release = spi_master_release, + .release = spi_master_release, }; @@ -364,9 +364,9 @@ spi_alloc_master(struct device *dev, unsigned size) if (!master) return NULL; - device_initialize(&master->dev); - master->dev.class = &spi_master_class; - master->dev.parent = get_device(dev); + class_device_initialize(&master->cdev); + master->cdev.class = &spi_master_class; + master->cdev.dev = get_device(dev); spi_master_set_devdata(master, &master[1]); return master; @@ -396,7 +396,7 @@ int __init_or_module spi_register_master(struct spi_master *master) { static atomic_t dyn_bus_id = ATOMIC_INIT((1<<16) - 1); - struct device *dev = master->dev.parent; + struct device *dev = master->cdev.dev; int status = -ENODEV; int dynamic = 0; @@ -412,12 +412,12 @@ spi_register_master(struct spi_master *master) /* register the device, then userspace will see it. * registration fails if the bus ID is in use. */ - snprintf(master->dev.bus_id, sizeof master->dev.bus_id, + snprintf(master->cdev.class_id, sizeof master->cdev.class_id, "spi%u", master->bus_num); - status = device_add(&master->dev); + status = class_device_add(&master->cdev); if (status < 0) goto done; - dev_dbg(dev, "registered master %s%s\n", master->dev.bus_id, + dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id, dynamic ? " (dynamic)" : ""); /* populate children from any spi device tables */ @@ -449,8 +449,8 @@ void spi_unregister_master(struct spi_master *master) { int dummy; - dummy = device_for_each_child(&master->dev, NULL, __unregister); - device_unregister(&master->dev); + dummy = device_for_each_child(master->cdev.dev, NULL, __unregister); + class_device_unregister(&master->cdev); } EXPORT_SYMBOL_GPL(spi_unregister_master); @@ -471,7 +471,7 @@ struct spi_master *spi_busnum_to_master(u16 bus_num) down(&spi_master_class.sem); list_for_each_entry(cdev, &spi_master_class.children, node) { - m = container_of(cdev, struct spi_master, dev.kobj); + m = container_of(cdev, struct spi_master, cdev); if (m->bus_num == bus_num) { master = spi_master_get(m); break; diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 4638e6c83715..57289b61d0be 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -479,7 +479,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) /* this task is the only thing to touch the SPI bits */ bitbang->busy = 0; bitbang->workqueue = create_singlethread_workqueue( - bitbang->master->dev.parent->bus_id); + bitbang->master->cdev.dev->bus_id); if (bitbang->workqueue == NULL) { status = -EBUSY; goto err1; @@ -513,14 +513,14 @@ int spi_bitbang_stop(struct spi_bitbang *bitbang) while (!list_empty(&bitbang->queue) && limit--) { spin_unlock_irq(&bitbang->lock); - dev_dbg(&bitbang->master->dev, "wait for queue\n"); + dev_dbg(bitbang->master->cdev.dev, "wait for queue\n"); msleep(10); spin_lock_irq(&bitbang->lock); } spin_unlock_irq(&bitbang->lock); if (!list_empty(&bitbang->queue)) { - dev_err(&bitbang->master->dev, "queue didn't empty\n"); + dev_err(bitbang->master->cdev.dev, "queue didn't empty\n"); return -EBUSY; } diff --git a/drivers/spi/spi_butterfly.c b/drivers/spi/spi_butterfly.c index 31b7970ae463..312987a03210 100644 --- a/drivers/spi/spi_butterfly.c +++ b/drivers/spi/spi_butterfly.c @@ -246,7 +246,7 @@ static void butterfly_attach(struct parport *p) * and no way to be selective about what it binds to. */ - /* FIXME where should master->dev.parent come from? + /* FIXME where should master->cdev.dev come from? * e.g. /sys/bus/pnp0/00:0b, some PCI thing, etc * setting up a platform device like this is an ugly kluge... */ @@ -386,7 +386,7 @@ static void butterfly_detach(struct parport *p) butterfly = NULL; /* stop() unregisters child devices too */ - pdev = to_platform_device(pp->bitbang.master->dev.parent); + pdev = to_platform_device(pp->bitbang.master->cdev.dev); status = spi_bitbang_stop(&pp->bitbang); /* turn off VCC */ diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 8c2edd82a073..176f6e36dbfa 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -170,7 +170,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * message's completion function when the transaction completes. */ struct spi_master { - struct device dev; + struct class_device cdev; /* other than negative (== assign one dynamically), bus_num is fully * board-specific. usually that simplifies to being SOC-specific. @@ -216,17 +216,17 @@ struct spi_master { static inline void *spi_master_get_devdata(struct spi_master *master) { - return dev_get_drvdata(&master->dev); + return class_get_devdata(&master->cdev); } static inline void spi_master_set_devdata(struct spi_master *master, void *data) { - dev_set_drvdata(&master->dev, data); + class_set_devdata(&master->cdev, data); } static inline struct spi_master *spi_master_get(struct spi_master *master) { - if (!master || !get_device(&master->dev)) + if (!master || !class_device_get(&master->cdev)) return NULL; return master; } @@ -234,7 +234,7 @@ static inline struct spi_master *spi_master_get(struct spi_master *master) static inline void spi_master_put(struct spi_master *master) { if (master) - put_device(&master->dev); + class_device_put(&master->cdev); } -- cgit v1.2.3 From f3cc28c797604fa1cda4aef3f250f465de54a0ca Mon Sep 17 00:00:00 2001 From: Jay Cliburn Date: Thu, 8 Feb 2007 10:42:37 -0500 Subject: Add Attansic L1 ethernet driver. This driver is a modified version of the Attansic reference driver for the L1 ethernet adapter. Attansic has granted permission for its inclusion in the mainline kernel. Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 11 + drivers/net/Makefile | 1 + drivers/net/atl1/Makefile | 2 + drivers/net/atl1/atl1.h | 283 +++++ drivers/net/atl1/atl1_ethtool.c | 508 ++++++++ drivers/net/atl1/atl1_hw.c | 718 ++++++++++++ drivers/net/atl1/atl1_hw.h | 951 +++++++++++++++ drivers/net/atl1/atl1_main.c | 2468 +++++++++++++++++++++++++++++++++++++++ drivers/net/atl1/atl1_param.c | 206 ++++ include/linux/pci_ids.h | 2 + 10 files changed, 5150 insertions(+) create mode 100644 drivers/net/atl1/Makefile create mode 100644 drivers/net/atl1/atl1.h create mode 100644 drivers/net/atl1/atl1_ethtool.c create mode 100644 drivers/net/atl1/atl1_hw.c create mode 100644 drivers/net/atl1/atl1_hw.h create mode 100644 drivers/net/atl1/atl1_main.c create mode 100644 drivers/net/atl1/atl1_param.c (limited to 'include/linux') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ad92b6a76ee6..4f2ffbd81dc1 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2335,6 +2335,17 @@ config QLA3XXX To compile this driver as a module, choose M here: the module will be called qla3xxx. +config ATL1 + tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)" + depends on NET_PCI && PCI && EXPERIMENTAL + select CRC32 + select MII + help + This driver supports the Attansic L1 gigabit ethernet adapter. + + To compile this driver as a module, choose M here. The module + will be called atl1. + endmenu # diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 0878e3df5174..33af833667da 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_CHELSIO_T1) += chelsio/ obj-$(CONFIG_CHELSIO_T3) += cxgb3/ obj-$(CONFIG_EHEA) += ehea/ obj-$(CONFIG_BONDING) += bonding/ +obj-$(CONFIG_ATL1) += atl1/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o gianfar_driver-objs := gianfar.o \ diff --git a/drivers/net/atl1/Makefile b/drivers/net/atl1/Makefile new file mode 100644 index 000000000000..a6b707e4e69e --- /dev/null +++ b/drivers/net/atl1/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ATL1) += atl1.o +atl1-y += atl1_main.o atl1_hw.o atl1_ethtool.o atl1_param.o diff --git a/drivers/net/atl1/atl1.h b/drivers/net/atl1/atl1.h new file mode 100644 index 000000000000..b1c6034e68fa --- /dev/null +++ b/drivers/net/atl1/atl1.h @@ -0,0 +1,283 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _ATL1_H_ +#define _ATL1_H_ + +#include +#include + +#include "atl1_hw.h" + +/* function prototypes needed by multiple files */ +s32 atl1_up(struct atl1_adapter *adapter); +void atl1_down(struct atl1_adapter *adapter); +int atl1_reset(struct atl1_adapter *adapter); +s32 atl1_setup_ring_resources(struct atl1_adapter *adapter); +void atl1_free_ring_resources(struct atl1_adapter *adapter); + +extern char atl1_driver_name[]; +extern char atl1_driver_version[]; +extern const struct ethtool_ops atl1_ethtool_ops; + +struct atl1_adapter; + +#define ATL1_MAX_INTR 3 + +#define ATL1_DEFAULT_TPD 256 +#define ATL1_MAX_TPD 1024 +#define ATL1_MIN_TPD 64 +#define ATL1_DEFAULT_RFD 512 +#define ATL1_MIN_RFD 128 +#define ATL1_MAX_RFD 2048 + +#define ATL1_GET_DESC(R, i, type) (&(((type *)((R)->desc))[i])) +#define ATL1_RFD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_free_desc) +#define ATL1_TPD_DESC(R, i) ATL1_GET_DESC(R, i, struct tx_packet_desc) +#define ATL1_RRD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_return_desc) + +/* + * Some workarounds require millisecond delays and are run during interrupt + * context. Most notably, when establishing link, the phy may need tweaking + * but cannot process phy register reads/writes faster than millisecond + * intervals...and we establish link due to a "link status change" interrupt. + */ + +/* + * wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer + */ +struct atl1_buffer { + struct sk_buff *skb; + u16 length; + u16 alloced; + dma_addr_t dma; +}; + +#define MAX_TX_BUF_LEN 0x3000 /* 12KB */ + +struct atl1_tpd_ring { + void *desc; /* pointer to the descriptor ring memory */ + dma_addr_t dma; /* physical adress of the descriptor ring */ + u16 size; /* length of descriptor ring in bytes */ + u16 count; /* number of descriptors in the ring */ + u16 hw_idx; /* hardware index */ + atomic_t next_to_clean; + atomic_t next_to_use; + struct atl1_buffer *buffer_info; +}; + +struct atl1_rfd_ring { + void *desc; + dma_addr_t dma; + u16 size; + u16 count; + atomic_t next_to_use; + u16 next_to_clean; + struct atl1_buffer *buffer_info; +}; + +struct atl1_rrd_ring { + void *desc; + dma_addr_t dma; + unsigned int size; + u16 count; + u16 next_to_use; + atomic_t next_to_clean; +}; + +struct atl1_ring_header { + void *desc; /* pointer to the descriptor ring memory */ + dma_addr_t dma; /* physical adress of the descriptor ring */ + unsigned int size; /* length of descriptor ring in bytes */ +}; + +struct atl1_cmb { + struct coals_msg_block *cmb; + dma_addr_t dma; +}; + +struct atl1_smb { + struct stats_msg_block *smb; + dma_addr_t dma; +}; + +/* Statistics counters */ +struct atl1_sft_stats { + u64 rx_packets; + u64 tx_packets; + u64 rx_bytes; + u64 tx_bytes; + u64 multicast; + u64 collisions; + u64 rx_errors; + u64 rx_length_errors; + u64 rx_crc_errors; + u64 rx_frame_errors; + u64 rx_fifo_errors; + u64 rx_missed_errors; + u64 tx_errors; + u64 tx_fifo_errors; + u64 tx_aborted_errors; + u64 tx_window_errors; + u64 tx_carrier_errors; + + u64 tx_pause; /* num Pause packet transmitted. */ + u64 excecol; /* num tx packets aborted due to excessive collisions. */ + u64 deffer; /* num deferred tx packets */ + u64 scc; /* num packets subsequently transmitted successfully w/ single prior collision. */ + u64 mcc; /* num packets subsequently transmitted successfully w/ multiple prior collisions. */ + u64 latecol; /* num tx packets w/ late collisions. */ + u64 tx_underun; /* num tx packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */ + u64 tx_trunc; /* num tx packets truncated due to size exceeding MTU, regardless whether truncated by Selene or not. (The name doesn't really reflect the meaning in this case.) */ + u64 rx_pause; /* num Pause packets received. */ + u64 rx_rrd_ov; + u64 rx_trunc; +}; + +/* board specific private data structure */ +#define ATL1_REGS_LEN 8 + +/* Structure containing variables used by the shared code */ +struct atl1_hw { + u8 __iomem *hw_addr; + struct atl1_adapter *back; + enum atl1_dma_order dma_ord; + enum atl1_dma_rcb rcb_value; + enum atl1_dma_req_block dmar_block; + enum atl1_dma_req_block dmaw_block; + u8 preamble_len; + u8 max_retry; /* Retransmission maximum, after which the packet will be discarded */ + u8 jam_ipg; /* IPG to start JAM for collision based flow control in half-duplex mode. In units of 8-bit time */ + u8 ipgt; /* Desired back to back inter-packet gap. The default is 96-bit time */ + u8 min_ifg; /* Minimum number of IFG to enforce in between RX frames. Frame gap below such IFP is dropped */ + u8 ipgr1; /* 64bit Carrier-Sense window */ + u8 ipgr2; /* 96-bit IPG window */ + u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned burst. Each TPD is 16 bytes long */ + u8 rfd_burst; /* Number of RFD to prefetch in cache-aligned burst. Each RFD is 12 bytes long */ + u8 rfd_fetch_gap; + u8 rrd_burst; /* Threshold number of RRDs that can be retired in a burst. Each RRD is 16 bytes long */ + u8 tpd_fetch_th; + u8 tpd_fetch_gap; + u16 tx_jumbo_task_th; + u16 txf_burst; /* Number of data bytes to read in a cache-aligned burst. Each SRAM entry is + 8 bytes long */ + u16 rx_jumbo_th; /* Jumbo packet size for non-VLAN packet. VLAN packets should add 4 bytes */ + u16 rx_jumbo_lkah; + u16 rrd_ret_timer; /* RRD retirement timer. Decrement by 1 after every 512ns passes. */ + u16 lcol; /* Collision Window */ + + u16 cmb_tpd; + u16 cmb_rrd; + u16 cmb_rx_timer; + u16 cmb_tx_timer; + u32 smb_timer; + u16 media_type; + u16 autoneg_advertised; + u16 pci_cmd_word; + + u16 mii_autoneg_adv_reg; + u16 mii_1000t_ctrl_reg; + + u32 mem_rang; + u32 txcw; + u32 max_frame_size; + u32 min_frame_size; + u32 mc_filter_type; + u32 num_mc_addrs; + u32 collision_delta; + u32 tx_packet_delta; + u16 phy_spd_default; + + u16 dev_rev; + u8 revision_id; + + /* spi flash */ + u8 flash_vendor; + + u8 dma_fairness; + u8 mac_addr[ETH_ALEN]; + u8 perm_mac_addr[ETH_ALEN]; + + /* bool phy_preamble_sup; */ + bool phy_configured; +}; + +struct atl1_adapter { + /* OS defined structs */ + struct net_device *netdev; + struct pci_dev *pdev; + struct net_device_stats net_stats; + struct atl1_sft_stats soft_stats; + + struct vlan_group *vlgrp; + u32 rx_buffer_len; + u32 wol; + u16 link_speed; + u16 link_duplex; + spinlock_t lock; + atomic_t irq_sem; + struct work_struct tx_timeout_task; + struct work_struct link_chg_task; + struct work_struct pcie_dma_to_rst_task; + struct timer_list watchdog_timer; + struct timer_list phy_config_timer; + bool phy_timer_pending; + + bool mac_disabled; + + /* All descriptor rings' memory */ + struct atl1_ring_header ring_header; + + /* TX */ + struct atl1_tpd_ring tpd_ring; + spinlock_t mb_lock; + + /* RX */ + struct atl1_rfd_ring rfd_ring; + struct atl1_rrd_ring rrd_ring; + u64 hw_csum_err; + u64 hw_csum_good; + + u32 gorcl; + u64 gorcl_old; + + /* Interrupt Moderator timer ( 2us resolution) */ + u16 imt; + /* Interrupt Clear timer (2us resolution) */ + u16 ict; + + /* MII interface info */ + struct mii_if_info mii; + + /* structs defined in atl1_hw.h */ + u32 bd_number; /* board number */ + bool pci_using_64; + struct atl1_hw hw; + struct atl1_smb smb; + struct atl1_cmb cmb; + + u32 pci_state[16]; +}; + +#endif /* _ATL1_H_ */ diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c new file mode 100644 index 000000000000..c11c27798e5c --- /dev/null +++ b/drivers/net/atl1/atl1_ethtool.c @@ -0,0 +1,508 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "atl1.h" + +struct atl1_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define ATL1_STAT(m) sizeof(((struct atl1_adapter *)0)->m), \ + offsetof(struct atl1_adapter, m) + +static struct atl1_stats atl1_gstrings_stats[] = { + {"rx_packets", ATL1_STAT(soft_stats.rx_packets)}, + {"tx_packets", ATL1_STAT(soft_stats.tx_packets)}, + {"rx_bytes", ATL1_STAT(soft_stats.rx_bytes)}, + {"tx_bytes", ATL1_STAT(soft_stats.tx_bytes)}, + {"rx_errors", ATL1_STAT(soft_stats.rx_errors)}, + {"tx_errors", ATL1_STAT(soft_stats.tx_errors)}, + {"rx_dropped", ATL1_STAT(net_stats.rx_dropped)}, + {"tx_dropped", ATL1_STAT(net_stats.tx_dropped)}, + {"multicast", ATL1_STAT(soft_stats.multicast)}, + {"collisions", ATL1_STAT(soft_stats.collisions)}, + {"rx_length_errors", ATL1_STAT(soft_stats.rx_length_errors)}, + {"rx_over_errors", ATL1_STAT(soft_stats.rx_missed_errors)}, + {"rx_crc_errors", ATL1_STAT(soft_stats.rx_crc_errors)}, + {"rx_frame_errors", ATL1_STAT(soft_stats.rx_frame_errors)}, + {"rx_fifo_errors", ATL1_STAT(soft_stats.rx_fifo_errors)}, + {"rx_missed_errors", ATL1_STAT(soft_stats.rx_missed_errors)}, + {"tx_aborted_errors", ATL1_STAT(soft_stats.tx_aborted_errors)}, + {"tx_carrier_errors", ATL1_STAT(soft_stats.tx_carrier_errors)}, + {"tx_fifo_errors", ATL1_STAT(soft_stats.tx_fifo_errors)}, + {"tx_window_errors", ATL1_STAT(soft_stats.tx_window_errors)}, + {"tx_abort_exce_coll", ATL1_STAT(soft_stats.excecol)}, + {"tx_abort_late_coll", ATL1_STAT(soft_stats.latecol)}, + {"tx_deferred_ok", ATL1_STAT(soft_stats.deffer)}, + {"tx_single_coll_ok", ATL1_STAT(soft_stats.scc)}, + {"tx_multi_coll_ok", ATL1_STAT(soft_stats.mcc)}, + {"tx_underun", ATL1_STAT(soft_stats.tx_underun)}, + {"tx_trunc", ATL1_STAT(soft_stats.tx_trunc)}, + {"tx_pause", ATL1_STAT(soft_stats.tx_pause)}, + {"rx_pause", ATL1_STAT(soft_stats.rx_pause)}, + {"rx_rrd_ov", ATL1_STAT(soft_stats.rx_rrd_ov)}, + {"rx_trunc", ATL1_STAT(soft_stats.rx_trunc)} +}; + +static void atl1_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int i; + char *p; + + for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) { + p = (char *)adapter+atl1_gstrings_stats[i].stat_offset; + data[i] = (atl1_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } + +} + +static int atl1_get_stats_count(struct net_device *netdev) +{ + return ARRAY_SIZE(atl1_gstrings_stats); +} + +static int atl1_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_TP); + ecmd->advertising = ADVERTISED_TP; + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + ecmd->advertising |= ADVERTISED_Autoneg; + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR) { + ecmd->advertising |= ADVERTISED_Autoneg; + ecmd->advertising |= + (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full); + } + else + ecmd->advertising |= (ADVERTISED_1000baseT_Full); + } + ecmd->port = PORT_TP; + ecmd->phy_address = 0; + ecmd->transceiver = XCVR_INTERNAL; + + if (netif_carrier_ok(adapter->netdev)) { + u16 link_speed, link_duplex; + atl1_get_speed_and_duplex(hw, &link_speed, &link_duplex); + ecmd->speed = link_speed; + if (link_duplex == FULL_DUPLEX) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) + ecmd->autoneg = AUTONEG_ENABLE; + else + ecmd->autoneg = AUTONEG_DISABLE; + + return 0; +} + +static int atl1_set_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + u16 phy_data; + int ret_val = 0; + u16 old_media_type = hw->media_type; + + if (netif_running(adapter->netdev)) { + printk(KERN_DEBUG "%s: ethtool shutting down adapter\n", + atl1_driver_name); + atl1_down(adapter); + } + + if (ecmd->autoneg == AUTONEG_ENABLE) + hw->media_type = MEDIA_TYPE_AUTO_SENSOR; + else { + if (ecmd->speed == SPEED_1000) { + if (ecmd->duplex != DUPLEX_FULL) { + printk(KERN_WARNING + "%s: can't force to 1000M half duplex\n", + atl1_driver_name); + ret_val = -EINVAL; + goto exit_sset; + } + hw->media_type = MEDIA_TYPE_1000M_FULL; + } else if (ecmd->speed == SPEED_100) { + if (ecmd->duplex == DUPLEX_FULL) { + hw->media_type = MEDIA_TYPE_100M_FULL; + } else + hw->media_type = MEDIA_TYPE_100M_HALF; + } else { + if (ecmd->duplex == DUPLEX_FULL) + hw->media_type = MEDIA_TYPE_10M_FULL; + else + hw->media_type = MEDIA_TYPE_10M_HALF; + } + } + switch (hw->media_type) { + case MEDIA_TYPE_AUTO_SENSOR: + ecmd->advertising = + ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full | + ADVERTISED_Autoneg | ADVERTISED_TP; + break; + case MEDIA_TYPE_1000M_FULL: + ecmd->advertising = + ADVERTISED_1000baseT_Full | + ADVERTISED_Autoneg | ADVERTISED_TP; + break; + default: + ecmd->advertising = 0; + break; + } + if (atl1_phy_setup_autoneg_adv(hw)) { + ret_val = -EINVAL; + printk(KERN_WARNING + "%s: invalid ethtool speed/duplex setting\n", + atl1_driver_name); + goto exit_sset; + } + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; + else { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 | + MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF: */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + break; + } + } + atl1_write_phy_reg(hw, MII_BMCR, phy_data); +exit_sset: + if (ret_val) + hw->media_type = old_media_type; + + if (netif_running(adapter->netdev)) { + printk(KERN_DEBUG "%s: ethtool starting adapter\n", + atl1_driver_name); + atl1_up(adapter); + } else if (!ret_val) { + printk(KERN_DEBUG "%s: ethtool resetting adapter\n", + atl1_driver_name); + atl1_reset(adapter); + } + return ret_val; +} + +static void atl1_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + strncpy(drvinfo->driver, atl1_driver_name, sizeof(drvinfo->driver)); + strncpy(drvinfo->version, atl1_driver_version, + sizeof(drvinfo->version)); + strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); + strncpy(drvinfo->bus_info, pci_name(adapter->pdev), + sizeof(drvinfo->bus_info)); + drvinfo->eedump_len = ATL1_EEDUMP_LEN; +} + +static void atl1_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC; + wol->wolopts = 0; + if (adapter->wol & ATL1_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if (adapter->wol & ATL1_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if (adapter->wol & ATL1_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if (adapter->wol & ATL1_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; + return; +} + +static int atl1_set_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) + return -EOPNOTSUPP; + adapter->wol = 0; + if (wol->wolopts & WAKE_UCAST) + adapter->wol |= ATL1_WUFC_EX; + if (wol->wolopts & WAKE_MCAST) + adapter->wol |= ATL1_WUFC_MC; + if (wol->wolopts & WAKE_BCAST) + adapter->wol |= ATL1_WUFC_BC; + if (wol->wolopts & WAKE_MAGIC) + adapter->wol |= ATL1_WUFC_MAG; + return 0; +} + +static void atl1_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_tpd_ring *txdr = &adapter->tpd_ring; + struct atl1_rfd_ring *rxdr = &adapter->rfd_ring; + + ring->rx_max_pending = ATL1_MAX_RFD; + ring->tx_max_pending = ATL1_MAX_TPD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rxdr->count; + ring->tx_pending = txdr->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int atl1_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_tpd_ring *tpdr = &adapter->tpd_ring; + struct atl1_rrd_ring *rrdr = &adapter->rrd_ring; + struct atl1_rfd_ring *rfdr = &adapter->rfd_ring; + + struct atl1_tpd_ring tpd_old, tpd_new; + struct atl1_rfd_ring rfd_old, rfd_new; + struct atl1_rrd_ring rrd_old, rrd_new; + struct atl1_ring_header rhdr_old, rhdr_new; + int err; + + tpd_old = adapter->tpd_ring; + rfd_old = adapter->rfd_ring; + rrd_old = adapter->rrd_ring; + rhdr_old = adapter->ring_header; + + if (netif_running(adapter->netdev)) + atl1_down(adapter); + + rfdr->count = (u16) max(ring->rx_pending, (u32) ATL1_MIN_RFD); + rfdr->count = rfdr->count > ATL1_MAX_RFD ? ATL1_MAX_RFD : + rfdr->count; + rfdr->count = (rfdr->count + 3) & ~3; + rrdr->count = rfdr->count; + + tpdr->count = (u16) max(ring->tx_pending, (u32) ATL1_MIN_TPD); + tpdr->count = tpdr->count > ATL1_MAX_TPD ? ATL1_MAX_TPD : + tpdr->count; + tpdr->count = (tpdr->count + 3) & ~3; + + if (netif_running(adapter->netdev)) { + /* try to get new resources before deleting old */ + err = atl1_setup_ring_resources(adapter); + if (err) + goto err_setup_ring; + + /* + * save the new, restore the old in order to free it, + * then restore the new back again + */ + + rfd_new = adapter->rfd_ring; + rrd_new = adapter->rrd_ring; + tpd_new = adapter->tpd_ring; + rhdr_new = adapter->ring_header; + adapter->rfd_ring = rfd_old; + adapter->rrd_ring = rrd_old; + adapter->tpd_ring = tpd_old; + adapter->ring_header = rhdr_old; + atl1_free_ring_resources(adapter); + adapter->rfd_ring = rfd_new; + adapter->rrd_ring = rrd_new; + adapter->tpd_ring = tpd_new; + adapter->ring_header = rhdr_new; + + err = atl1_up(adapter); + if (err) + return err; + } + return 0; + +err_setup_ring: + adapter->rfd_ring = rfd_old; + adapter->rrd_ring = rrd_old; + adapter->tpd_ring = tpd_old; + adapter->ring_header = rhdr_old; + atl1_up(adapter); + return err; +} + +static void atl1_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *epause) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + epause->autoneg = AUTONEG_ENABLE; + } else { + epause->autoneg = AUTONEG_DISABLE; + } + epause->rx_pause = 1; + epause->tx_pause = 1; +} + +static int atl1_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *epause) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + epause->autoneg = AUTONEG_ENABLE; + } else { + epause->autoneg = AUTONEG_DISABLE; + } + + epause->rx_pause = 1; + epause->tx_pause = 1; + + return 0; +} + +static u32 atl1_get_rx_csum(struct net_device *netdev) +{ + return 1; +} + +static void atl1_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) { + memcpy(p, atl1_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static int atl1_nway_reset(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + + if (netif_running(netdev)) { + u16 phy_data; + atl1_down(adapter); + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) { + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; + } else { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = MII_CR_FULL_DUPLEX | + MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = MII_CR_FULL_DUPLEX | + MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + } + } + atl1_write_phy_reg(hw, MII_BMCR, phy_data); + atl1_up(adapter); + } + return 0; +} + +const struct ethtool_ops atl1_ethtool_ops = { + .get_settings = atl1_get_settings, + .set_settings = atl1_set_settings, + .get_drvinfo = atl1_get_drvinfo, + .get_wol = atl1_get_wol, + .set_wol = atl1_set_wol, + .get_ringparam = atl1_get_ringparam, + .set_ringparam = atl1_set_ringparam, + .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/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c new file mode 100644 index 000000000000..08b2d785469d --- /dev/null +++ b/drivers/net/atl1/atl1_hw.c @@ -0,0 +1,718 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "atl1.h" + +/* + * Reset the transmit and receive units; mask and clear all interrupts. + * hw - Struct containing variables accessed by shared code + * return : ATL1_SUCCESS or idle status (if error) + */ +s32 atl1_reset_hw(struct atl1_hw *hw) +{ + u32 icr; + int i; + + /* + * Clear Interrupt mask to stop board from generating + * interrupts & Clear any pending interrupt events + */ + /* + * iowrite32(0, hw->hw_addr + REG_IMR); + * iowrite32(0xffffffff, hw->hw_addr + REG_ISR); + */ + + /* + * Issue Soft Reset to the MAC. This will reset the chip's + * transmit, receive, DMA. It will not effect + * the current PCI configuration. The global reset bit is self- + * clearing, and should clear within a microsecond. + */ + iowrite32(MASTER_CTRL_SOFT_RST, hw->hw_addr + REG_MASTER_CTRL); + ioread32(hw->hw_addr + REG_MASTER_CTRL); + + iowrite16(1, hw->hw_addr + REG_GPHY_ENABLE); + ioread16(hw->hw_addr + REG_GPHY_ENABLE); + + msleep(1); /* delay about 1ms */ + + /* Wait at least 10ms for All module to be Idle */ + for (i = 0; i < 10; i++) { + icr = ioread32(hw->hw_addr + REG_IDLE_STATUS); + if (!icr) + break; + msleep(1); /* delay 1 ms */ + cpu_relax(); /* FIXME: is this still the right way to do this? */ + } + + if (icr) { + printk (KERN_DEBUG "icr = %x\n", icr); + return icr; + } + + return ATL1_SUCCESS; +} + +/* function about EEPROM + * + * check_eeprom_exist + * return 0 if eeprom exist + */ +static int atl1_check_eeprom_exist(struct atl1_hw *hw) +{ + u32 value; + value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL); + if (value & SPI_FLASH_CTRL_EN_VPD) { + value &= ~SPI_FLASH_CTRL_EN_VPD; + iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL); + } + + value = ioread16(hw->hw_addr + REG_PCIE_CAP_LIST); + return ((value & 0xFF00) == 0x6C00) ? 0 : 1; +} + +static bool atl1_read_eeprom(struct atl1_hw *hw, u32 offset, u32 *p_value) +{ + int i; + u32 control; + + if (offset & 3) + return false; /* address do not align */ + + iowrite32(0, hw->hw_addr + REG_VPD_DATA); + control = (offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT; + iowrite32(control, hw->hw_addr + REG_VPD_CAP); + ioread32(hw->hw_addr + REG_VPD_CAP); + + for (i = 0; i < 10; i++) { + msleep(2); + control = ioread32(hw->hw_addr + REG_VPD_CAP); + if (control & VPD_CAP_VPD_FLAG) + break; + } + if (control & VPD_CAP_VPD_FLAG) { + *p_value = ioread32(hw->hw_addr + REG_VPD_DATA); + return true; + } + return false; /* timeout */ +} + +/* + * Reads the value from a PHY register + * hw - Struct containing variables accessed by shared code + * reg_addr - address of the PHY register to read + */ +s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data) +{ + u32 val; + int i; + + val = ((u32) (reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT | + MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 << + MDIO_CLK_SEL_SHIFT; + iowrite32(val, hw->hw_addr + REG_MDIO_CTRL); + ioread32(hw->hw_addr + REG_MDIO_CTRL); + + for (i = 0; i < MDIO_WAIT_TIMES; i++) { + udelay(2); + val = ioread32(hw->hw_addr + REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + if (!(val & (MDIO_START | MDIO_BUSY))) { + *phy_data = (u16) val; + return ATL1_SUCCESS; + } + return ATL1_ERR_PHY; +} + +#define CUSTOM_SPI_CS_SETUP 2 +#define CUSTOM_SPI_CLK_HI 2 +#define CUSTOM_SPI_CLK_LO 2 +#define CUSTOM_SPI_CS_HOLD 2 +#define CUSTOM_SPI_CS_HI 3 + +static bool atl1_spi_read(struct atl1_hw *hw, u32 addr, u32 *buf) +{ + int i; + u32 value; + + iowrite32(0, hw->hw_addr + REG_SPI_DATA); + iowrite32(addr, hw->hw_addr + REG_SPI_ADDR); + + value = SPI_FLASH_CTRL_WAIT_READY | + (CUSTOM_SPI_CS_SETUP & SPI_FLASH_CTRL_CS_SETUP_MASK) << + SPI_FLASH_CTRL_CS_SETUP_SHIFT | (CUSTOM_SPI_CLK_HI & + SPI_FLASH_CTRL_CLK_HI_MASK) << + SPI_FLASH_CTRL_CLK_HI_SHIFT | (CUSTOM_SPI_CLK_LO & + SPI_FLASH_CTRL_CLK_LO_MASK) << + SPI_FLASH_CTRL_CLK_LO_SHIFT | (CUSTOM_SPI_CS_HOLD & + SPI_FLASH_CTRL_CS_HOLD_MASK) << + SPI_FLASH_CTRL_CS_HOLD_SHIFT | (CUSTOM_SPI_CS_HI & + SPI_FLASH_CTRL_CS_HI_MASK) << + SPI_FLASH_CTRL_CS_HI_SHIFT | (1 & SPI_FLASH_CTRL_INS_MASK) << + SPI_FLASH_CTRL_INS_SHIFT; + + iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL); + + value |= SPI_FLASH_CTRL_START; + iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL); + ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL); + + for (i = 0; i < 10; i++) { + msleep(1); /* 1ms */ + value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL); + if (!(value & SPI_FLASH_CTRL_START)) + break; + } + + if (value & SPI_FLASH_CTRL_START) + return false; + + *buf = ioread32(hw->hw_addr + REG_SPI_DATA); + + return true; +} + +/* + * get_permanent_address + * return 0 if get valid mac address, + */ +static int atl1_get_permanent_address(struct atl1_hw *hw) +{ + u32 addr[2]; + u32 i, control; + u16 reg; + u8 eth_addr[ETH_ALEN]; + bool key_valid; + + if (is_valid_ether_addr(hw->perm_mac_addr)) + return 0; + + /* init */ + addr[0] = addr[1] = 0; + + if (!atl1_check_eeprom_exist(hw)) { /* eeprom exist */ + reg = 0; + key_valid = false; + /* Read out all EEPROM content */ + i = 0; + while (1) { + if (atl1_read_eeprom(hw, i + 0x100, &control)) { + if (key_valid) { + if (reg == REG_MAC_STA_ADDR) + addr[0] = control; + else if (reg == (REG_MAC_STA_ADDR + 4)) + addr[1] = control; + key_valid = false; + } else if ((control & 0xff) == 0x5A) { + key_valid = true; + reg = (u16) (control >> 16); + } else + break; /* assume data end while encount an invalid KEYWORD */ + } else + break; /* read error */ + i += 4; + } + +/* + * The following 2 lines are the Attansic originals. Saving for posterity. + * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]); + * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]); + */ + *(u32 *) & eth_addr[2] = swab32(addr[0]); + *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]); + + if (is_valid_ether_addr(eth_addr)) { + memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); + return 0; + } + return 1; + } + + /* see if SPI FLAGS exist ? */ + addr[0] = addr[1] = 0; + reg = 0; + key_valid = false; + i = 0; + while (1) { + if (atl1_spi_read(hw, i + 0x1f000, &control)) { + if (key_valid) { + if (reg == REG_MAC_STA_ADDR) + addr[0] = control; + else if (reg == (REG_MAC_STA_ADDR + 4)) + addr[1] = control; + key_valid = false; + } else if ((control & 0xff) == 0x5A) { + key_valid = true; + reg = (u16) (control >> 16); + } else + break; /* data end */ + } else + break; /* read error */ + i += 4; + } + +/* + * The following 2 lines are the Attansic originals. Saving for posterity. + * *(u32 *) & eth_addr[2] = LONGSWAP(addr[0]); + * *(u16 *) & eth_addr[0] = SHORTSWAP(*(u16 *) & addr[1]); + */ + *(u32 *) & eth_addr[2] = swab32(addr[0]); + *(u16 *) & eth_addr[0] = swab16(*(u16 *) & addr[1]); + if (is_valid_ether_addr(eth_addr)) { + memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); + return 0; + } + return 1; +} + +/* + * Reads the adapter's MAC address from the EEPROM + * hw - Struct containing variables accessed by shared code + */ +s32 atl1_read_mac_addr(struct atl1_hw *hw) +{ + u16 i; + + if (atl1_get_permanent_address(hw)) + random_ether_addr(hw->perm_mac_addr); + + for (i = 0; i < ETH_ALEN; i++) + hw->mac_addr[i] = hw->perm_mac_addr[i]; + return ATL1_SUCCESS; +} + +/* + * Hashes an address to determine its location in the multicast table + * hw - Struct containing variables accessed by shared code + * mc_addr - the multicast address to hash + * + * atl1_hash_mc_addr + * purpose + * set hash value for a multicast address + * hash calcu processing : + * 1. calcu 32bit CRC for multicast address + * 2. reverse crc with MSB to LSB + */ +u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr) +{ + u32 crc32, value = 0; + int i; + + crc32 = ether_crc_le(6, mc_addr); + crc32 = ~crc32; + for (i = 0; i < 32; i++) + value |= (((crc32 >> i) & 1) << (31 - i)); + + return value; +} + +/* + * Sets the bit in the multicast table corresponding to the hash value. + * hw - Struct containing variables accessed by shared code + * hash_value - Multicast address hash value + */ +void atl1_hash_set(struct atl1_hw *hw, u32 hash_value) +{ + u32 hash_bit, hash_reg; + u32 mta; + + /* + * The HASH Table is a register array of 2 32-bit registers. + * It is treated like an array of 64 bits. We want to set + * bit BitArray[hash_value]. So we figure out what register + * the bit is in, read it, OR in the new bit, then write + * back the new value. The register is determined by the + * upper 7 bits of the hash value and the bit within that + * register are determined by the lower 5 bits of the value. + */ + hash_reg = (hash_value >> 31) & 0x1; + hash_bit = (hash_value >> 26) & 0x1F; + mta = ioread32((hw + REG_RX_HASH_TABLE) + (hash_reg << 2)); + mta |= (1 << hash_bit); + iowrite32(mta, (hw->hw_addr + REG_RX_HASH_TABLE) + (hash_reg << 2)); +} + +/* + * Writes a value to a PHY register + * hw - Struct containing variables accessed by shared code + * reg_addr - address of the PHY register to write + * data - data to write to the PHY + */ +s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data) +{ + int i; + u32 val; + + val = ((u32) (phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT | + (reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT | + MDIO_SUP_PREAMBLE | + MDIO_START | MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; + iowrite32(val, hw->hw_addr + REG_MDIO_CTRL); + ioread32(hw->hw_addr + REG_MDIO_CTRL); + + for (i = 0; i < MDIO_WAIT_TIMES; i++) { + udelay(2); + val = ioread32(hw->hw_addr + REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + + if (!(val & (MDIO_START | MDIO_BUSY))) + return ATL1_SUCCESS; + + return ATL1_ERR_PHY; +} + +/* + * Make L001's PHY out of Power Saving State (bug) + * hw - Struct containing variables accessed by shared code + * when power on, L001's PHY always on Power saving State + * (Gigabit Link forbidden) + */ +static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw) +{ + s32 ret; + ret = atl1_write_phy_reg(hw, 29, 0x0029); + if (ret) + return ret; + return atl1_write_phy_reg(hw, 30, 0); +} + +/* + *TODO: do something or get rid of this + */ +s32 atl1_phy_enter_power_saving(struct atl1_hw *hw) +{ +/* s32 ret_val; + * u16 phy_data; + */ + +/* + ret_val = atl1_write_phy_reg(hw, ...); + ret_val = atl1_write_phy_reg(hw, ...); + .... +*/ + return ATL1_SUCCESS; +} + +/* + * Resets the PHY and make all config validate + * hw - Struct containing variables accessed by shared code + * + * Sets bit 15 and 12 of the MII Control regiser (for F001 bug) + */ +static s32 atl1_phy_reset(struct atl1_hw *hw) +{ + s32 ret_val; + u16 phy_data; + + if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR || + hw->media_type == MEDIA_TYPE_1000M_FULL) + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN; + else { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 | + MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF: */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + break; + } + } + + ret_val = atl1_write_phy_reg(hw, MII_BMCR, phy_data); + if (ret_val) { + u32 val; + int i; + /* pcie serdes link may be down! */ + printk(KERN_DEBUG "%s: autoneg caused pcie phy link down\n", + atl1_driver_name); + + for (i = 0; i < 25; i++) { + msleep(1); + val = ioread32(hw->hw_addr + REG_MDIO_CTRL); + if (!(val & (MDIO_START | MDIO_BUSY))) + break; + } + + if ((val & (MDIO_START | MDIO_BUSY)) != 0) { + printk(KERN_WARNING + "%s: pcie link down at least for 25ms\n", + atl1_driver_name); + return ret_val; + } + } + return ATL1_SUCCESS; +} + +/* + * Configures PHY autoneg and flow control advertisement settings + * hw - Struct containing variables accessed by shared code + */ +s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw) +{ + s32 ret_val; + s16 mii_autoneg_adv_reg; + s16 mii_1000t_ctrl_reg; + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK; + + /* Read the MII 1000Base-T Control Register (Address 9). */ + mii_1000t_ctrl_reg = MII_AT001_CR_1000T_DEFAULT_CAP_MASK; + + /* + * 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 &= ~MII_AR_SPEED_MASK; + mii_1000t_ctrl_reg &= ~MII_AT001_CR_1000T_SPEED_MASK; + + /* + * Need to parse media_type and set up + * the appropriate PHY registers. + */ + switch (hw->media_type) { + case MEDIA_TYPE_AUTO_SENSOR: + mii_autoneg_adv_reg |= (MII_AR_10T_HD_CAPS | + MII_AR_10T_FD_CAPS | + MII_AR_100TX_HD_CAPS | + MII_AR_100TX_FD_CAPS); + mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS; + break; + + case MEDIA_TYPE_1000M_FULL: + mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS; + break; + + case MEDIA_TYPE_100M_FULL: + mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS; + break; + + case MEDIA_TYPE_100M_HALF: + mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS; + break; + + case MEDIA_TYPE_10M_FULL: + mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS; + break; + + default: + mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS; + break; + } + + /* flow control fixed to enable all */ + mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE); + + hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg; + hw->mii_1000t_ctrl_reg = mii_1000t_ctrl_reg; + + ret_val = atl1_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg); + if (ret_val) + return ret_val; + + ret_val = atl1_write_phy_reg(hw, MII_AT001_CR, mii_1000t_ctrl_reg); + if (ret_val) + return ret_val; + + return ATL1_SUCCESS; +} + +/* + * Configures link settings. + * hw - Struct containing variables accessed by shared code + * Assumes the hardware has previously been reset and the + * transmitter and receiver are not enabled. + */ +static s32 atl1_setup_link(struct atl1_hw *hw) +{ + s32 ret_val; + + /* + * Options: + * PHY will advertise value(s) parsed from + * autoneg_advertised and fc + * no matter what autoneg is , We will not wait link result. + */ + ret_val = atl1_phy_setup_autoneg_adv(hw); + if (ret_val) { + printk(KERN_DEBUG "%s: error setting up autonegotiation\n", + atl1_driver_name); + return ret_val; + } + /* SW.Reset , En-Auto-Neg if needed */ + ret_val = atl1_phy_reset(hw); + if (ret_val) { + printk(KERN_DEBUG "%s: error resetting the phy\n", + atl1_driver_name); + return ret_val; + } + hw->phy_configured = true; + return ret_val; +} + +static struct atl1_spi_flash_dev flash_table[] = { +/* MFR_NAME WRSR READ PRGM WREN WRDI RDSR RDID SECTOR_ERASE CHIP_ERASE */ + {"Atmel", 0x00, 0x03, 0x02, 0x06, 0x04, 0x05, 0x15, 0x52, 0x62}, + {"SST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0x90, 0x20, 0x60}, + {"ST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0xAB, 0xD8, 0xC7}, +}; + +static void atl1_init_flash_opcode(struct atl1_hw *hw) +{ + if (hw->flash_vendor >= sizeof(flash_table) / sizeof(flash_table[0])) + hw->flash_vendor = 0; /* ATMEL */ + + /* Init OP table */ + iowrite8(flash_table[hw->flash_vendor].cmd_program, + hw->hw_addr + REG_SPI_FLASH_OP_PROGRAM); + iowrite8(flash_table[hw->flash_vendor].cmd_sector_erase, + hw->hw_addr + REG_SPI_FLASH_OP_SC_ERASE); + iowrite8(flash_table[hw->flash_vendor].cmd_chip_erase, + hw->hw_addr + REG_SPI_FLASH_OP_CHIP_ERASE); + iowrite8(flash_table[hw->flash_vendor].cmd_rdid, + hw->hw_addr + REG_SPI_FLASH_OP_RDID); + iowrite8(flash_table[hw->flash_vendor].cmd_wren, + hw->hw_addr + REG_SPI_FLASH_OP_WREN); + iowrite8(flash_table[hw->flash_vendor].cmd_rdsr, + hw->hw_addr + REG_SPI_FLASH_OP_RDSR); + iowrite8(flash_table[hw->flash_vendor].cmd_wrsr, + hw->hw_addr + REG_SPI_FLASH_OP_WRSR); + iowrite8(flash_table[hw->flash_vendor].cmd_read, + hw->hw_addr + REG_SPI_FLASH_OP_READ); +} + +/* + * Performs basic configuration of the adapter. + * hw - Struct containing variables accessed by shared code + * Assumes that the controller has previously been reset and is in a + * post-reset uninitialized state. Initializes multicast table, + * and Calls routines to setup link + * Leaves the transmit and receive units disabled and uninitialized. + */ +s32 atl1_init_hw(struct atl1_hw *hw) +{ + u32 ret_val = 0; + + /* Zero out the Multicast HASH table */ + iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE); + /* clear the old settings from the multicast hash table */ + iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2)); + + atl1_init_flash_opcode(hw); + + if (!hw->phy_configured) { + /* enable GPHY LinkChange Interrrupt */ + ret_val = atl1_write_phy_reg(hw, 18, 0xC00); + if (ret_val) + return ret_val; + /* make PHY out of power-saving state */ + ret_val = atl1_phy_leave_power_saving(hw); + if (ret_val) + return ret_val; + /* Call a subroutine to configure the link */ + ret_val = atl1_setup_link(hw); + } + return ret_val; +} + +/* + * Detects the current speed and duplex settings of the hardware. + * hw - Struct containing variables accessed by shared code + * speed - Speed of the connection + * duplex - Duplex setting of the connection + */ +s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex) +{ + s32 ret_val; + u16 phy_data; + + /* ; --- Read PHY Specific Status Register (17) */ + ret_val = atl1_read_phy_reg(hw, MII_AT001_PSSR, &phy_data); + if (ret_val) + return ret_val; + + if (!(phy_data & MII_AT001_PSSR_SPD_DPLX_RESOLVED)) + return ATL1_ERR_PHY_RES; + + switch (phy_data & MII_AT001_PSSR_SPEED) { + case MII_AT001_PSSR_1000MBS: + *speed = SPEED_1000; + break; + case MII_AT001_PSSR_100MBS: + *speed = SPEED_100; + break; + case MII_AT001_PSSR_10MBS: + *speed = SPEED_10; + break; + default: + printk(KERN_DEBUG "%s: error getting speed\n", + atl1_driver_name); + return ATL1_ERR_PHY_SPEED; + break; + } + if (phy_data & MII_AT001_PSSR_DPLX) + *duplex = FULL_DUPLEX; + else + *duplex = HALF_DUPLEX; + + return ATL1_SUCCESS; +} + +void atl1_set_mac_addr(struct atl1_hw *hw) +{ + u32 value; + /* + * 00-0B-6A-F6-00-DC + * 0: 6AF600DC 1: 000B + * low dword + */ + value = (((u32) hw->mac_addr[2]) << 24) | + (((u32) hw->mac_addr[3]) << 16) | + (((u32) hw->mac_addr[4]) << 8) | (((u32) hw->mac_addr[5])); + iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR); + /* high dword */ + value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1])); + iowrite32(value, (hw->hw_addr + REG_MAC_STA_ADDR) + (1 << 2)); +} diff --git a/drivers/net/atl1/atl1_hw.h b/drivers/net/atl1/atl1_hw.h new file mode 100644 index 000000000000..100c09c66e64 --- /dev/null +++ b/drivers/net/atl1/atl1_hw.h @@ -0,0 +1,951 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * There are a lot of defines in here that are unused and/or have cryptic + * names. Please leave them alone, as they're the closest thing we have + * to a spec from Attansic at present. *ahem* -- CHS + */ + +#ifndef _ATL1_HW_H_ +#define _ATL1_HW_H_ + +#include +#include + +struct atl1_adapter; +struct atl1_hw; + +/* function prototypes needed by multiple files */ +s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw); +s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data); +s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex); +s32 atl1_read_mac_addr(struct atl1_hw *hw); +s32 atl1_init_hw(struct atl1_hw *hw); +s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex); +s32 atl1_set_speed_and_duplex(struct atl1_hw *hw, u16 speed, u16 duplex); +u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr); +void atl1_hash_set(struct atl1_hw *hw, u32 hash_value); +s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data); +void atl1_set_mac_addr(struct atl1_hw *hw); +s32 atl1_phy_enter_power_saving(struct atl1_hw *hw); +s32 atl1_reset_hw(struct atl1_hw *hw); +void atl1_check_options(struct atl1_adapter *adapter); + +/* register definitions */ +#define REG_PCIE_CAP_LIST 0x58 + +#define REG_VPD_CAP 0x6C +#define VPD_CAP_ID_MASK 0xff +#define VPD_CAP_ID_SHIFT 0 +#define VPD_CAP_NEXT_PTR_MASK 0xFF +#define VPD_CAP_NEXT_PTR_SHIFT 8 +#define VPD_CAP_VPD_ADDR_MASK 0x7FFF +#define VPD_CAP_VPD_ADDR_SHIFT 16 +#define VPD_CAP_VPD_FLAG 0x80000000 + +#define REG_VPD_DATA 0x70 + +#define REG_SPI_FLASH_CTRL 0x200 +#define SPI_FLASH_CTRL_STS_NON_RDY 0x1 +#define SPI_FLASH_CTRL_STS_WEN 0x2 +#define SPI_FLASH_CTRL_STS_WPEN 0x80 +#define SPI_FLASH_CTRL_DEV_STS_MASK 0xFF +#define SPI_FLASH_CTRL_DEV_STS_SHIFT 0 +#define SPI_FLASH_CTRL_INS_MASK 0x7 +#define SPI_FLASH_CTRL_INS_SHIFT 8 +#define SPI_FLASH_CTRL_START 0x800 +#define SPI_FLASH_CTRL_EN_VPD 0x2000 +#define SPI_FLASH_CTRL_LDSTART 0x8000 +#define SPI_FLASH_CTRL_CS_HI_MASK 0x3 +#define SPI_FLASH_CTRL_CS_HI_SHIFT 16 +#define SPI_FLASH_CTRL_CS_HOLD_MASK 0x3 +#define SPI_FLASH_CTRL_CS_HOLD_SHIFT 18 +#define SPI_FLASH_CTRL_CLK_LO_MASK 0x3 +#define SPI_FLASH_CTRL_CLK_LO_SHIFT 20 +#define SPI_FLASH_CTRL_CLK_HI_MASK 0x3 +#define SPI_FLASH_CTRL_CLK_HI_SHIFT 22 +#define SPI_FLASH_CTRL_CS_SETUP_MASK 0x3 +#define SPI_FLASH_CTRL_CS_SETUP_SHIFT 24 +#define SPI_FLASH_CTRL_EROM_PGSZ_MASK 0x3 +#define SPI_FLASH_CTRL_EROM_PGSZ_SHIFT 26 +#define SPI_FLASH_CTRL_WAIT_READY 0x10000000 + +#define REG_SPI_ADDR 0x204 + +#define REG_SPI_DATA 0x208 + +#define REG_SPI_FLASH_CONFIG 0x20C +#define SPI_FLASH_CONFIG_LD_ADDR_MASK 0xFFFFFF +#define SPI_FLASH_CONFIG_LD_ADDR_SHIFT 0 +#define SPI_FLASH_CONFIG_VPD_ADDR_MASK 0x3 +#define SPI_FLASH_CONFIG_VPD_ADDR_SHIFT 24 +#define SPI_FLASH_CONFIG_LD_EXIST 0x4000000 + +#define REG_SPI_FLASH_OP_PROGRAM 0x210 +#define REG_SPI_FLASH_OP_SC_ERASE 0x211 +#define REG_SPI_FLASH_OP_CHIP_ERASE 0x212 +#define REG_SPI_FLASH_OP_RDID 0x213 +#define REG_SPI_FLASH_OP_WREN 0x214 +#define REG_SPI_FLASH_OP_RDSR 0x215 +#define REG_SPI_FLASH_OP_WRSR 0x216 +#define REG_SPI_FLASH_OP_READ 0x217 + +#define REG_TWSI_CTRL 0x218 +#define TWSI_CTRL_LD_OFFSET_MASK 0xFF +#define TWSI_CTRL_LD_OFFSET_SHIFT 0 +#define TWSI_CTRL_LD_SLV_ADDR_MASK 0x7 +#define TWSI_CTRL_LD_SLV_ADDR_SHIFT 8 +#define TWSI_CTRL_SW_LDSTART 0x800 +#define TWSI_CTRL_HW_LDSTART 0x1000 +#define TWSI_CTRL_SMB_SLV_ADDR_MASK 0x7F +#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT 15 +#define TWSI_CTRL_LD_EXIST 0x400000 +#define TWSI_CTRL_READ_FREQ_SEL_MASK 0x3 +#define TWSI_CTRL_READ_FREQ_SEL_SHIFT 23 +#define TWSI_CTRL_FREQ_SEL_100K 0 +#define TWSI_CTRL_FREQ_SEL_200K 1 +#define TWSI_CTRL_FREQ_SEL_300K 2 +#define TWSI_CTRL_FREQ_SEL_400K 3 +#define TWSI_CTRL_SMB_SLV_ADDR +#define TWSI_CTRL_WRITE_FREQ_SEL_MASK 0x3 +#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT 24 + +#define REG_PCIE_DEV_MISC_CTRL 0x21C +#define PCIE_DEV_MISC_CTRL_EXT_PIPE 0x2 +#define PCIE_DEV_MISC_CTRL_RETRY_BUFDIS 0x1 +#define PCIE_DEV_MISC_CTRL_SPIROM_EXIST 0x4 +#define PCIE_DEV_MISC_CTRL_SERDES_ENDIAN 0x8 +#define PCIE_DEV_MISC_CTRL_SERDES_SEL_DIN 0x10 + +/* Selene Master Control Register */ +#define REG_MASTER_CTRL 0x1400 +#define MASTER_CTRL_SOFT_RST 0x1 +#define MASTER_CTRL_MTIMER_EN 0x2 +#define MASTER_CTRL_ITIMER_EN 0x4 +#define MASTER_CTRL_MANUAL_INT 0x8 +#define MASTER_CTRL_REV_NUM_SHIFT 16 +#define MASTER_CTRL_REV_NUM_MASK 0xff +#define MASTER_CTRL_DEV_ID_SHIFT 24 +#define MASTER_CTRL_DEV_ID_MASK 0xff + +/* Timer Initial Value Register */ +#define REG_MANUAL_TIMER_INIT 0x1404 + +/* IRQ ModeratorTimer Initial Value Register */ +#define REG_IRQ_MODU_TIMER_INIT 0x1408 + +#define REG_GPHY_ENABLE 0x140C + +/* IRQ Anti-Lost Timer Initial Value Register */ +#define REG_CMBDISDMA_TIMER 0x140E + +/* Block IDLE Status Register */ +#define REG_IDLE_STATUS 0x1410 +#define IDLE_STATUS_RXMAC 1 +#define IDLE_STATUS_TXMAC 2 +#define IDLE_STATUS_RXQ 4 +#define IDLE_STATUS_TXQ 8 +#define IDLE_STATUS_DMAR 0x10 +#define IDLE_STATUS_DMAW 0x20 +#define IDLE_STATUS_SMB 0x40 +#define IDLE_STATUS_CMB 0x80 + +/* MDIO Control Register */ +#define REG_MDIO_CTRL 0x1414 +#define MDIO_DATA_MASK 0xffff +#define MDIO_DATA_SHIFT 0 +#define MDIO_REG_ADDR_MASK 0x1f +#define MDIO_REG_ADDR_SHIFT 16 +#define MDIO_RW 0x200000 +#define MDIO_SUP_PREAMBLE 0x400000 +#define MDIO_START 0x800000 +#define MDIO_CLK_SEL_SHIFT 24 +#define MDIO_CLK_25_4 0 +#define MDIO_CLK_25_6 2 +#define MDIO_CLK_25_8 3 +#define MDIO_CLK_25_10 4 +#define MDIO_CLK_25_14 5 +#define MDIO_CLK_25_20 6 +#define MDIO_CLK_25_28 7 +#define MDIO_BUSY 0x8000000 +#define MDIO_WAIT_TIMES 30 + +/* MII PHY Status Register */ +#define REG_PHY_STATUS 0x1418 + +/* BIST Control and Status Register0 (for the Packet Memory) */ +#define REG_BIST0_CTRL 0x141c +#define BIST0_NOW 0x1 +#define BIST0_SRAM_FAIL 0x2 +#define BIST0_FUSE_FLAG 0x4 +#define REG_BIST1_CTRL 0x1420 +#define BIST1_NOW 0x1 +#define BIST1_SRAM_FAIL 0x2 +#define BIST1_FUSE_FLAG 0x4 + +/* MAC Control Register */ +#define REG_MAC_CTRL 0x1480 +#define MAC_CTRL_TX_EN 1 +#define MAC_CTRL_RX_EN 2 +#define MAC_CTRL_TX_FLOW 4 +#define MAC_CTRL_RX_FLOW 8 +#define MAC_CTRL_LOOPBACK 0x10 +#define MAC_CTRL_DUPLX 0x20 +#define MAC_CTRL_ADD_CRC 0x40 +#define MAC_CTRL_PAD 0x80 +#define MAC_CTRL_LENCHK 0x100 +#define MAC_CTRL_HUGE_EN 0x200 +#define MAC_CTRL_PRMLEN_SHIFT 10 +#define MAC_CTRL_PRMLEN_MASK 0xf +#define MAC_CTRL_RMV_VLAN 0x4000 +#define MAC_CTRL_PROMIS_EN 0x8000 +#define MAC_CTRL_TX_PAUSE 0x10000 +#define MAC_CTRL_SCNT 0x20000 +#define MAC_CTRL_SRST_TX 0x40000 +#define MAC_CTRL_TX_SIMURST 0x80000 +#define MAC_CTRL_SPEED_SHIFT 20 +#define MAC_CTRL_SPEED_MASK 0x300000 +#define MAC_CTRL_SPEED_1000 2 +#define MAC_CTRL_SPEED_10_100 1 +#define MAC_CTRL_DBG_TX_BKPRESURE 0x400000 +#define MAC_CTRL_TX_HUGE 0x800000 +#define MAC_CTRL_RX_CHKSUM_EN 0x1000000 +#define MAC_CTRL_MC_ALL_EN 0x2000000 +#define MAC_CTRL_BC_EN 0x4000000 +#define MAC_CTRL_DBG 0x8000000 + +/* MAC IPG/IFG Control Register */ +#define REG_MAC_IPG_IFG 0x1484 +#define MAC_IPG_IFG_IPGT_SHIFT 0 +#define MAC_IPG_IFG_IPGT_MASK 0x7f +#define MAC_IPG_IFG_MIFG_SHIFT 8 +#define MAC_IPG_IFG_MIFG_MASK 0xff +#define MAC_IPG_IFG_IPGR1_SHIFT 16 +#define MAC_IPG_IFG_IPGR1_MASK 0x7f +#define MAC_IPG_IFG_IPGR2_SHIFT 24 +#define MAC_IPG_IFG_IPGR2_MASK 0x7f + +/* MAC STATION ADDRESS */ +#define REG_MAC_STA_ADDR 0x1488 + +/* Hash table for multicast address */ +#define REG_RX_HASH_TABLE 0x1490 + +/* MAC Half-Duplex Control Register */ +#define REG_MAC_HALF_DUPLX_CTRL 0x1498 +#define MAC_HALF_DUPLX_CTRL_LCOL_SHIFT 0 +#define MAC_HALF_DUPLX_CTRL_LCOL_MASK 0x3ff +#define MAC_HALF_DUPLX_CTRL_RETRY_SHIFT 12 +#define MAC_HALF_DUPLX_CTRL_RETRY_MASK 0xf +#define MAC_HALF_DUPLX_CTRL_EXC_DEF_EN 0x10000 +#define MAC_HALF_DUPLX_CTRL_NO_BACK_C 0x20000 +#define MAC_HALF_DUPLX_CTRL_NO_BACK_P 0x40000 +#define MAC_HALF_DUPLX_CTRL_ABEBE 0x80000 +#define MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT 20 +#define MAC_HALF_DUPLX_CTRL_ABEBT_MASK 0xf +#define MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT 24 +#define MAC_HALF_DUPLX_CTRL_JAMIPG_MASK 0xf + +/* Maximum Frame Length Control Register */ +#define REG_MTU 0x149c + +/* Wake-On-Lan control register */ +#define REG_WOL_CTRL 0x14a0 +#define WOL_PATTERN_EN 0x00000001 +#define WOL_PATTERN_PME_EN 0x00000002 +#define WOL_MAGIC_EN 0x00000004 +#define WOL_MAGIC_PME_EN 0x00000008 +#define WOL_LINK_CHG_EN 0x00000010 +#define WOL_LINK_CHG_PME_EN 0x00000020 +#define WOL_PATTERN_ST 0x00000100 +#define WOL_MAGIC_ST 0x00000200 +#define WOL_LINKCHG_ST 0x00000400 +#define WOL_CLK_SWITCH_EN 0x00008000 +#define WOL_PT0_EN 0x00010000 +#define WOL_PT1_EN 0x00020000 +#define WOL_PT2_EN 0x00040000 +#define WOL_PT3_EN 0x00080000 +#define WOL_PT4_EN 0x00100000 +#define WOL_PT5_EN 0x00200000 +#define WOL_PT6_EN 0x00400000 + +/* WOL Length ( 2 DWORD ) */ +#define REG_WOL_PATTERN_LEN 0x14a4 +#define WOL_PT_LEN_MASK 0x7f +#define WOL_PT0_LEN_SHIFT 0 +#define WOL_PT1_LEN_SHIFT 8 +#define WOL_PT2_LEN_SHIFT 16 +#define WOL_PT3_LEN_SHIFT 24 +#define WOL_PT4_LEN_SHIFT 0 +#define WOL_PT5_LEN_SHIFT 8 +#define WOL_PT6_LEN_SHIFT 16 + +/* Internal SRAM Partition Register */ +#define REG_SRAM_RFD_ADDR 0x1500 +#define REG_SRAM_RFD_LEN (REG_SRAM_RFD_ADDR+ 4) +#define REG_SRAM_RRD_ADDR (REG_SRAM_RFD_ADDR+ 8) +#define REG_SRAM_RRD_LEN (REG_SRAM_RFD_ADDR+12) +#define REG_SRAM_TPD_ADDR (REG_SRAM_RFD_ADDR+16) +#define REG_SRAM_TPD_LEN (REG_SRAM_RFD_ADDR+20) +#define REG_SRAM_TRD_ADDR (REG_SRAM_RFD_ADDR+24) +#define REG_SRAM_TRD_LEN (REG_SRAM_RFD_ADDR+28) +#define REG_SRAM_RXF_ADDR (REG_SRAM_RFD_ADDR+32) +#define REG_SRAM_RXF_LEN (REG_SRAM_RFD_ADDR+36) +#define REG_SRAM_TXF_ADDR (REG_SRAM_RFD_ADDR+40) +#define REG_SRAM_TXF_LEN (REG_SRAM_RFD_ADDR+44) +#define REG_SRAM_TCPH_PATH_ADDR (REG_SRAM_RFD_ADDR+48) +#define SRAM_TCPH_ADDR_MASK 0x0fff +#define SRAM_TCPH_ADDR_SHIFT 0 +#define SRAM_PATH_ADDR_MASK 0x0fff +#define SRAM_PATH_ADDR_SHIFT 16 + +/* Load Ptr Register */ +#define REG_LOAD_PTR (REG_SRAM_RFD_ADDR+52) + +/* Descriptor Control register */ +#define REG_DESC_BASE_ADDR_HI 0x1540 +#define REG_DESC_RFD_ADDR_LO (REG_DESC_BASE_ADDR_HI+4) +#define REG_DESC_RRD_ADDR_LO (REG_DESC_BASE_ADDR_HI+8) +#define REG_DESC_TPD_ADDR_LO (REG_DESC_BASE_ADDR_HI+12) +#define REG_DESC_CMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+16) +#define REG_DESC_SMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+20) +#define REG_DESC_RFD_RRD_RING_SIZE (REG_DESC_BASE_ADDR_HI+24) +#define DESC_RFD_RING_SIZE_MASK 0x7ff +#define DESC_RFD_RING_SIZE_SHIFT 0 +#define DESC_RRD_RING_SIZE_MASK 0x7ff +#define DESC_RRD_RING_SIZE_SHIFT 16 +#define REG_DESC_TPD_RING_SIZE (REG_DESC_BASE_ADDR_HI+28) +#define DESC_TPD_RING_SIZE_MASK 0x3ff +#define DESC_TPD_RING_SIZE_SHIFT 0 + +/* TXQ Control Register */ +#define REG_TXQ_CTRL 0x1580 +#define TXQ_CTRL_TPD_BURST_NUM_SHIFT 0 +#define TXQ_CTRL_TPD_BURST_NUM_MASK 0x1f +#define TXQ_CTRL_EN 0x20 +#define TXQ_CTRL_ENH_MODE 0x40 +#define TXQ_CTRL_TPD_FETCH_TH_SHIFT 8 +#define TXQ_CTRL_TPD_FETCH_TH_MASK 0x3f +#define TXQ_CTRL_TXF_BURST_NUM_SHIFT 16 +#define TXQ_CTRL_TXF_BURST_NUM_MASK 0xffff + +/* Jumbo packet Threshold for task offload */ +#define REG_TX_JUMBO_TASK_TH_TPD_IPG 0x1584 +#define TX_JUMBO_TASK_TH_MASK 0x7ff +#define TX_JUMBO_TASK_TH_SHIFT 0 +#define TX_TPD_MIN_IPG_MASK 0x1f +#define TX_TPD_MIN_IPG_SHIFT 16 + +/* RXQ Control Register */ +#define REG_RXQ_CTRL 0x15a0 +#define RXQ_CTRL_RFD_BURST_NUM_SHIFT 0 +#define RXQ_CTRL_RFD_BURST_NUM_MASK 0xff +#define RXQ_CTRL_RRD_BURST_THRESH_SHIFT 8 +#define RXQ_CTRL_RRD_BURST_THRESH_MASK 0xff +#define RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT 16 +#define RXQ_CTRL_RFD_PREF_MIN_IPG_MASK 0x1f +#define RXQ_CTRL_CUT_THRU_EN 0x40000000 +#define RXQ_CTRL_EN 0x80000000 + +/* Rx jumbo packet threshold and rrd retirement timer */ +#define REG_RXQ_JMBOSZ_RRDTIM (REG_RXQ_CTRL+ 4) +#define RXQ_JMBOSZ_TH_MASK 0x7ff +#define RXQ_JMBOSZ_TH_SHIFT 0 +#define RXQ_JMBO_LKAH_MASK 0xf +#define RXQ_JMBO_LKAH_SHIFT 11 +#define RXQ_RRD_TIMER_MASK 0xffff +#define RXQ_RRD_TIMER_SHIFT 16 + +/* RFD flow control register */ +#define REG_RXQ_RXF_PAUSE_THRESH (REG_RXQ_CTRL+ 8) +#define RXQ_RXF_PAUSE_TH_HI_SHIFT 16 +#define RXQ_RXF_PAUSE_TH_HI_MASK 0xfff +#define RXQ_RXF_PAUSE_TH_LO_SHIFT 0 +#define RXQ_RXF_PAUSE_TH_LO_MASK 0xfff + +/* RRD flow control register */ +#define REG_RXQ_RRD_PAUSE_THRESH (REG_RXQ_CTRL+12) +#define RXQ_RRD_PAUSE_TH_HI_SHIFT 0 +#define RXQ_RRD_PAUSE_TH_HI_MASK 0xfff +#define RXQ_RRD_PAUSE_TH_LO_SHIFT 16 +#define RXQ_RRD_PAUSE_TH_LO_MASK 0xfff + +/* DMA Engine Control Register */ +#define REG_DMA_CTRL 0x15c0 +#define DMA_CTRL_DMAR_IN_ORDER 0x1 +#define DMA_CTRL_DMAR_ENH_ORDER 0x2 +#define DMA_CTRL_DMAR_OUT_ORDER 0x4 +#define DMA_CTRL_RCB_VALUE 0x8 +#define DMA_CTRL_DMAR_BURST_LEN_SHIFT 4 +#define DMA_CTRL_DMAR_BURST_LEN_MASK 7 +#define DMA_CTRL_DMAW_BURST_LEN_SHIFT 7 +#define DMA_CTRL_DMAW_BURST_LEN_MASK 7 +#define DMA_CTRL_DMAR_EN 0x400 +#define DMA_CTRL_DMAW_EN 0x800 + +/* CMB/SMB Control Register */ +#define REG_CSMB_CTRL 0x15d0 +#define CSMB_CTRL_CMB_NOW 1 +#define CSMB_CTRL_SMB_NOW 2 +#define CSMB_CTRL_CMB_EN 4 +#define CSMB_CTRL_SMB_EN 8 + +/* CMB DMA Write Threshold Register */ +#define REG_CMB_WRITE_TH (REG_CSMB_CTRL+ 4) +#define CMB_RRD_TH_SHIFT 0 +#define CMB_RRD_TH_MASK 0x7ff +#define CMB_TPD_TH_SHIFT 16 +#define CMB_TPD_TH_MASK 0x7ff + +/* RX/TX count-down timer to trigger CMB-write. 2us resolution. */ +#define REG_CMB_WRITE_TIMER (REG_CSMB_CTRL+ 8) +#define CMB_RX_TM_SHIFT 0 +#define CMB_RX_TM_MASK 0xffff +#define CMB_TX_TM_SHIFT 16 +#define CMB_TX_TM_MASK 0xffff + +/* Number of packet received since last CMB write */ +#define REG_CMB_RX_PKT_CNT (REG_CSMB_CTRL+12) + +/* Number of packet transmitted since last CMB write */ +#define REG_CMB_TX_PKT_CNT (REG_CSMB_CTRL+16) + +/* SMB auto DMA timer register */ +#define REG_SMB_TIMER (REG_CSMB_CTRL+20) + +/* Mailbox Register */ +#define REG_MAILBOX 0x15f0 +#define MB_RFD_PROD_INDX_SHIFT 0 +#define MB_RFD_PROD_INDX_MASK 0x7ff +#define MB_RRD_CONS_INDX_SHIFT 11 +#define MB_RRD_CONS_INDX_MASK 0x7ff +#define MB_TPD_PROD_INDX_SHIFT 22 +#define MB_TPD_PROD_INDX_MASK 0x3ff + +/* Interrupt Status Register */ +#define REG_ISR 0x1600 +#define ISR_SMB 1 +#define ISR_TIMER 2 +#define ISR_MANUAL 4 +#define ISR_RXF_OV 8 +#define ISR_RFD_UNRUN 0x10 +#define ISR_RRD_OV 0x20 +#define ISR_TXF_UNRUN 0x40 +#define ISR_LINK 0x80 +#define ISR_HOST_RFD_UNRUN 0x100 +#define ISR_HOST_RRD_OV 0x200 +#define ISR_DMAR_TO_RST 0x400 +#define ISR_DMAW_TO_RST 0x800 +#define ISR_GPHY 0x1000 +#define ISR_RX_PKT 0x10000 +#define ISR_TX_PKT 0x20000 +#define ISR_TX_DMA 0x40000 +#define ISR_RX_DMA 0x80000 +#define ISR_CMB_RX 0x100000 +#define ISR_CMB_TX 0x200000 +#define ISR_MAC_RX 0x400000 +#define ISR_MAC_TX 0x800000 +#define ISR_UR_DETECTED 0x1000000 +#define ISR_FERR_DETECTED 0x2000000 +#define ISR_NFERR_DETECTED 0x4000000 +#define ISR_CERR_DETECTED 0x8000000 +#define ISR_PHY_LINKDOWN 0x10000000 +#define ISR_DIS_SMB 0x20000000 +#define ISR_DIS_DMA 0x40000000 +#define ISR_DIS_INT 0x80000000 + +/* Interrupt Mask Register */ +#define REG_IMR 0x1604 + +/* Normal Interrupt mask */ +#define IMR_NORMAL_MASK (\ + ISR_SMB |\ + ISR_GPHY |\ + ISR_PHY_LINKDOWN|\ + ISR_DMAR_TO_RST |\ + ISR_DMAW_TO_RST |\ + ISR_CMB_TX |\ + ISR_CMB_RX ) + +/* Debug Interrupt Mask (enable all interrupt) */ +#define IMR_DEBUG_MASK (\ + ISR_SMB |\ + ISR_TIMER |\ + ISR_MANUAL |\ + ISR_RXF_OV |\ + ISR_RFD_UNRUN |\ + ISR_RRD_OV |\ + ISR_TXF_UNRUN |\ + ISR_LINK |\ + ISR_CMB_TX |\ + ISR_CMB_RX |\ + ISR_RX_PKT |\ + ISR_TX_PKT |\ + ISR_MAC_RX |\ + ISR_MAC_TX ) + +/* Interrupt Status Register */ +#define REG_RFD_RRD_IDX 0x1800 +#define REG_TPD_IDX 0x1804 + +/* MII definition */ +/* PHY Common Register */ +#define MII_AT001_CR 0x09 +#define MII_AT001_SR 0x0A +#define MII_AT001_ESR 0x0F +#define MII_AT001_PSCR 0x10 +#define MII_AT001_PSSR 0x11 + +/* PHY Control Register */ +#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ +#define MII_CR_POWER_DOWN 0x0800 /* Power down */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ +#define MII_CR_SPEED_MASK 0x2040 +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 + +/* PHY Status Register */ +#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ +#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ +#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ +#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ +#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ +#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ +#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ +#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ +#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ +#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ +#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ +#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ + +/* Link partner ability register. */ +#define MII_LPA_SLCT 0x001f /* Same as advertise selector */ +#define MII_LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */ +#define MII_LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ +#define MII_LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ +#define MII_LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ +#define MII_LPA_100BASE4 0x0200 /* 100BASE-T4 */ +#define MII_LPA_PAUSE 0x0400 /* PAUSE */ +#define MII_LPA_ASYPAUSE 0x0800 /* Asymmetrical PAUSE */ +#define MII_LPA_RFAULT 0x2000 /* Link partner faulted */ +#define MII_LPA_LPACK 0x4000 /* Link partner acked us */ +#define MII_LPA_NPAGE 0x8000 /* Next page bit */ + +/* Autoneg Advertisement Register */ +#define MII_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ +#define MII_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define MII_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define MII_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define MII_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define MII_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ +#define MII_AR_PAUSE 0x0400 /* Pause operation desired */ +#define MII_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ +#define MII_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ +#define MII_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ +#define MII_AR_SPEED_MASK 0x01E0 +#define MII_AR_DEFAULT_CAP_MASK 0x0DE0 + +/* 1000BASE-T Control Register */ +#define MII_AT001_CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define MII_AT001_CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ +#define MII_AT001_CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port, 0=DTE device */ +#define MII_AT001_CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master, 0=Configure PHY as Slave */ +#define MII_AT001_CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value, 0=Automatic Master/Slave config */ +#define MII_AT001_CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ +#define MII_AT001_CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ +#define MII_AT001_CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ +#define MII_AT001_CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ +#define MII_AT001_CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ +#define MII_AT001_CR_1000T_SPEED_MASK 0x0300 +#define MII_AT001_CR_1000T_DEFAULT_CAP_MASK 0x0300 + +/* 1000BASE-T Status Register */ +#define MII_AT001_SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ +#define MII_AT001_SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ +#define MII_AT001_SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define MII_AT001_SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ +#define MII_AT001_SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */ +#define MII_AT001_SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ +#define MII_AT001_SR_1000T_REMOTE_RX_STATUS_SHIFT 12 +#define MII_AT001_SR_1000T_LOCAL_RX_STATUS_SHIFT 13 + +/* Extended Status Register */ +#define MII_AT001_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */ +#define MII_AT001_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */ +#define MII_AT001_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */ +#define MII_AT001_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */ + +/* AT001 PHY Specific Control Register */ +#define MII_AT001_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ +#define MII_AT001_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +#define MII_AT001_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ +#define MII_AT001_PSCR_MAC_POWERDOWN 0x0008 +#define MII_AT001_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, 0=CLK125 toggling */ +#define MII_AT001_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5, Manual MDI configuration */ +#define MII_AT001_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ +#define MII_AT001_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */ +#define MII_AT001_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled all speeds. */ +#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE 0x0080 /* 1=Enable Extended 10BASE-T distance (Lower 10BASE-T RX Threshold), 0=Normal 10BASE-T RX Threshold */ +#define MII_AT001_PSCR_MII_5BIT_ENABLE 0x0100 /* 1=5-Bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */ +#define MII_AT001_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ +#define MII_AT001_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ +#define MII_AT001_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ +#define MII_AT001_PSCR_POLARITY_REVERSAL_SHIFT 1 +#define MII_AT001_PSCR_AUTO_X_MODE_SHIFT 5 +#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7 + +/* AT001 PHY Specific Status Register */ +#define MII_AT001_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ +#define MII_AT001_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ +#define MII_AT001_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ +#define MII_AT001_PSSR_10MBS 0x0000 /* 00=10Mbs */ +#define MII_AT001_PSSR_100MBS 0x4000 /* 01=100Mbs */ +#define MII_AT001_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ + +/* PCI Command Register Bit Definitions */ +#define PCI_REG_COMMAND 0x04 /* PCI Command Register */ +#define CMD_IO_SPACE 0x0001 +#define CMD_MEMORY_SPACE 0x0002 +#define CMD_BUS_MASTER 0x0004 + +/* Wake Up Filter Control */ +#define ATL1_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define ATL1_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define ATL1_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ +#define ATL1_WUFC_MC 0x00000008 /* Multicast Wakeup Enable */ +#define ATL1_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ + +/* Error Codes */ +#define ATL1_SUCCESS 0 +#define ATL1_ERR_EEPROM 1 +#define ATL1_ERR_PHY 2 +#define ATL1_ERR_CONFIG 3 +#define ATL1_ERR_PARAM 4 +#define ATL1_ERR_MAC_TYPE 5 +#define ATL1_ERR_PHY_TYPE 6 +#define ATL1_ERR_PHY_SPEED 7 +#define ATL1_ERR_PHY_RES 8 + +#define SPEED_0 0xffff +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + +#define MEDIA_TYPE_AUTO_SENSOR 0 +#define MEDIA_TYPE_1000M_FULL 1 +#define MEDIA_TYPE_100M_FULL 2 +#define MEDIA_TYPE_100M_HALF 3 +#define MEDIA_TYPE_10M_FULL 4 +#define MEDIA_TYPE_10M_HALF 5 + +#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 +#define ADVERTISE_1000_FULL 0x0020 +#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */ +#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds */ +#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds */ + +/* The size (in bytes) of a ethernet packet */ +#define ENET_HEADER_SIZE 14 +#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* with FCS */ +#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* with FCS */ +#define ETHERNET_FCS_SIZE 4 +#define MAX_JUMBO_FRAME_SIZE 0x2800 + +#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */ +#define PHY_FORCE_TIME 20 /* 2.0 Seconds */ + +/* For checksumming , the sum of all words in the EEPROM should equal 0xBABA */ +#define EEPROM_SUM 0xBABA + +#define ATL1_EEDUMP_LEN 48 + +/* Statistics counters collected by the MAC */ +struct stats_msg_block { + /* rx */ + u32 rx_ok; /* The number of good packet received. */ + u32 rx_bcast; /* The number of good broadcast packet received. */ + u32 rx_mcast; /* The number of good multicast packet received. */ + u32 rx_pause; /* The number of Pause packet received. */ + u32 rx_ctrl; /* The number of Control packet received other than Pause frame. */ + u32 rx_fcs_err; /* The number of packets with bad FCS. */ + u32 rx_len_err; /* The number of packets with mismatch of length field and actual size. */ + u32 rx_byte_cnt; /* The number of bytes of good packet received. FCS is NOT included. */ + u32 rx_runt; /* The number of packets received that are less than 64 byte long and with good FCS. */ + u32 rx_frag; /* The number of packets received that are less than 64 byte long and with bad FCS. */ + u32 rx_sz_64; /* The number of good and bad packets received that are 64 byte long. */ + u32 rx_sz_65_127; /* The number of good and bad packets received that are between 65 and 127-byte long. */ + u32 rx_sz_128_255; /* The number of good and bad packets received that are between 128 and 255-byte long. */ + u32 rx_sz_256_511; /* The number of good and bad packets received that are between 256 and 511-byte long. */ + u32 rx_sz_512_1023; /* The number of good and bad packets received that are between 512 and 1023-byte long. */ + u32 rx_sz_1024_1518; /* The number of good and bad packets received that are between 1024 and 1518-byte long. */ + u32 rx_sz_1519_max; /* The number of good and bad packets received that are between 1519-byte and MTU. */ + u32 rx_sz_ov; /* The number of good and bad packets received that are more than MTU size Å¡C truncated by Selene. */ + u32 rx_rxf_ov; /* The number of frame dropped due to occurrence of RX FIFO overflow. */ + u32 rx_rrd_ov; /* The number of frame dropped due to occurrence of RRD overflow. */ + u32 rx_align_err; /* Alignment Error */ + u32 rx_bcast_byte_cnt; /* The byte count of broadcast packet received, excluding FCS. */ + u32 rx_mcast_byte_cnt; /* The byte count of multicast packet received, excluding FCS. */ + u32 rx_err_addr; /* The number of packets dropped due to address filtering. */ + + /* tx */ + u32 tx_ok; /* The number of good packet transmitted. */ + u32 tx_bcast; /* The number of good broadcast packet transmitted. */ + u32 tx_mcast; /* The number of good multicast packet transmitted. */ + u32 tx_pause; /* The number of Pause packet transmitted. */ + u32 tx_exc_defer; /* The number of packets transmitted with excessive deferral. */ + u32 tx_ctrl; /* The number of packets transmitted is a control frame, excluding Pause frame. */ + u32 tx_defer; /* The number of packets transmitted that is deferred. */ + u32 tx_byte_cnt; /* The number of bytes of data transmitted. FCS is NOT included. */ + u32 tx_sz_64; /* The number of good and bad packets transmitted that are 64 byte long. */ + u32 tx_sz_65_127; /* The number of good and bad packets transmitted that are between 65 and 127-byte long. */ + u32 tx_sz_128_255; /* The number of good and bad packets transmitted that are between 128 and 255-byte long. */ + u32 tx_sz_256_511; /* The number of good and bad packets transmitted that are between 256 and 511-byte long. */ + u32 tx_sz_512_1023; /* The number of good and bad packets transmitted that are between 512 and 1023-byte long. */ + u32 tx_sz_1024_1518; /* The number of good and bad packets transmitted that are between 1024 and 1518-byte long. */ + u32 tx_sz_1519_max; /* The number of good and bad packets transmitted that are between 1519-byte and MTU. */ + u32 tx_1_col; /* The number of packets subsequently transmitted successfully with a single prior collision. */ + u32 tx_2_col; /* The number of packets subsequently transmitted successfully with multiple prior collisions. */ + u32 tx_late_col; /* The number of packets transmitted with late collisions. */ + u32 tx_abort_col; /* The number of transmit packets aborted due to excessive collisions. */ + u32 tx_underrun; /* The number of transmit packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */ + u32 tx_rd_eop; /* The number of times that read beyond the EOP into the next frame area when TRD was not written timely */ + u32 tx_len_err; /* The number of transmit packets with length field does NOT match the actual frame size. */ + u32 tx_trunc; /* The number of transmit packets truncated due to size exceeding MTU. */ + u32 tx_bcast_byte; /* The byte count of broadcast packet transmitted, excluding FCS. */ + u32 tx_mcast_byte; /* The byte count of multicast packet transmitted, excluding FCS. */ + u32 smb_updated; /* 1: SMB Updated. This is used by software as the indication of the statistics update. + * Software should clear this bit as soon as retrieving the statistics information. */ +}; + +/* Coalescing Message Block */ +struct coals_msg_block { + u32 int_stats; /* interrupt status */ + u16 rrd_prod_idx; /* TRD Producer Index. */ + u16 rfd_cons_idx; /* RFD Consumer Index. */ + u16 update; /* Selene sets this bit every time it DMA the CMB to host memory. + * Software supposes to clear this bit when CMB information is processed. */ + u16 tpd_cons_idx; /* TPD Consumer Index. */ +}; + +/* RRD descriptor */ +struct rx_return_desc { + u8 num_buf; /* Number of RFD buffers used by the received packet */ + u8 resved; + u16 buf_indx; /* RFD Index of the first buffer */ + union { + u32 valid; + struct { + u16 rx_chksum; + u16 pkt_size; + } xsum_sz; + } xsz; + + u16 pkt_flg; /* Packet flags */ + u16 err_flg; /* Error flags */ + u16 resved2; + u16 vlan_tag; /* VLAN TAG */ +}; + +#define PACKET_FLAG_ETH_TYPE 0x0080 +#define PACKET_FLAG_VLAN_INS 0x0100 +#define PACKET_FLAG_ERR 0x0200 +#define PACKET_FLAG_IPV4 0x0400 +#define PACKET_FLAG_UDP 0x0800 +#define PACKET_FLAG_TCP 0x1000 +#define PACKET_FLAG_BCAST 0x2000 +#define PACKET_FLAG_MCAST 0x4000 +#define PACKET_FLAG_PAUSE 0x8000 + +#define ERR_FLAG_CRC 0x0001 +#define ERR_FLAG_CODE 0x0002 +#define ERR_FLAG_DRIBBLE 0x0004 +#define ERR_FLAG_RUNT 0x0008 +#define ERR_FLAG_OV 0x0010 +#define ERR_FLAG_TRUNC 0x0020 +#define ERR_FLAG_IP_CHKSUM 0x0040 +#define ERR_FLAG_L4_CHKSUM 0x0080 +#define ERR_FLAG_LEN 0x0100 +#define ERR_FLAG_DES_ADDR 0x0200 + +/* RFD descriptor */ +struct rx_free_desc { + __le64 buffer_addr; /* Address of the descriptor's data buffer */ + __le16 buf_len; /* Size of the receive buffer in host memory, in byte */ + u16 coalese; /* Update consumer index to host after the reception of this frame */ + /* __attribute__ ((packed)) is required */ +} __attribute__ ((packed)); + +/* tsopu defines */ +#define TSO_PARAM_BUFLEN_MASK 0x3FFF +#define TSO_PARAM_BUFLEN_SHIFT 0 +#define TSO_PARAM_DMAINT_MASK 0x0001 +#define TSO_PARAM_DMAINT_SHIFT 14 +#define TSO_PARAM_PKTNT_MASK 0x0001 +#define TSO_PARAM_PKTINT_SHIFT 15 +#define TSO_PARAM_VLANTAG_MASK 0xFFFF +#define TSO_PARAM_VLAN_SHIFT 16 + +/* tsopl defines */ +#define TSO_PARAM_EOP_MASK 0x0001 +#define TSO_PARAM_EOP_SHIFT 0 +#define TSO_PARAM_COALESCE_MASK 0x0001 +#define TSO_PARAM_COALESCE_SHIFT 1 +#define TSO_PARAM_INSVLAG_MASK 0x0001 +#define TSO_PARAM_INSVLAG_SHIFT 2 +#define TSO_PARAM_CUSTOMCKSUM_MASK 0x0001 +#define TSO_PARAM_CUSTOMCKSUM_SHIFT 3 +#define TSO_PARAM_SEGMENT_MASK 0x0001 +#define TSO_PARAM_SEGMENT_SHIFT 4 +#define TSO_PARAM_IPCKSUM_MASK 0x0001 +#define TSO_PARAM_IPCKSUM_SHIFT 5 +#define TSO_PARAM_TCPCKSUM_MASK 0x0001 +#define TSO_PARAM_TCPCKSUM_SHIFT 6 +#define TSO_PARAM_UDPCKSUM_MASK 0x0001 +#define TSO_PARAM_UDPCKSUM_SHIFT 7 +#define TSO_PARAM_VLANTAGGED_MASK 0x0001 +#define TSO_PARAM_VLANTAGGED_SHIFT 8 +#define TSO_PARAM_ETHTYPE_MASK 0x0001 +#define TSO_PARAM_ETHTYPE_SHIFT 9 +#define TSO_PARAM_IPHL_MASK 0x000F +#define TSO_PARAM_IPHL_SHIFT 10 +#define TSO_PARAM_TCPHDRLEN_MASK 0x000F +#define TSO_PARAM_TCPHDRLEN_SHIFT 14 +#define TSO_PARAM_HDRFLAG_MASK 0x0001 +#define TSO_PARAM_HDRFLAG_SHIFT 18 +#define TSO_PARAM_MSS_MASK 0x1FFF +#define TSO_PARAM_MSS_SHIFT 19 + +/* csumpu defines */ +#define CSUM_PARAM_BUFLEN_MASK 0x3FFF +#define CSUM_PARAM_BUFLEN_SHIFT 0 +#define CSUM_PARAM_DMAINT_MASK 0x0001 +#define CSUM_PARAM_DMAINT_SHIFT 14 +#define CSUM_PARAM_PKTINT_MASK 0x0001 +#define CSUM_PARAM_PKTINT_SHIFT 15 +#define CSUM_PARAM_VALANTAG_MASK 0xFFFF +#define CSUM_PARAM_VALAN_SHIFT 16 + +/* csumpl defines*/ +#define CSUM_PARAM_EOP_MASK 0x0001 +#define CSUM_PARAM_EOP_SHIFT 0 +#define CSUM_PARAM_COALESCE_MASK 0x0001 +#define CSUM_PARAM_COALESCE_SHIFT 1 +#define CSUM_PARAM_INSVLAG_MASK 0x0001 +#define CSUM_PARAM_INSVLAG_SHIFT 2 +#define CSUM_PARAM_CUSTOMCKSUM_MASK 0x0001 +#define CSUM_PARAM_CUSTOMCKSUM_SHIFT 3 +#define CSUM_PARAM_SEGMENT_MASK 0x0001 +#define CSUM_PARAM_SEGMENT_SHIFT 4 +#define CSUM_PARAM_IPCKSUM_MASK 0x0001 +#define CSUM_PARAM_IPCKSUM_SHIFT 5 +#define CSUM_PARAM_TCPCKSUM_MASK 0x0001 +#define CSUM_PARAM_TCPCKSUM_SHIFT 6 +#define CSUM_PARAM_UDPCKSUM_MASK 0x0001 +#define CSUM_PARAM_UDPCKSUM_SHIFT 7 +#define CSUM_PARAM_VLANTAGGED_MASK 0x0001 +#define CSUM_PARAM_VLANTAGGED_SHIFT 8 +#define CSUM_PARAM_ETHTYPE_MASK 0x0001 +#define CSUM_PARAM_ETHTYPE_SHIFT 9 +#define CSUM_PARAM_IPHL_MASK 0x000F +#define CSUM_PARAM_IPHL_SHIFT 10 +#define CSUM_PARAM_PLOADOFFSET_MASK 0x00FF +#define CSUM_PARAM_PLOADOFFSET_SHIFT 16 +#define CSUM_PARAM_XSUMOFFSET_MASK 0x00FF +#define CSUM_PARAM_XSUMOFFSET_SHIFT 24 + +/* TPD descriptor */ +struct tso_param { + /* The order of these declarations is important -- don't change it */ + u32 tsopu; /* tso_param upper word */ + u32 tsopl; /* tso_param lower word */ +}; + +struct csum_param { + /* The order of these declarations is important -- don't change it */ + u32 csumpu; /* csum_param upper word */ + u32 csumpl; /* csum_param lower word */ +}; + +union tpd_descr { + u64 data; + struct csum_param csum; + struct tso_param tso; +}; + +struct tx_packet_desc { + __le64 buffer_addr; + union tpd_descr desc; +}; + +/* DMA Order Settings */ +enum atl1_dma_order { + atl1_dma_ord_in = 1, + atl1_dma_ord_enh = 2, + atl1_dma_ord_out = 4 +}; + +enum atl1_dma_rcb { + atl1_rcb_64 = 0, + atl1_rcb_128 = 1 +}; + +enum atl1_dma_req_block { + atl1_dma_req_128 = 0, + atl1_dma_req_256 = 1, + atl1_dma_req_512 = 2, + atl1_dam_req_1024 = 3, + atl1_dam_req_2048 = 4, + atl1_dma_req_4096 = 5 +}; + +struct atl1_spi_flash_dev { + const char *manu_name; /* manufacturer id */ + /* op-code */ + u8 cmd_wrsr; + u8 cmd_read; + u8 cmd_program; + u8 cmd_wren; + u8 cmd_wrdi; + u8 cmd_rdsr; + u8 cmd_rdid; + u8 cmd_sector_erase; + u8 cmd_chip_erase; +}; + +#endif /* _ATL1_HW_H_ */ diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c new file mode 100644 index 000000000000..6655640eb4ca --- /dev/null +++ b/drivers/net/atl1/atl1_main.c @@ -0,0 +1,2468 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The full GNU General Public License is included in this distribution in the + * file called COPYING. + * + * Contact Information: + * Xiong Huang + * Attansic Technology Corp. 3F 147, Xianzheng 9th Road, Zhubei, + * Xinzhu 302, TAIWAN, REPUBLIC OF CHINA + * + * Chris Snook + * Jay Cliburn + * + * This version is adapted from the Attansic reference driver for + * inclusion in the Linux kernel. It is currently under heavy development. + * A very incomplete list of things that need to be dealt with: + * + * TODO: + * Fix TSO; tx performance is horrible with TSO enabled. + * Wake on LAN. + * Add more ethtool functions, including set ring parameters. + * Fix abstruse irq enable/disable condition described here: + * http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2 + * + * NEEDS TESTING: + * VLAN + * multicast + * promiscuous mode + * interrupt coalescing + * SMP torture testing + */ + +#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 "atl1.h" + +#define RUN_REALTIME 0 +#define DRIVER_VERSION "2.0.6" + +char atl1_driver_name[] = "atl1"; +static const char atl1_driver_string[] = "Attansic L1 Ethernet Network Driver"; +static const char atl1_copyright[] = "Copyright(c) 2005-2006 Attansic Corporation."; +char atl1_driver_version[] = DRIVER_VERSION; + +MODULE_AUTHOR + ("Attansic Corporation , Chris Snook , Jay Cliburn "); +MODULE_DESCRIPTION("Attansic 1000M Ethernet Network Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); + +/* + * atl1_pci_tbl - PCI Device ID Table + */ +static const struct pci_device_id atl1_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1048)}, + /* required last entry */ + {0,} +}; + +MODULE_DEVICE_TABLE(pci, atl1_pci_tbl); + +/* + * atl1_sw_init - Initialize general software structures (struct atl1_adapter) + * @adapter: board private structure to initialize + * + * atl1_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 atl1_sw_init(struct atl1_adapter *adapter) +{ + struct atl1_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + + /* PCI config space info */ + pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); + + hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; + hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE; + + adapter->wol = 0; + adapter->rx_buffer_len = (hw->max_frame_size + 7) & ~7; + adapter->ict = 50000; /* 100ms */ + adapter->link_speed = SPEED_0; /* hardware init */ + adapter->link_duplex = FULL_DUPLEX; + + hw->phy_configured = false; + hw->preamble_len = 7; + hw->ipgt = 0x60; + hw->min_ifg = 0x50; + hw->ipgr1 = 0x40; + hw->ipgr2 = 0x60; + hw->max_retry = 0xf; + hw->lcol = 0x37; + hw->jam_ipg = 7; + hw->rfd_burst = 8; + hw->rrd_burst = 8; + hw->rfd_fetch_gap = 1; + hw->rx_jumbo_th = adapter->rx_buffer_len / 8; + hw->rx_jumbo_lkah = 1; + hw->rrd_ret_timer = 16; + hw->tpd_burst = 4; + hw->tpd_fetch_th = 16; + hw->txf_burst = 0x100; + hw->tx_jumbo_task_th = (hw->max_frame_size + 7) >> 3; + hw->tpd_fetch_gap = 1; + hw->rcb_value = atl1_rcb_64; + hw->dma_ord = atl1_dma_ord_enh; + hw->dmar_block = atl1_dma_req_256; + hw->dmaw_block = atl1_dma_req_256; + hw->cmb_rrd = 4; + hw->cmb_tpd = 4; + hw->cmb_rx_timer = 1; /* about 2us */ + hw->cmb_tx_timer = 1; /* about 2us */ + hw->smb_timer = 100000; /* about 200ms */ + + atomic_set(&adapter->irq_sem, 0); + spin_lock_init(&adapter->lock); + spin_lock_init(&adapter->mb_lock); + + return 0; +} + +/* + * atl1_setup_mem_resources - allocate Tx / RX descriptor resources + * @adapter: board private structure + * + * Return 0 on success, negative on failure + */ +s32 atl1_setup_ring_resources(struct atl1_adapter *adapter) +{ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_ring_header *ring_header = &adapter->ring_header; + struct pci_dev *pdev = adapter->pdev; + int size; + u8 offset = 0; + + size = sizeof(struct atl1_buffer) * (tpd_ring->count + rfd_ring->count); + tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL); + if (unlikely(!tpd_ring->buffer_info)) { + printk(KERN_WARNING "%s: kzalloc failed , size = D%d\n", + atl1_driver_name, size); + goto err_nomem; + } + rfd_ring->buffer_info = + (struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count); + + /* real ring DMA buffer */ + ring_header->size = size = sizeof(struct tx_packet_desc) * + tpd_ring->count + + sizeof(struct rx_free_desc) * rfd_ring->count + + sizeof(struct rx_return_desc) * rrd_ring->count + + sizeof(struct coals_msg_block) + + sizeof(struct stats_msg_block) + + 40; /* "40: for 8 bytes align" huh? -- CHS */ + + ring_header->desc = pci_alloc_consistent(pdev, ring_header->size, + &ring_header->dma); + if (unlikely(!ring_header->desc)) { + printk(KERN_WARNING + "%s: pci_alloc_consistent failed, size = D%d\n", + atl1_driver_name, size); + goto err_nomem; + } + + memset(ring_header->desc, 0, ring_header->size); + + /* init TPD ring */ + tpd_ring->dma = ring_header->dma; + offset = (tpd_ring->dma & 0x7) ? (8 - (ring_header->dma & 0x7)) : 0; + tpd_ring->dma += offset; + tpd_ring->desc = (u8 *) ring_header->desc + offset; + tpd_ring->size = sizeof(struct tx_packet_desc) * tpd_ring->count; + atomic_set(&tpd_ring->next_to_use, 0); + atomic_set(&tpd_ring->next_to_clean, 0); + + /* init RFD ring */ + rfd_ring->dma = tpd_ring->dma + tpd_ring->size; + offset = (rfd_ring->dma & 0x7) ? (8 - (rfd_ring->dma & 0x7)) : 0; + rfd_ring->dma += offset; + rfd_ring->desc = (u8 *) tpd_ring->desc + (tpd_ring->size + offset); + rfd_ring->size = sizeof(struct rx_free_desc) * rfd_ring->count; + rfd_ring->next_to_clean = 0; + /* rfd_ring->next_to_use = rfd_ring->count - 1; */ + atomic_set(&rfd_ring->next_to_use, 0); + + /* init RRD ring */ + rrd_ring->dma = rfd_ring->dma + rfd_ring->size; + offset = (rrd_ring->dma & 0x7) ? (8 - (rrd_ring->dma & 0x7)) : 0; + rrd_ring->dma += offset; + rrd_ring->desc = (u8 *) rfd_ring->desc + (rfd_ring->size + offset); + rrd_ring->size = sizeof(struct rx_return_desc) * rrd_ring->count; + rrd_ring->next_to_use = 0; + atomic_set(&rrd_ring->next_to_clean, 0); + + /* init CMB */ + adapter->cmb.dma = rrd_ring->dma + rrd_ring->size; + offset = (adapter->cmb.dma & 0x7) ? (8 - (adapter->cmb.dma & 0x7)) : 0; + adapter->cmb.dma += offset; + adapter->cmb.cmb = + (struct coals_msg_block *) ((u8 *) rrd_ring->desc + + (rrd_ring->size + offset)); + + /* init SMB */ + adapter->smb.dma = adapter->cmb.dma + sizeof(struct coals_msg_block); + offset = (adapter->smb.dma & 0x7) ? (8 - (adapter->smb.dma & 0x7)) : 0; + adapter->smb.dma += offset; + adapter->smb.smb = (struct stats_msg_block *) + ((u8 *) adapter->cmb.cmb + (sizeof(struct coals_msg_block) + offset)); + + return ATL1_SUCCESS; + +err_nomem: + kfree(tpd_ring->buffer_info); + return -ENOMEM; +} + +/* + * atl1_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + */ +static void atl1_irq_enable(struct atl1_adapter *adapter) +{ + if (likely(!atomic_dec_and_test(&adapter->irq_sem))) + iowrite32(IMR_NORMAL_MASK, adapter->hw.hw_addr + REG_IMR); +} + +static void atl1_clear_phy_int(struct atl1_adapter *adapter) +{ + u16 phy_data; + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + atl1_read_phy_reg(&adapter->hw, 19, &phy_data); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +static void atl1_inc_smb(struct atl1_adapter *adapter) +{ + struct stats_msg_block *smb = adapter->smb.smb; + + /* Fill out the OS statistics structure */ + adapter->soft_stats.rx_packets += smb->rx_ok; + adapter->soft_stats.tx_packets += smb->tx_ok; + adapter->soft_stats.rx_bytes += smb->rx_byte_cnt; + adapter->soft_stats.tx_bytes += smb->tx_byte_cnt; + adapter->soft_stats.multicast += smb->rx_mcast; + adapter->soft_stats.collisions += (smb->tx_1_col + + smb->tx_2_col * 2 + + smb->tx_late_col + + smb->tx_abort_col * + adapter->hw.max_retry); + + /* Rx Errors */ + adapter->soft_stats.rx_errors += (smb->rx_frag + + smb->rx_fcs_err + + smb->rx_len_err + + smb->rx_sz_ov + + smb->rx_rxf_ov + + smb->rx_rrd_ov + smb->rx_align_err); + adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov; + adapter->soft_stats.rx_length_errors += smb->rx_len_err; + adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err; + adapter->soft_stats.rx_frame_errors += smb->rx_align_err; + adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov + + smb->rx_rxf_ov); + + adapter->soft_stats.rx_pause += smb->rx_pause; + adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov; + adapter->soft_stats.rx_trunc += smb->rx_sz_ov; + + /* Tx Errors */ + adapter->soft_stats.tx_errors += (smb->tx_late_col + + smb->tx_abort_col + + smb->tx_underrun + smb->tx_trunc); + adapter->soft_stats.tx_fifo_errors += smb->tx_underrun; + adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col; + adapter->soft_stats.tx_window_errors += smb->tx_late_col; + + adapter->soft_stats.excecol += smb->tx_abort_col; + adapter->soft_stats.deffer += smb->tx_defer; + adapter->soft_stats.scc += smb->tx_1_col; + adapter->soft_stats.mcc += smb->tx_2_col; + adapter->soft_stats.latecol += smb->tx_late_col; + adapter->soft_stats.tx_underun += smb->tx_underrun; + adapter->soft_stats.tx_trunc += smb->tx_trunc; + adapter->soft_stats.tx_pause += smb->tx_pause; + + adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets; + adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets; + adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes; + adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes; + adapter->net_stats.multicast = adapter->soft_stats.multicast; + adapter->net_stats.collisions = adapter->soft_stats.collisions; + adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors; + adapter->net_stats.rx_over_errors = + adapter->soft_stats.rx_missed_errors; + adapter->net_stats.rx_length_errors = + adapter->soft_stats.rx_length_errors; + adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors; + adapter->net_stats.rx_frame_errors = + adapter->soft_stats.rx_frame_errors; + adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors; + adapter->net_stats.rx_missed_errors = + adapter->soft_stats.rx_missed_errors; + adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors; + adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors; + adapter->net_stats.tx_aborted_errors = + adapter->soft_stats.tx_aborted_errors; + adapter->net_stats.tx_window_errors = + adapter->soft_stats.tx_window_errors; + adapter->net_stats.tx_carrier_errors = + adapter->soft_stats.tx_carrier_errors; +} + +static void atl1_rx_checksum(struct atl1_adapter *adapter, + struct rx_return_desc *rrd, + struct sk_buff *skb) +{ + skb->ip_summed = CHECKSUM_NONE; + + if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) { + if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC | + ERR_FLAG_CODE | ERR_FLAG_OV)) { + adapter->hw_csum_err++; + printk(KERN_DEBUG "%s: rx checksum error\n", + atl1_driver_name); + return; + } + } + + /* not IPv4 */ + if (!(rrd->pkt_flg & PACKET_FLAG_IPV4)) + /* checksum is invalid, but it's not an IPv4 pkt, so ok */ + return; + + /* IPv4 packet */ + if (likely(!(rrd->err_flg & + (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM)))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + adapter->hw_csum_good++; + return; + } + + /* IPv4, but hardware thinks its checksum is wrong */ + printk(KERN_DEBUG "%s: hw csum wrong pkt_flag:%x, err_flag:%x\n", + atl1_driver_name, rrd->pkt_flg, rrd->err_flg); + skb->ip_summed = CHECKSUM_COMPLETE; + skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum); + adapter->hw_csum_err++; + return; +} + +/* + * atl1_alloc_rx_buffers - Replace used receive buffers + * @adapter: address of board private structure + */ +static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter) +{ + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + struct page *page; + unsigned long offset; + struct atl1_buffer *buffer_info, *next_info; + struct sk_buff *skb; + u16 num_alloc = 0; + u16 rfd_next_to_use, next_next; + struct rx_free_desc *rfd_desc; + + next_next = rfd_next_to_use = atomic_read(&rfd_ring->next_to_use); + if (++next_next == rfd_ring->count) + next_next = 0; + buffer_info = &rfd_ring->buffer_info[rfd_next_to_use]; + next_info = &rfd_ring->buffer_info[next_next]; + + while (!buffer_info->alloced && !next_info->alloced) { + if (buffer_info->skb) { + buffer_info->alloced = 1; + goto next; + } + + rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use); + + skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN); + if (unlikely(!skb)) { /* Better luck next round */ + adapter->net_stats.rx_dropped++; + 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); + skb->dev = netdev; + + buffer_info->alloced = 1; + buffer_info->skb = skb; + buffer_info->length = (u16) adapter->rx_buffer_len; + page = virt_to_page(skb->data); + offset = (unsigned long)skb->data & ~PAGE_MASK; + buffer_info->dma = pci_map_page(pdev, page, offset, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma); + rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len); + rfd_desc->coalese = 0; + +next: + rfd_next_to_use = next_next; + if (unlikely(++next_next == rfd_ring->count)) + next_next = 0; + + buffer_info = &rfd_ring->buffer_info[rfd_next_to_use]; + next_info = &rfd_ring->buffer_info[next_next]; + num_alloc++; + } + + if (num_alloc) { + /* + * 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(); + atomic_set(&rfd_ring->next_to_use, (int)rfd_next_to_use); + } + return num_alloc; +} + +static void atl1_intr_rx(struct atl1_adapter *adapter) +{ + int i, count; + u16 length; + u16 rrd_next_to_clean; + u32 value; + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_buffer *buffer_info; + struct rx_return_desc *rrd; + struct sk_buff *skb; + + count = 0; + + rrd_next_to_clean = atomic_read(&rrd_ring->next_to_clean); + + while (1) { + rrd = ATL1_RRD_DESC(rrd_ring, rrd_next_to_clean); + i = 1; + if (likely(rrd->xsz.valid)) { /* packet valid */ +chk_rrd: + /* check rrd status */ + if (likely(rrd->num_buf == 1)) + goto rrd_ok; + + /* rrd seems to be bad */ + if (unlikely(i-- > 0)) { + /* rrd may not be DMAed completely */ + printk(KERN_DEBUG + "%s: RRD may not be DMAed completely\n", + atl1_driver_name); + udelay(1); + goto chk_rrd; + } + /* bad rrd */ + printk(KERN_DEBUG "%s: bad RRD\n", atl1_driver_name); + /* see if update RFD index */ + if (rrd->num_buf > 1) { + u16 num_buf; + num_buf = + (rrd->xsz.xsum_sz.pkt_size + + adapter->rx_buffer_len - + 1) / adapter->rx_buffer_len; + if (rrd->num_buf == num_buf) { + /* clean alloc flag for bad rrd */ + while (rfd_ring->next_to_clean != + (rrd->buf_indx + num_buf)) { + rfd_ring->buffer_info[rfd_ring-> + next_to_clean].alloced = 0; + if (++rfd_ring->next_to_clean == + rfd_ring->count) { + rfd_ring-> + next_to_clean = 0; + } + } + } + } + + /* update rrd */ + rrd->xsz.valid = 0; + if (++rrd_next_to_clean == rrd_ring->count) + rrd_next_to_clean = 0; + count++; + continue; + } else { /* current rrd still not be updated */ + + break; + } +rrd_ok: + /* clean alloc flag for bad rrd */ + while (rfd_ring->next_to_clean != rrd->buf_indx) { + rfd_ring->buffer_info[rfd_ring->next_to_clean].alloced = + 0; + if (++rfd_ring->next_to_clean == rfd_ring->count) + rfd_ring->next_to_clean = 0; + } + + buffer_info = &rfd_ring->buffer_info[rrd->buf_indx]; + if (++rfd_ring->next_to_clean == rfd_ring->count) + rfd_ring->next_to_clean = 0; + + /* update rrd next to clean */ + if (++rrd_next_to_clean == rrd_ring->count) + rrd_next_to_clean = 0; + count++; + + if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) { + if (!(rrd->err_flg & + (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM + | ERR_FLAG_LEN))) { + /* packet error, don't need upstream */ + buffer_info->alloced = 0; + rrd->xsz.valid = 0; + continue; + } + } + + /* Good Receive */ + pci_unmap_page(adapter->pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_FROMDEVICE); + skb = buffer_info->skb; + length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size); + + skb_put(skb, length - ETHERNET_FCS_SIZE); + + /* Receive Checksum Offload */ + atl1_rx_checksum(adapter, rrd, skb); + skb->protocol = eth_type_trans(skb, adapter->netdev); + + if (adapter->vlgrp && (rrd->pkt_flg & PACKET_FLAG_VLAN_INS)) { + u16 vlan_tag = (rrd->vlan_tag >> 4) | + ((rrd->vlan_tag & 7) << 13) | + ((rrd->vlan_tag & 8) << 9); + vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag); + } else + netif_rx(skb); + + /* let protocol layer free skb */ + buffer_info->skb = NULL; + buffer_info->alloced = 0; + rrd->xsz.valid = 0; + + adapter->netdev->last_rx = jiffies; + } + + atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean); + + atl1_alloc_rx_buffers(adapter); + + /* update mailbox ? */ + if (count) { + u32 tpd_next_to_use; + u32 rfd_next_to_use; + u32 rrd_next_to_clean; + + spin_lock(&adapter->mb_lock); + + tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use); + rfd_next_to_use = + atomic_read(&adapter->rfd_ring.next_to_use); + rrd_next_to_clean = + atomic_read(&adapter->rrd_ring.next_to_clean); + value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) << + MB_RFD_PROD_INDX_SHIFT) | + ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) << + MB_RRD_CONS_INDX_SHIFT) | + ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) << + MB_TPD_PROD_INDX_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX); + spin_unlock(&adapter->mb_lock); + } +} + +static void atl1_intr_tx(struct atl1_adapter *adapter) +{ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_buffer *buffer_info; + u16 sw_tpd_next_to_clean; + u16 cmb_tpd_next_to_clean; + u8 update = 0; + + sw_tpd_next_to_clean = atomic_read(&tpd_ring->next_to_clean); + cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx); + + while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) { + struct tx_packet_desc *tpd; + update = 1; + tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean); + buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean]; + 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_irq(buffer_info->skb); + buffer_info->skb = NULL; + } + tpd->buffer_addr = 0; + tpd->desc.data = 0; + + if (++sw_tpd_next_to_clean == tpd_ring->count) + sw_tpd_next_to_clean = 0; + } + atomic_set(&tpd_ring->next_to_clean, sw_tpd_next_to_clean); + + if (netif_queue_stopped(adapter->netdev) + && netif_carrier_ok(adapter->netdev)) + netif_wake_queue(adapter->netdev); +} + +static void atl1_check_for_link(struct atl1_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u16 phy_data = 0; + + spin_lock(&adapter->lock); + adapter->phy_timer_pending = false; + atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); + atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); + spin_unlock(&adapter->lock); + + /* notify upper layer link down ASAP */ + if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */ + if (netif_carrier_ok(netdev)) { /* old link state: Up */ + printk(KERN_INFO "%s: %s link is down\n", + atl1_driver_name, netdev->name); + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + } + schedule_work(&adapter->link_chg_task); +} + +/* + * atl1_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + * @pt_regs: CPU registers structure + */ +static irqreturn_t atl1_intr(int irq, void *data) +{ + /*struct atl1_adapter *adapter = ((struct net_device *)data)->priv;*/ + struct atl1_adapter *adapter = netdev_priv(data); + u32 status; + u8 update_rx; + int max_ints = 10; + + status = adapter->cmb.cmb->int_stats; + if (!status) + return IRQ_NONE; + + update_rx = 0; + + do { + /* clear CMB interrupt status at once */ + adapter->cmb.cmb->int_stats = 0; + + if (status & ISR_GPHY) /* clear phy status */ + atl1_clear_phy_int(adapter); + + /* clear ISR status, and Enable CMB DMA/Disable Interrupt */ + iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR); + + /* check if SMB intr */ + if (status & ISR_SMB) + atl1_inc_smb(adapter); + + /* check if PCIE PHY Link down */ + if (status & ISR_PHY_LINKDOWN) { + printk(KERN_DEBUG "%s: pcie phy link down %x\n", + atl1_driver_name, status); + if (netif_running(adapter->netdev)) { /* reset MAC */ + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + schedule_work(&adapter->pcie_dma_to_rst_task); + return IRQ_HANDLED; + } + } + + /* check if DMA read/write error ? */ + if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) { + printk(KERN_DEBUG + "%s: pcie DMA r/w error (status = 0x%x)\n", + atl1_driver_name, status); + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + schedule_work(&adapter->pcie_dma_to_rst_task); + return IRQ_HANDLED; + } + + /* link event */ + if (status & ISR_GPHY) { + adapter->soft_stats.tx_carrier_errors++; + atl1_check_for_link(adapter); + } + + /* transmit event */ + if (status & ISR_CMB_TX) + atl1_intr_tx(adapter); + + /* rx exception */ + if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN | + ISR_RRD_OV | ISR_HOST_RFD_UNRUN | + ISR_HOST_RRD_OV | ISR_CMB_RX))) { + if (status & + (ISR_RXF_OV | ISR_RFD_UNRUN | ISR_RRD_OV | + ISR_HOST_RFD_UNRUN | ISR_HOST_RRD_OV)) + printk(KERN_INFO + "%s: rx exception: status = 0x%x\n", + atl1_driver_name, status); + atl1_intr_rx(adapter); + } + + if (--max_ints < 0) + break; + + } while ((status = adapter->cmb.cmb->int_stats)); + + /* re-enable Interrupt */ + iowrite32(ISR_DIS_SMB | ISR_DIS_DMA, adapter->hw.hw_addr + REG_ISR); + return IRQ_HANDLED; +} + +/* + * atl1_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 atl1_set_multi(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + struct dev_mc_list *mc_ptr; + u32 rctl; + u32 hash_value; + + /* Check for Promiscuous and All Multicast modes */ + rctl = ioread32(hw->hw_addr + REG_MAC_CTRL); + if (netdev->flags & IFF_PROMISC) + rctl |= MAC_CTRL_PROMIS_EN; + else if (netdev->flags & IFF_ALLMULTI) { + rctl |= MAC_CTRL_MC_ALL_EN; + rctl &= ~MAC_CTRL_PROMIS_EN; + } else + rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN); + + iowrite32(rctl, hw->hw_addr + REG_MAC_CTRL); + + /* clear the old settings from the multicast hash table */ + iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE); + iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2)); + + /* compute mc addresses' hash value ,and put it into hash table */ + for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { + hash_value = atl1_hash_mc_addr(hw, mc_ptr->dmi_addr); + atl1_hash_set(hw, hash_value); + } +} + +static void atl1_setup_mac_ctrl(struct atl1_adapter *adapter) +{ + u32 value; + struct atl1_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + /* Config MAC CTRL Register */ + value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN; + /* duplex */ + if (FULL_DUPLEX == adapter->link_duplex) + value |= MAC_CTRL_DUPLX; + /* speed */ + value |= ((u32) ((SPEED_1000 == adapter->link_speed) ? + MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100) << + MAC_CTRL_SPEED_SHIFT); + /* flow control */ + value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW); + /* PAD & CRC */ + value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); + /* preamble length */ + value |= (((u32) adapter->hw.preamble_len + & MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT); + /* vlan */ + if (adapter->vlgrp) + value |= MAC_CTRL_RMV_VLAN; + /* rx checksum + if (adapter->rx_csum) + value |= MAC_CTRL_RX_CHKSUM_EN; + */ + /* filter mode */ + value |= MAC_CTRL_BC_EN; + if (netdev->flags & IFF_PROMISC) + value |= MAC_CTRL_PROMIS_EN; + else if (netdev->flags & IFF_ALLMULTI) + value |= MAC_CTRL_MC_ALL_EN; + /* value |= MAC_CTRL_LOOPBACK; */ + iowrite32(value, hw->hw_addr + REG_MAC_CTRL); +} + +static u32 atl1_check_link(struct atl1_adapter *adapter) +{ + struct atl1_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + u32 ret_val; + u16 speed, duplex, phy_data; + int reconfig = 0; + + /* MII_BMSR must read twice */ + atl1_read_phy_reg(hw, MII_BMSR, &phy_data); + atl1_read_phy_reg(hw, MII_BMSR, &phy_data); + if (!(phy_data & BMSR_LSTATUS)) { /* link down */ + if (netif_carrier_ok(netdev)) { /* old link state: Up */ + printk(KERN_INFO "%s: link is down\n", + atl1_driver_name); + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + return ATL1_SUCCESS; + } + + /* Link Up */ + ret_val = atl1_get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) + return ret_val; + + switch (hw->media_type) { + case MEDIA_TYPE_1000M_FULL: + if (speed != SPEED_1000 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_100M_FULL: + if (speed != SPEED_100 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_100M_HALF: + if (speed != SPEED_100 || duplex != HALF_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_10M_FULL: + if (speed != SPEED_10 || duplex != FULL_DUPLEX) + reconfig = 1; + break; + case MEDIA_TYPE_10M_HALF: + if (speed != SPEED_10 || duplex != HALF_DUPLEX) + reconfig = 1; + break; + } + + /* link result is our setting */ + if (!reconfig) { + if (adapter->link_speed != speed + || adapter->link_duplex != duplex) { + adapter->link_speed = speed; + adapter->link_duplex = duplex; + atl1_setup_mac_ctrl(adapter); + printk(KERN_INFO "%s: %s link is up %d Mbps %s\n", + atl1_driver_name, netdev->name, + adapter->link_speed, + adapter->link_duplex == + FULL_DUPLEX ? "full duplex" : "half duplex"); + } + if (!netif_carrier_ok(netdev)) { /* Link down -> Up */ + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } + return ATL1_SUCCESS; + } + + /* change orignal link status */ + if (netif_carrier_ok(netdev)) { + adapter->link_speed = SPEED_0; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + } + + if (hw->media_type != MEDIA_TYPE_AUTO_SENSOR && + hw->media_type != MEDIA_TYPE_1000M_FULL) { + switch (hw->media_type) { + case MEDIA_TYPE_100M_FULL: + phy_data = MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 | + MII_CR_RESET; + break; + case MEDIA_TYPE_100M_HALF: + phy_data = MII_CR_SPEED_100 | MII_CR_RESET; + break; + case MEDIA_TYPE_10M_FULL: + phy_data = + MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET; + break; + default: /* MEDIA_TYPE_10M_HALF: */ + phy_data = MII_CR_SPEED_10 | MII_CR_RESET; + break; + } + atl1_write_phy_reg(hw, MII_BMCR, phy_data); + return ATL1_SUCCESS; + } + + /* auto-neg, insert timer to re-config phy */ + if (!adapter->phy_timer_pending) { + adapter->phy_timer_pending = true; + mod_timer(&adapter->phy_config_timer, jiffies + 3 * HZ); + } + + return ATL1_SUCCESS; +} + +static void set_flow_ctrl_old(struct atl1_adapter *adapter) +{ + u32 hi, lo, value; + + /* RFD Flow Control */ + value = adapter->rfd_ring.count; + hi = value / 16; + if (hi < 2) + hi = 2; + lo = value * 7 / 8; + + value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RXF_PAUSE_THRESH); + + /* RRD Flow Control */ + value = adapter->rrd_ring.count; + lo = value / 16; + hi = value * 7 / 8; + if (lo < 2) + lo = 2; + value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RRD_PAUSE_THRESH); +} + +static void set_flow_ctrl_new(struct atl1_hw *hw) +{ + u32 hi, lo, value; + + /* RXF Flow Control */ + value = ioread32(hw->hw_addr + REG_SRAM_RXF_LEN); + lo = value / 16; + if (lo < 192) + lo = 192; + hi = value * 7 / 8; + if (hi < lo) + hi = lo + 16; + value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT); + iowrite32(value, hw->hw_addr + REG_RXQ_RXF_PAUSE_THRESH); + + /* RRD Flow Control */ + value = ioread32(hw->hw_addr + REG_SRAM_RRD_LEN); + lo = value / 8; + hi = value * 7 / 8; + if (lo < 2) + lo = 2; + if (hi < lo) + hi = lo + 3; + value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) | + ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT); + iowrite32(value, hw->hw_addr + REG_RXQ_RRD_PAUSE_THRESH); +} + +/* + * atl1_configure - Configure Transmit&Receive Unit after Reset + * @adapter: board private structure + * + * Configure the Tx /Rx unit of the MAC after a reset. + */ +static u32 atl1_configure(struct atl1_adapter *adapter) +{ + struct atl1_hw *hw = &adapter->hw; + u32 value; + + /* clear interrupt status */ + iowrite32(0xffffffff, adapter->hw.hw_addr + REG_ISR); + + /* set MAC Address */ + value = (((u32) hw->mac_addr[2]) << 24) | + (((u32) hw->mac_addr[3]) << 16) | + (((u32) hw->mac_addr[4]) << 8) | + (((u32) hw->mac_addr[5])); + iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR); + value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1])); + iowrite32(value, hw->hw_addr + (REG_MAC_STA_ADDR + 4)); + + /* tx / rx ring */ + + /* HI base address */ + iowrite32((u32) ((adapter->tpd_ring.dma & 0xffffffff00000000ULL) >> 32), + hw->hw_addr + REG_DESC_BASE_ADDR_HI); + /* LO base address */ + iowrite32((u32) (adapter->rfd_ring.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_RFD_ADDR_LO); + iowrite32((u32) (adapter->rrd_ring.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_RRD_ADDR_LO); + iowrite32((u32) (adapter->tpd_ring.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_TPD_ADDR_LO); + iowrite32((u32) (adapter->cmb.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_CMB_ADDR_LO); + iowrite32((u32) (adapter->smb.dma & 0x00000000ffffffffULL), + hw->hw_addr + REG_DESC_SMB_ADDR_LO); + + /* element count */ + value = adapter->rrd_ring.count; + value <<= 16; + value += adapter->rfd_ring.count; + iowrite32(value, hw->hw_addr + REG_DESC_RFD_RRD_RING_SIZE); + iowrite32(adapter->tpd_ring.count, hw->hw_addr + REG_DESC_TPD_RING_SIZE); + + /* Load Ptr */ + iowrite32(1, hw->hw_addr + REG_LOAD_PTR); + + /* config Mailbox */ + value = ((atomic_read(&adapter->tpd_ring.next_to_use) + & MB_TPD_PROD_INDX_MASK) << MB_TPD_PROD_INDX_SHIFT) | + ((atomic_read(&adapter->rrd_ring.next_to_clean) + & MB_RRD_CONS_INDX_MASK) << MB_RRD_CONS_INDX_SHIFT) | + ((atomic_read(&adapter->rfd_ring.next_to_use) + & MB_RFD_PROD_INDX_MASK) << MB_RFD_PROD_INDX_SHIFT); + iowrite32(value, hw->hw_addr + REG_MAILBOX); + + /* config IPG/IFG */ + value = (((u32) hw->ipgt & MAC_IPG_IFG_IPGT_MASK) + << MAC_IPG_IFG_IPGT_SHIFT) | + (((u32) hw->min_ifg & MAC_IPG_IFG_MIFG_MASK) + << MAC_IPG_IFG_MIFG_SHIFT) | + (((u32) hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK) + << MAC_IPG_IFG_IPGR1_SHIFT) | + (((u32) hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK) + << MAC_IPG_IFG_IPGR2_SHIFT); + iowrite32(value, hw->hw_addr + REG_MAC_IPG_IFG); + + /* config Half-Duplex Control */ + value = ((u32) hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) | + (((u32) hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK) + << MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) | + MAC_HALF_DUPLX_CTRL_EXC_DEF_EN | + (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) | + (((u32) hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK) + << MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT); + iowrite32(value, hw->hw_addr + REG_MAC_HALF_DUPLX_CTRL); + + /* set Interrupt Moderator Timer */ + iowrite16(adapter->imt, hw->hw_addr + REG_IRQ_MODU_TIMER_INIT); + iowrite32(MASTER_CTRL_ITIMER_EN, hw->hw_addr + REG_MASTER_CTRL); + + /* set Interrupt Clear Timer */ + iowrite16(adapter->ict, hw->hw_addr + REG_CMBDISDMA_TIMER); + + /* set MTU, 4 : VLAN */ + iowrite32(hw->max_frame_size + 4, hw->hw_addr + REG_MTU); + + /* jumbo size & rrd retirement timer */ + value = (((u32) hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK) + << RXQ_JMBOSZ_TH_SHIFT) | + (((u32) hw->rx_jumbo_lkah & RXQ_JMBO_LKAH_MASK) + << RXQ_JMBO_LKAH_SHIFT) | + (((u32) hw->rrd_ret_timer & RXQ_RRD_TIMER_MASK) + << RXQ_RRD_TIMER_SHIFT); + iowrite32(value, hw->hw_addr + REG_RXQ_JMBOSZ_RRDTIM); + + /* Flow Control */ + switch (hw->dev_rev) { + case 0x8001: + case 0x9001: + case 0x9002: + case 0x9003: + set_flow_ctrl_old(adapter); + break; + default: + set_flow_ctrl_new(hw); + break; + } + + /* config TXQ */ + value = (((u32) hw->tpd_burst & TXQ_CTRL_TPD_BURST_NUM_MASK) + << TXQ_CTRL_TPD_BURST_NUM_SHIFT) | + (((u32) hw->txf_burst & TXQ_CTRL_TXF_BURST_NUM_MASK) + << TXQ_CTRL_TXF_BURST_NUM_SHIFT) | + (((u32) hw->tpd_fetch_th & TXQ_CTRL_TPD_FETCH_TH_MASK) + << TXQ_CTRL_TPD_FETCH_TH_SHIFT) | TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN; + iowrite32(value, hw->hw_addr + REG_TXQ_CTRL); + + /* min tpd fetch gap & tx jumbo packet size threshold for taskoffload */ + value = (((u32) hw->tx_jumbo_task_th & TX_JUMBO_TASK_TH_MASK) + << TX_JUMBO_TASK_TH_SHIFT) | + (((u32) hw->tpd_fetch_gap & TX_TPD_MIN_IPG_MASK) + << TX_TPD_MIN_IPG_SHIFT); + iowrite32(value, hw->hw_addr + REG_TX_JUMBO_TASK_TH_TPD_IPG); + + /* config RXQ */ + value = (((u32) hw->rfd_burst & RXQ_CTRL_RFD_BURST_NUM_MASK) + << RXQ_CTRL_RFD_BURST_NUM_SHIFT) | + (((u32) hw->rrd_burst & RXQ_CTRL_RRD_BURST_THRESH_MASK) + << RXQ_CTRL_RRD_BURST_THRESH_SHIFT) | + (((u32) hw->rfd_fetch_gap & RXQ_CTRL_RFD_PREF_MIN_IPG_MASK) + << RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT) | + RXQ_CTRL_CUT_THRU_EN | RXQ_CTRL_EN; + iowrite32(value, hw->hw_addr + REG_RXQ_CTRL); + + /* config DMA Engine */ + value = ((((u32) hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK) + << DMA_CTRL_DMAR_BURST_LEN_SHIFT) | + ((((u32) hw->dmaw_block) & DMA_CTRL_DMAR_BURST_LEN_MASK) + << DMA_CTRL_DMAR_BURST_LEN_SHIFT) | + DMA_CTRL_DMAR_EN | DMA_CTRL_DMAW_EN; + value |= (u32) hw->dma_ord; + if (atl1_rcb_128 == hw->rcb_value) + value |= DMA_CTRL_RCB_VALUE; + iowrite32(value, hw->hw_addr + REG_DMA_CTRL); + + /* config CMB / SMB */ + value = hw->cmb_rrd | ((u32) hw->cmb_tpd << 16); + iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TH); + value = hw->cmb_rx_timer | ((u32) hw->cmb_tx_timer << 16); + iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TIMER); + iowrite32(hw->smb_timer, hw->hw_addr + REG_SMB_TIMER); + + /* --- enable CMB / SMB */ + value = CSMB_CTRL_CMB_EN | CSMB_CTRL_SMB_EN; + iowrite32(value, hw->hw_addr + REG_CSMB_CTRL); + + value = ioread32(adapter->hw.hw_addr + REG_ISR); + if (unlikely((value & ISR_PHY_LINKDOWN) != 0)) + value = 1; /* config failed */ + else + value = 0; + + /* clear all interrupt status */ + iowrite32(0x3fffffff, adapter->hw.hw_addr + REG_ISR); + iowrite32(0, adapter->hw.hw_addr + REG_ISR); + return value; +} + +/* + * atl1_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + */ +static void atl1_irq_disable(struct atl1_adapter *adapter) +{ + atomic_inc(&adapter->irq_sem); + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + ioread32(adapter->hw.hw_addr + REG_IMR); + synchronize_irq(adapter->pdev->irq); +} + +static void atl1_vlan_rx_register(struct net_device *netdev, + struct vlan_group *grp) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + u32 ctrl; + + spin_lock_irqsave(&adapter->lock, flags); + /* atl1_irq_disable(adapter); */ + adapter->vlgrp = grp; + + if (grp) { + /* enable VLAN tag insert/strip */ + ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL); + ctrl |= MAC_CTRL_RMV_VLAN; + iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL); + } else { + /* disable VLAN tag insert/strip */ + ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL); + ctrl &= ~MAC_CTRL_RMV_VLAN; + iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL); + } + + /* atl1_irq_enable(adapter); */ + spin_unlock_irqrestore(&adapter->lock, flags); +} + +/* FIXME: justify or remove -- CHS */ +static void atl1_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + /* We don't do Vlan filtering */ + return; +} + +/* FIXME: this looks wrong too -- CHS */ +static void atl1_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + /* atl1_irq_disable(adapter); */ + if (adapter->vlgrp) + adapter->vlgrp->vlan_devices[vid] = NULL; + /* atl1_irq_enable(adapter); */ + spin_unlock_irqrestore(&adapter->lock, flags); + /* We don't do Vlan filtering */ + return; +} + +static void atl1_restore_vlan(struct atl1_adapter *adapter) +{ + atl1_vlan_rx_register(adapter->netdev, adapter->vlgrp); + if (adapter->vlgrp) { + u16 vid; + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!adapter->vlgrp->vlan_devices[vid]) + continue; + atl1_vlan_rx_add_vid(adapter->netdev, vid); + } + } +} + +static u16 tpd_avail(struct atl1_tpd_ring *tpd_ring) +{ + u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean); + u16 next_to_use = atomic_read(&tpd_ring->next_to_use); + return ((next_to_clean > + next_to_use) ? next_to_clean - next_to_use - + 1 : tpd_ring->count + next_to_clean - next_to_use - 1); +} + +static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb, + struct tso_param *tso) +{ + /* We enter this function holding a spinlock. */ + u8 ipofst; + int err; + + if (skb_shinfo(skb)->gso_size) { + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (unlikely(err)) + return err; + } + + if (skb->protocol == ntohs(ETH_P_IP)) { + skb->nh.iph->tot_len = 0; + skb->nh.iph->check = 0; + skb->h.th->check = + ~csum_tcpudp_magic(skb->nh.iph->saddr, + skb->nh.iph->daddr, 0, + IPPROTO_TCP, 0); + ipofst = skb->nh.raw - skb->data; + if (ipofst != ENET_HEADER_SIZE) /* 802.3 frame */ + tso->tsopl |= 1 << TSO_PARAM_ETHTYPE_SHIFT; + + tso->tsopl |= (skb->nh.iph->ihl & + CSUM_PARAM_IPHL_MASK) << CSUM_PARAM_IPHL_SHIFT; + tso->tsopl |= ((skb->h.th->doff << 2) & + TSO_PARAM_TCPHDRLEN_MASK) << TSO_PARAM_TCPHDRLEN_SHIFT; + tso->tsopl |= (skb_shinfo(skb)->gso_size & + TSO_PARAM_MSS_MASK) << TSO_PARAM_MSS_SHIFT; + tso->tsopl |= 1 << TSO_PARAM_IPCKSUM_SHIFT; + tso->tsopl |= 1 << TSO_PARAM_TCPCKSUM_SHIFT; + tso->tsopl |= 1 << TSO_PARAM_SEGMENT_SHIFT; + return true; + } + } + return false; +} + +static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb, + struct csum_param *csum) +{ + u8 css, cso; + + if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { + cso = skb->h.raw - skb->data; + css = (skb->h.raw + skb->csum) - skb->data; + if (unlikely(cso & 0x1)) { + printk(KERN_DEBUG "%s: payload offset != even number\n", + atl1_driver_name); + return -1; + } + csum->csumpl |= (cso & CSUM_PARAM_PLOADOFFSET_MASK) << + CSUM_PARAM_PLOADOFFSET_SHIFT; + csum->csumpl |= (css & CSUM_PARAM_XSUMOFFSET_MASK) << + CSUM_PARAM_XSUMOFFSET_SHIFT; + csum->csumpl |= 1 << CSUM_PARAM_CUSTOMCKSUM_SHIFT; + return true; + } + + return true; +} + +static void atl1_tx_map(struct atl1_adapter *adapter, + struct sk_buff *skb, bool tcp_seg) +{ + /* We enter this function holding a spinlock. */ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_buffer *buffer_info; + struct page *page; + int first_buf_len = skb->len; + unsigned long offset; + unsigned int nr_frags; + unsigned int f; + u16 tpd_next_to_use; + u16 proto_hdr_len; + u16 i, m, len12; + + first_buf_len -= skb->data_len; + nr_frags = skb_shinfo(skb)->nr_frags; + tpd_next_to_use = atomic_read(&tpd_ring->next_to_use); + buffer_info = &tpd_ring->buffer_info[tpd_next_to_use]; + if (unlikely(buffer_info->skb)) + BUG(); + buffer_info->skb = NULL; /* put skb in last TPD */ + + if (tcp_seg) { + /* TSO/GSO */ + proto_hdr_len = + ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); + buffer_info->length = proto_hdr_len; + page = virt_to_page(skb->data); + offset = (unsigned long)skb->data & ~PAGE_MASK; + buffer_info->dma = pci_map_page(adapter->pdev, page, + offset, proto_hdr_len, + PCI_DMA_TODEVICE); + + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + + if (first_buf_len > proto_hdr_len) { + len12 = first_buf_len - proto_hdr_len; + m = (len12 + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + for (i = 0; i < m; i++) { + buffer_info = + &tpd_ring->buffer_info[tpd_next_to_use]; + buffer_info->skb = NULL; + buffer_info->length = + (MAX_TX_BUF_LEN >= + len12) ? MAX_TX_BUF_LEN : len12; + len12 -= buffer_info->length; + page = virt_to_page(skb->data + + (proto_hdr_len + + i * MAX_TX_BUF_LEN)); + offset = (unsigned long)(skb->data + + (proto_hdr_len + + i * MAX_TX_BUF_LEN)) & + ~PAGE_MASK; + buffer_info->dma = + pci_map_page(adapter->pdev, page, offset, + buffer_info->length, + PCI_DMA_TODEVICE); + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + } + } else { + /* not TSO/GSO */ + buffer_info->length = first_buf_len; + page = virt_to_page(skb->data); + offset = (unsigned long)skb->data & ~PAGE_MASK; + buffer_info->dma = pci_map_page(adapter->pdev, page, + offset, first_buf_len, + PCI_DMA_TODEVICE); + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + + for (f = 0; f < nr_frags; f++) { + struct skb_frag_struct *frag; + u16 lenf, i, m; + + frag = &skb_shinfo(skb)->frags[f]; + lenf = frag->size; + + m = (lenf + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + for (i = 0; i < m; i++) { + buffer_info = &tpd_ring->buffer_info[tpd_next_to_use]; + if (unlikely(buffer_info->skb)) + BUG(); + buffer_info->skb = NULL; + buffer_info->length = + (lenf > MAX_TX_BUF_LEN) ? MAX_TX_BUF_LEN : lenf; + lenf -= buffer_info->length; + buffer_info->dma = + pci_map_page(adapter->pdev, frag->page, + frag->page_offset + i * MAX_TX_BUF_LEN, + buffer_info->length, PCI_DMA_TODEVICE); + + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + } + + /* last tpd's buffer-info */ + buffer_info->skb = skb; +} + +static void atl1_tx_queue(struct atl1_adapter *adapter, int count, + union tpd_descr *descr) +{ + /* We enter this function holding a spinlock. */ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + int j; + u32 val; + struct atl1_buffer *buffer_info; + struct tx_packet_desc *tpd; + u16 tpd_next_to_use = atomic_read(&tpd_ring->next_to_use); + + for (j = 0; j < count; j++) { + buffer_info = &tpd_ring->buffer_info[tpd_next_to_use]; + tpd = ATL1_TPD_DESC(&adapter->tpd_ring, tpd_next_to_use); + tpd->desc.csum.csumpu = descr->csum.csumpu; + tpd->desc.csum.csumpl = descr->csum.csumpl; + tpd->desc.tso.tsopu = descr->tso.tsopu; + tpd->desc.tso.tsopl = descr->tso.tsopl; + tpd->buffer_addr = cpu_to_le64(buffer_info->dma); + tpd->desc.data = descr->data; + tpd->desc.csum.csumpu |= (cpu_to_le16(buffer_info->length) & + CSUM_PARAM_BUFLEN_MASK) << CSUM_PARAM_BUFLEN_SHIFT; + + val = (descr->tso.tsopl >> TSO_PARAM_SEGMENT_SHIFT) & + TSO_PARAM_SEGMENT_MASK; + if (val && !j) + tpd->desc.tso.tsopl |= 1 << TSO_PARAM_HDRFLAG_SHIFT; + + if (j == (count - 1)) + tpd->desc.csum.csumpl |= 1 << CSUM_PARAM_EOP_SHIFT; + + if (++tpd_next_to_use == tpd_ring->count) + tpd_next_to_use = 0; + } + /* + * 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(); + + atomic_set(&tpd_ring->next_to_use, (int)tpd_next_to_use); +} + +static void atl1_update_mailbox(struct atl1_adapter *adapter) +{ + unsigned long flags; + u32 tpd_next_to_use; + u32 rfd_next_to_use; + u32 rrd_next_to_clean; + u32 value; + + spin_lock_irqsave(&adapter->mb_lock, flags); + + tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use); + rfd_next_to_use = atomic_read(&adapter->rfd_ring.next_to_use); + rrd_next_to_clean = atomic_read(&adapter->rrd_ring.next_to_clean); + + value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) << + MB_RFD_PROD_INDX_SHIFT) | + ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) << + MB_RRD_CONS_INDX_SHIFT) | + ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) << + MB_TPD_PROD_INDX_SHIFT); + iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX); + + spin_unlock_irqrestore(&adapter->mb_lock, flags); +} + +static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int len = skb->len; + int tso; + int count = 1; + int ret_val; + u32 val; + union tpd_descr param; + u16 frag_size; + u16 vlan_tag; + unsigned long flags; + unsigned int nr_frags = 0; + unsigned int mss = 0; + unsigned int f; + unsigned int proto_hdr_len; + + len -= skb->data_len; + + if (unlikely(skb->len == 0)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + param.data = 0; + param.tso.tsopu = 0; + param.tso.tsopl = 0; + param.csum.csumpu = 0; + param.csum.csumpl = 0; + + /* nr_frags will be nonzero if we're doing scatter/gather (SG) */ + nr_frags = skb_shinfo(skb)->nr_frags; + for (f = 0; f < nr_frags; f++) { + frag_size = skb_shinfo(skb)->frags[f].size; + if (frag_size) + count += + (frag_size + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + } + + /* mss will be nonzero if we're doing segment offload (TSO/GSO) */ + mss = skb_shinfo(skb)->gso_size; + if (mss) { + if (skb->protocol == ntohs(ETH_P_IP)) { + proto_hdr_len = ((skb->h.raw - skb->data) + + (skb->h.th->doff << 2)); + if (unlikely(proto_hdr_len > len)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + /* need additional TPD ? */ + if (proto_hdr_len != len) + count += (len - proto_hdr_len + + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN; + } + } + + local_irq_save(flags); + if (!spin_trylock(&adapter->lock)) { + /* Can't get lock - tell upper layer to requeue */ + local_irq_restore(flags); + printk(KERN_DEBUG "%s: TX locked\n", atl1_driver_name); + return NETDEV_TX_LOCKED; + } + + if (tpd_avail(&adapter->tpd_ring) < count) { + /* not enough descriptors */ + netif_stop_queue(netdev); + spin_unlock_irqrestore(&adapter->lock, flags); + printk(KERN_DEBUG "%s: TX busy\n", atl1_driver_name); + return NETDEV_TX_BUSY; + } + + param.data = 0; + + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + vlan_tag = vlan_tx_tag_get(skb); + vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) | + ((vlan_tag >> 9) & 0x8); + param.csum.csumpl |= 1 << CSUM_PARAM_INSVLAG_SHIFT; + param.csum.csumpu |= (vlan_tag & CSUM_PARAM_VALANTAG_MASK) << + CSUM_PARAM_VALAN_SHIFT; + } + + tso = atl1_tso(adapter, skb, ¶m.tso); + if (tso < 0) { + spin_unlock_irqrestore(&adapter->lock, flags); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (!tso) { + ret_val = atl1_tx_csum(adapter, skb, ¶m.csum); + if (ret_val < 0) { + spin_unlock_irqrestore(&adapter->lock, flags); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + } + + val = (param.csum.csumpl >> CSUM_PARAM_SEGMENT_SHIFT) & + CSUM_PARAM_SEGMENT_MASK; + atl1_tx_map(adapter, skb, 1 == val); + atl1_tx_queue(adapter, count, ¶m); + netdev->trans_start = jiffies; + spin_unlock_irqrestore(&adapter->lock, flags); + atl1_update_mailbox(adapter); + return NETDEV_TX_OK; +} + +/* + * atl1_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 *atl1_get_stats(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + return &adapter->net_stats; +} + +/* + * atl1_clean_rx_ring - Free RFD Buffers + * @adapter: board private structure + */ +static void atl1_clean_rx_ring(struct atl1_adapter *adapter) +{ + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_buffer *buffer_info; + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; + + /* Free all the Rx ring sk_buffs */ + for (i = 0; i < rfd_ring->count; i++) { + buffer_info = &rfd_ring->buffer_info[i]; + if (buffer_info->dma) { + pci_unmap_page(pdev, + buffer_info->dma, + buffer_info->length, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + } + if (buffer_info->skb) { + dev_kfree_skb(buffer_info->skb); + buffer_info->skb = NULL; + } + } + + size = sizeof(struct atl1_buffer) * rfd_ring->count; + memset(rfd_ring->buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(rfd_ring->desc, 0, rfd_ring->size); + + rfd_ring->next_to_clean = 0; + atomic_set(&rfd_ring->next_to_use, 0); + + rrd_ring->next_to_use = 0; + atomic_set(&rrd_ring->next_to_clean, 0); +} + +/* + * atl1_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + */ +static void atl1_clean_tx_ring(struct atl1_adapter *adapter) +{ + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_buffer *buffer_info; + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; + + /* Free all the Tx ring sk_buffs */ + for (i = 0; i < tpd_ring->count; i++) { + buffer_info = &tpd_ring->buffer_info[i]; + if (buffer_info->dma) { + pci_unmap_page(pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } + } + + for (i = 0; i < tpd_ring->count; i++) { + buffer_info = &tpd_ring->buffer_info[i]; + if (buffer_info->skb) { + dev_kfree_skb_any(buffer_info->skb); + buffer_info->skb = NULL; + } + } + + size = sizeof(struct atl1_buffer) * tpd_ring->count; + memset(tpd_ring->buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(tpd_ring->desc, 0, tpd_ring->size); + + atomic_set(&tpd_ring->next_to_use, 0); + atomic_set(&tpd_ring->next_to_clean, 0); +} + +/* + * atl1_free_ring_resources - Free Tx / RX descriptor Resources + * @adapter: board private structure + * + * Free all transmit software resources + */ +void atl1_free_ring_resources(struct atl1_adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; + struct atl1_ring_header *ring_header = &adapter->ring_header; + + atl1_clean_tx_ring(adapter); + atl1_clean_rx_ring(adapter); + + kfree(tpd_ring->buffer_info); + pci_free_consistent(pdev, ring_header->size, ring_header->desc, + ring_header->dma); + + tpd_ring->buffer_info = NULL; + tpd_ring->desc = NULL; + tpd_ring->dma = 0; + + rfd_ring->buffer_info = NULL; + rfd_ring->desc = NULL; + rfd_ring->dma = 0; + + rrd_ring->desc = NULL; + rrd_ring->dma = 0; +} + +s32 atl1_up(struct atl1_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int err; + int irq_flags = IRQF_SAMPLE_RANDOM; + + /* hardware has been reset, we need to reload some things */ + atl1_set_multi(netdev); + atl1_restore_vlan(adapter); + err = atl1_alloc_rx_buffers(adapter); + if (unlikely(!err)) /* no RX BUFFER allocated */ + return -ENOMEM; + + if (unlikely(atl1_configure(adapter))) { + err = -EIO; + goto err_up; + } + + err = pci_enable_msi(adapter->pdev); + if (err) { + dev_info(&adapter->pdev->dev, + "Unable to enable MSI: %d\n", err); + irq_flags |= IRQF_SHARED; + } + + err = request_irq(adapter->pdev->irq, &atl1_intr, irq_flags, + netdev->name, netdev); + if (unlikely(err)) + goto err_up; + + mod_timer(&adapter->watchdog_timer, jiffies); + atl1_irq_enable(adapter); + atl1_check_link(adapter); + return 0; + + /* FIXME: unreachable code! -- CHS */ + /* free irq disable any interrupt */ + iowrite32(0, adapter->hw.hw_addr + REG_IMR); + free_irq(adapter->pdev->irq, netdev); + +err_up: + pci_disable_msi(adapter->pdev); + /* free rx_buffers */ + atl1_clean_rx_ring(adapter); + return err; +} + +void atl1_down(struct atl1_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_config_timer); + adapter->phy_timer_pending = false; + + atl1_irq_disable(adapter); + free_irq(adapter->pdev->irq, netdev); + pci_disable_msi(adapter->pdev); + atl1_reset_hw(&adapter->hw); + adapter->cmb.cmb->int_stats = 0; + + adapter->link_speed = SPEED_0; + adapter->link_duplex = -1; + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + atl1_clean_tx_ring(adapter); + atl1_clean_rx_ring(adapter); +} + +/* + * atl1_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 atl1_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int old_mtu = netdev->mtu; + int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; + + if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) || + (max_frame > MAX_JUMBO_FRAME_SIZE)) { + printk(KERN_WARNING "%s: invalid MTU setting\n", + atl1_driver_name); + return -EINVAL; + } + + adapter->hw.max_frame_size = max_frame; + adapter->hw.tx_jumbo_task_th = (max_frame + 7) >> 3; + adapter->rx_buffer_len = (max_frame + 7) & ~7; + adapter->hw.rx_jumbo_th = adapter->rx_buffer_len / 8; + + netdev->mtu = new_mtu; + if ((old_mtu != new_mtu) && netif_running(netdev)) { + atl1_down(adapter); + atl1_up(adapter); + } + + return 0; +} + +/* + * atl1_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 atl1_set_mac(struct net_device *netdev, void *p) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (netif_running(netdev)) + return -EBUSY; + + 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); + + atl1_set_mac_addr(&adapter->hw); + return 0; +} + +/* + * atl1_watchdog - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + */ +static void atl1_watchdog(unsigned long data) +{ + struct atl1_adapter *adapter = (struct atl1_adapter *)data; + + /* Reset the timer */ + mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); +} + +static int mdio_read(struct net_device *netdev, int phy_id, int reg_num) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + u16 result; + + atl1_read_phy_reg(&adapter->hw, reg_num & 0x1f, &result); + + return result; +} + +static void mdio_write(struct net_device *netdev, int phy_id, int reg_num, int val) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + atl1_write_phy_reg(&adapter->hw, reg_num, val); +} + +/* + * atl1_mii_ioctl - + * @netdev: + * @ifreq: + * @cmd: + */ +static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + int retval; + + if (!netif_running(netdev)) + return -EINVAL; + + spin_lock_irqsave(&adapter->lock, flags); + retval = generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL); + spin_unlock_irqrestore(&adapter->lock, flags); + + return retval; +} + +/* + * atl1_ioctl - + * @netdev: + * @ifreq: + * @cmd: + */ +static int atl1_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return atl1_mii_ioctl(netdev, ifr, cmd); + default: + return -EOPNOTSUPP; + } +} + +/* + * atl1_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + */ +static void atl1_tx_timeout(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + /* Do the reset outside of interrupt context */ + schedule_work(&adapter->tx_timeout_task); +} + +/* + * atl1_phy_config - Timer Call-back + * @data: pointer to netdev cast into an unsigned long + */ +static void atl1_phy_config(unsigned long data) +{ + struct atl1_adapter *adapter = (struct atl1_adapter *)data; + struct atl1_hw *hw = &adapter->hw; + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + adapter->phy_timer_pending = false; + atl1_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg); + atl1_write_phy_reg(hw, MII_AT001_CR, hw->mii_1000t_ctrl_reg); + atl1_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +int atl1_reset(struct atl1_adapter *adapter) +{ + int ret; + + ret = atl1_reset_hw(&adapter->hw); + if (ret != ATL1_SUCCESS) + return ret; + return atl1_init_hw(&adapter->hw); +} + +/* + * atl1_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 atl1_open(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + int err; + + /* allocate transmit descriptors */ + err = atl1_setup_ring_resources(adapter); + if (err) + return err; + + err = atl1_up(adapter); + if (err) + goto err_up; + + return 0; + +err_up: + atl1_reset(adapter); + return err; +} + +/* + * atl1_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 atl1_close(struct net_device *netdev) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + atl1_down(adapter); + atl1_free_ring_resources(adapter); + return 0; +} + +/* + * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT + * will assert. We do soft reset <0x1400=1> according + * with the SPEC. BUT, it seemes that PCIE or DMA + * state-machine will not be reset. DMAR_TO_INT will + * assert again and again. + */ +static void atl1_tx_timeout_task(struct work_struct *work) +{ + struct atl1_adapter *adapter = + container_of(work, struct atl1_adapter, tx_timeout_task); + struct net_device *netdev = adapter->netdev; + + netif_device_detach(netdev); + atl1_down(adapter); + atl1_up(adapter); + netif_device_attach(netdev); +} + +/* + * atl1_link_chg_task - deal with link change event Out of interrupt context + */ +static void atl1_link_chg_task(struct work_struct *work) +{ + struct atl1_adapter *adapter = + container_of(work, struct atl1_adapter, link_chg_task); + unsigned long flags; + + spin_lock_irqsave(&adapter->lock, flags); + atl1_check_link(adapter); + spin_unlock_irqrestore(&adapter->lock, flags); +} + +/* + * atl1_pcie_patch - Patch for PCIE module + */ +static void atl1_pcie_patch(struct atl1_adapter *adapter) +{ + u32 value; + value = 0x6500; + iowrite32(value, adapter->hw.hw_addr + 0x12FC); + /* pcie flow control mode change */ + value = ioread32(adapter->hw.hw_addr + 0x1008); + value |= 0x8000; + iowrite32(value, adapter->hw.hw_addr + 0x1008); +} + +/* + * When ACPI resume on some VIA MotherBoard, the Interrupt Disable bit/0x400 + * on PCI Command register is disable. + * The function enable this bit. + * Brackett, 2006/03/15 + */ +static void atl1_via_workaround(struct atl1_adapter *adapter) +{ + unsigned long value; + + value = ioread16(adapter->hw.hw_addr + PCI_COMMAND); + if (value & PCI_COMMAND_INTX_DISABLE) + value &= ~PCI_COMMAND_INTX_DISABLE; + iowrite32(value, adapter->hw.hw_addr + PCI_COMMAND); +} + +/* + * atl1_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in atl1_pci_tbl + * + * Returns 0 on success, negative on failure + * + * atl1_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 atl1_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct atl1_adapter *adapter; + static int cards_found = 0; + bool pci_using_64 = true; + int err; + + err = pci_enable_device(pdev); + if (err) + return err; + + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + if (err) { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + printk(KERN_DEBUG + "%s: no usable DMA configuration, aborting\n", + atl1_driver_name); + goto err_dma; + } + pci_using_64 = false; + } + /* Mark all PCI regions associated with PCI device + * pdev as being reserved by owner atl1_driver_name + */ + err = pci_request_regions(pdev, atl1_driver_name); + if (err) + goto err_request_regions; + + /* Enables bus-mastering on the device and calls + * pcibios_set_master to do the needed arch specific settings + */ + pci_set_master(pdev); + + netdev = alloc_etherdev(sizeof(struct atl1_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; + adapter->hw.back = adapter; + + adapter->hw.hw_addr = pci_iomap(pdev, 0, 0); + if (!adapter->hw.hw_addr) { + err = -EIO; + goto err_pci_iomap; + } + /* get device revision number */ + adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + (REG_MASTER_CTRL + 2)); + + /* set default ring resource counts */ + adapter->rfd_ring.count = adapter->rrd_ring.count = ATL1_DEFAULT_RFD; + adapter->tpd_ring.count = ATL1_DEFAULT_TPD; + + adapter->mii.dev = netdev; + adapter->mii.mdio_read = mdio_read; + adapter->mii.mdio_write = mdio_write; + adapter->mii.phy_id_mask = 0x1f; + adapter->mii.reg_num_mask = 0x1f; + + netdev->open = &atl1_open; + netdev->stop = &atl1_close; + netdev->hard_start_xmit = &atl1_xmit_frame; + netdev->get_stats = &atl1_get_stats; + netdev->set_multicast_list = &atl1_set_multi; + netdev->set_mac_address = &atl1_set_mac; + netdev->change_mtu = &atl1_change_mtu; + netdev->do_ioctl = &atl1_ioctl; + netdev->tx_timeout = &atl1_tx_timeout; + netdev->watchdog_timeo = 5 * HZ; + netdev->vlan_rx_register = atl1_vlan_rx_register; + netdev->vlan_rx_add_vid = atl1_vlan_rx_add_vid; + netdev->vlan_rx_kill_vid = atl1_vlan_rx_kill_vid; + netdev->ethtool_ops = &atl1_ethtool_ops; + adapter->bd_number = cards_found; + adapter->pci_using_64 = pci_using_64; + + /* setup the private structure */ + err = atl1_sw_init(adapter); + if (err) + goto err_common; + + netdev->features = NETIF_F_HW_CSUM; + netdev->features |= NETIF_F_SG; + netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); + + /* + * FIXME - Until tso performance gets fixed, disable the feature. + * Enable it with ethtool -K if desired. + */ + /* netdev->features |= NETIF_F_TSO; */ + + if (pci_using_64) + netdev->features |= NETIF_F_HIGHDMA; + + netdev->features |= NETIF_F_LLTX; + + /* + * patch for some L1 of old version, + * the final version of L1 may not need these + * patches + */ + /* atl1_pcie_patch(adapter); */ + + /* really reset GPHY core */ + iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE); + + /* + * reset the controller to + * put the device in a known good starting state + */ + if (atl1_reset_hw(&adapter->hw)) { + err = -EIO; + goto err_common; + } + + /* copy the MAC address out of the EEPROM */ + atl1_read_mac_addr(&adapter->hw); + memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); + + if (!is_valid_ether_addr(netdev->dev_addr)) { + err = -EIO; + goto err_common; + } + + atl1_check_options(adapter); + + /* pre-init the MAC, and setup link */ + err = atl1_init_hw(&adapter->hw); + if (err) { + err = -EIO; + goto err_common; + } + + atl1_pcie_patch(adapter); + /* assume we have no link for now */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &atl1_watchdog; + adapter->watchdog_timer.data = (unsigned long)adapter; + + init_timer(&adapter->phy_config_timer); + adapter->phy_config_timer.function = &atl1_phy_config; + adapter->phy_config_timer.data = (unsigned long)adapter; + adapter->phy_timer_pending = false; + + INIT_WORK(&adapter->tx_timeout_task, atl1_tx_timeout_task); + + INIT_WORK(&adapter->link_chg_task, atl1_link_chg_task); + + INIT_WORK(&adapter->pcie_dma_to_rst_task, atl1_tx_timeout_task); + + err = register_netdev(netdev); + if (err) + goto err_common; + + cards_found++; + atl1_via_workaround(adapter); + return 0; + +err_common: + pci_iounmap(pdev, adapter->hw.hw_addr); +err_pci_iomap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_regions(pdev); +err_dma: +err_request_regions: + pci_disable_device(pdev); + return err; +} + +/* + * atl1_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * atl1_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 atl1_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1_adapter *adapter; + /* Device not available. Return. */ + if (!netdev) + return; + + adapter = netdev_priv(netdev); + iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE); + unregister_netdev(netdev); + pci_iounmap(pdev, adapter->hw.hw_addr); + pci_release_regions(pdev); + free_netdev(netdev); + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM +static int atl1_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1_adapter *adapter = netdev_priv(netdev); + struct atl1_hw *hw = &adapter->hw; + u32 ctrl = 0; + u32 wufc = adapter->wol; + + netif_device_detach(netdev); + if (netif_running(netdev)) + atl1_down(adapter); + + atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); + atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); + if (ctrl & BMSR_LSTATUS) + wufc &= ~ATL1_WUFC_LNKC; + + /* reduce speed to 10/100M */ + if (wufc) { + atl1_phy_enter_power_saving(hw); + /* if resume, let driver to re- setup link */ + hw->phy_configured = false; + atl1_set_mac_addr(hw); + atl1_set_multi(netdev); + + ctrl = 0; + /* turn on magic packet wol */ + if (wufc & ATL1_WUFC_MAG) + ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN; + + /* turn on Link change WOL */ + if (wufc & ATL1_WUFC_LNKC) + ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); + iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL); + + /* turn on all-multi mode if wake on multicast is enabled */ + ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL); + ctrl &= ~MAC_CTRL_DBG; + ctrl &= ~MAC_CTRL_PROMIS_EN; + if (wufc & ATL1_WUFC_MC) + ctrl |= MAC_CTRL_MC_ALL_EN; + else + ctrl &= ~MAC_CTRL_MC_ALL_EN; + + /* turn on broadcast mode if wake on-BC is enabled */ + if (wufc & ATL1_WUFC_BC) + ctrl |= MAC_CTRL_BC_EN; + else + ctrl &= ~MAC_CTRL_BC_EN; + + /* enable RX */ + ctrl |= MAC_CTRL_RX_EN; + iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL); + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); /* 4 == D3 cold */ + } else { + iowrite32(0, hw->hw_addr + REG_WOL_CTRL); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); /* 4 == D3 cold */ + } + + pci_save_state(pdev); + pci_disable_device(pdev); + + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int atl1_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1_adapter *adapter = netdev_priv(netdev); + u32 ret_val; + + pci_set_power_state(pdev, 0); + pci_restore_state(pdev); + + ret_val = pci_enable_device(pdev); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL); + atl1_reset(adapter); + + if (netif_running(netdev)) + atl1_up(adapter); + netif_device_attach(netdev); + + atl1_via_workaround(adapter); + + return 0; +} +#else +#define atl1_suspend NULL +#define atl1_resume NULL +#endif + +static struct pci_driver atl1_driver = { + .name = atl1_driver_name, + .id_table = atl1_pci_tbl, + .probe = atl1_probe, + .remove = __devexit_p(atl1_remove), + /* Power Managment Hooks */ + /* probably broken right now -- CHS */ + .suspend = atl1_suspend, + .resume = atl1_resume +}; + +/* + * atl1_exit_module - Driver Exit Cleanup Routine + * + * atl1_exit_module is called just before the driver is removed + * from memory. + */ +static void __exit atl1_exit_module(void) +{ + pci_unregister_driver(&atl1_driver); +} + +/* + * atl1_init_module - Driver Registration Routine + * + * atl1_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + */ +static int __init atl1_init_module(void) +{ + printk(KERN_INFO "%s - version %s\n", atl1_driver_string, DRIVER_VERSION); + printk(KERN_INFO "%s\n", atl1_copyright); + return pci_register_driver(&atl1_driver); +} + +module_init(atl1_init_module); +module_exit(atl1_exit_module); diff --git a/drivers/net/atl1/atl1_param.c b/drivers/net/atl1/atl1_param.c new file mode 100644 index 000000000000..c407214339f6 --- /dev/null +++ b/drivers/net/atl1/atl1_param.c @@ -0,0 +1,206 @@ +/* + * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved. + * Copyright(c) 2006 Chris Snook + * Copyright(c) 2006 Jay Cliburn + * + * Derived from Intel e1000 driver + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include "atl1.h" + +/* + * This is the only thing that needs to be changed to adjust the + * maximum number of ports that the driver can manage. + */ +#define ATL1_MAX_NIC 4 + +#define OPTION_UNSET -1 +#define OPTION_DISABLED 0 +#define OPTION_ENABLED 1 + +#define ATL1_PARAM_INIT { [0 ... ATL1_MAX_NIC] = OPTION_UNSET } + +/* + * Interrupt Moderate Timer in units of 2 us + * + * Valid Range: 10-65535 + * + * Default Value: 100 (200us) + */ +static int __devinitdata int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT; +static int num_int_mod_timer = 0; +module_param_array_named(int_mod_timer, int_mod_timer, int, &num_int_mod_timer, 0); +MODULE_PARM_DESC(int_mod_timer, "Interrupt moderator timer"); + +/* + * flash_vendor + * + * Valid Range: 0-2 + * + * 0 - Atmel + * 1 - SST + * 2 - ST + * + * Default Value: 0 + */ +static int __devinitdata flash_vendor[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT; +static int num_flash_vendor = 0; +module_param_array_named(flash_vendor, flash_vendor, int, &num_flash_vendor, 0); +MODULE_PARM_DESC(flash_vendor, "SPI flash vendor"); + +#define DEFAULT_INT_MOD_CNT 100 /* 200us */ +#define MAX_INT_MOD_CNT 65000 +#define MIN_INT_MOD_CNT 50 + +#define FLASH_VENDOR_DEFAULT 0 +#define FLASH_VENDOR_MIN 0 +#define FLASH_VENDOR_MAX 2 + +struct atl1_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 atl1_opt_list { + int i; + char *str; + } *p; + } l; + } arg; +}; + +static int __devinit atl1_validate_option(int *value, struct atl1_option *opt) +{ + if (*value == OPTION_UNSET) { + *value = opt->def; + return 0; + } + + switch (opt->type) { + case enable_option: + switch (*value) { + case OPTION_ENABLED: + printk(KERN_INFO "%s: %s Enabled\n", atl1_driver_name, + opt->name); + return 0; + case OPTION_DISABLED: + printk(KERN_INFO "%s: %s Disabled\n", atl1_driver_name, + opt->name); + return 0; + } + break; + case range_option: + if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { + printk(KERN_INFO "%s: %s set to %i\n", + atl1_driver_name, opt->name, *value); + return 0; + } + break; + case list_option:{ + int i; + struct atl1_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') + printk(KERN_INFO "%s: %s\n", + atl1_driver_name, ent->str); + return 0; + } + } + } + break; + + default: + break; + } + + printk(KERN_INFO "%s: invalid %s specified (%i) %s\n", + atl1_driver_name, opt->name, *value, opt->err); + *value = opt->def; + return -1; +} + +/* + * atl1_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 atl1_check_options(struct atl1_adapter *adapter) +{ + int bd = adapter->bd_number; + if (bd >= ATL1_MAX_NIC) { + printk(KERN_NOTICE "%s: warning: no configuration for board #%i\n", + atl1_driver_name, bd); + printk(KERN_NOTICE "%s: using defaults for all values\n", + atl1_driver_name); + } + { /* Interrupt Moderate Timer */ + struct atl1_option opt = { + .type = range_option, + .name = "Interrupt Moderator Timer", + .err = "using default of " + __MODULE_STRING(DEFAULT_INT_MOD_CNT), + .def = DEFAULT_INT_MOD_CNT, + .arg = {.r = + {.min = MIN_INT_MOD_CNT,.max = MAX_INT_MOD_CNT}} + }; + int val; + if (num_int_mod_timer > bd) { + val = int_mod_timer[bd]; + atl1_validate_option(&val, &opt); + adapter->imt = (u16) val; + } else + adapter->imt = (u16) (opt.def); + } + + { /* Flash Vendor */ + struct atl1_option opt = { + .type = range_option, + .name = "SPI Flash Vendor", + .err = "using default of " + __MODULE_STRING(FLASH_VENDOR_DEFAULT), + .def = DEFAULT_INT_MOD_CNT, + .arg = {.r = + {.min = FLASH_VENDOR_MIN,.max = + FLASH_VENDOR_MAX}} + }; + int val; + if (num_flash_vendor > bd) { + val = flash_vendor[bd]; + atl1_validate_option(&val, &opt); + adapter->hw.flash_vendor = (u8) val; + } else + adapter->hw.flash_vendor = (u8) (opt.def); + } +} diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index defdeed20641..920d21e021b6 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2073,6 +2073,8 @@ #define PCI_VENDOR_ID_PASEMI 0x1959 +#define PCI_VENDOR_ID_ATTANSIC 0x1969 + #define PCI_VENDOR_ID_JMICRON 0x197B #define PCI_DEVICE_ID_JMICRON_JMB360 0x2360 #define PCI_DEVICE_ID_JMICRON_JMB361 0x2361 -- cgit v1.2.3 From dcb71129841e5821c0cbbdd4017a6f202f180108 Mon Sep 17 00:00:00 2001 From: Kristian Høgsberg Date: Sun, 17 Dec 2006 14:34:09 -0500 Subject: Add PCI class ID for firewire OHCI controllers. Pull this define out of drivers/ieee1394/ohci1394.c and rename to match other PCI class defines. Signed-off-by: Stefan Richter --- drivers/ieee1394/ohci1394.c | 4 +--- include/linux/pci_ids.h | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 628130a58af3..380212573fb5 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -3634,11 +3634,9 @@ static int ohci1394_pci_resume(struct pci_dev *pdev) } #endif /* CONFIG_PM */ -#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10) - static struct pci_device_id ohci1394_pci_tbl[] = { { - .class = PCI_CLASS_FIREWIRE_OHCI, + .class = PCI_CLASS_SERIAL_FIREWIRE_OHCI, .class_mask = PCI_ANY_ID, .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3d1d21035dec..c0ced96656c5 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -95,6 +95,7 @@ #define PCI_BASE_CLASS_SERIAL 0x0c #define PCI_CLASS_SERIAL_FIREWIRE 0x0c00 +#define PCI_CLASS_SERIAL_FIREWIRE_OHCI 0x0c0010 #define PCI_CLASS_SERIAL_ACCESS 0x0c01 #define PCI_CLASS_SERIAL_SSA 0x0c02 #define PCI_CLASS_SERIAL_USB 0x0c03 -- cgit v1.2.3 From 8dc4194474159660d7f37c495e3fc3f10d0db8cc Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 4 Feb 2007 23:31:32 -0800 Subject: [PACKET]: Add optional checksum computation for recvmsg This patch is needed to make ISC's DHCP server (and probably other DHCP servers/clients using AF_PACKET) to be able to serve another client on the same Xen host. The problem is that packets between different domains on the same Xen host only have partial checksums. Unfortunately this piece of information is not passed along in AF_PACKET unless you're using the mmap interface. Since dhcpd doesn't support packet-mmap, UDP packets from the same host come out with apparently bogus checksums. This patch adds a mechanism for AF_PACKET recvmsg(2) to return the status along with the packet. It does so by adding a new cmsg that contains this information along with some other relevant data such as the original packet length. I didn't include the time stamp information since there is already a cmsg for that. This patch also changes the mmap code to set the CSUMNOTREADY flag on all packets instead of just outoing packets on cooked sockets. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/if_packet.h | 10 +++++++++ net/packet/af_packet.c | 57 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h index 99393ef3af39..f3de05c30678 100644 --- a/include/linux/if_packet.h +++ b/include/linux/if_packet.h @@ -41,6 +41,7 @@ struct sockaddr_ll #define PACKET_RX_RING 5 #define PACKET_STATISTICS 6 #define PACKET_COPY_THRESH 7 +#define PACKET_AUXDATA 8 struct tpacket_stats { @@ -48,6 +49,15 @@ struct tpacket_stats unsigned int tp_drops; }; +struct tpacket_auxdata +{ + __u32 tp_status; + __u32 tp_len; + __u32 tp_snaplen; + __u16 tp_mac; + __u16 tp_net; +}; + struct tpacket_hdr { unsigned long tp_status; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 6dc01bdeb76b..8973ea78831e 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -200,7 +200,8 @@ struct packet_sock { #endif struct packet_type prot_hook; spinlock_t bind_lock; - char running; /* prot_hook is attached*/ + unsigned int running:1, /* prot_hook is attached*/ + auxdata:1; int ifindex; /* bound device */ __be16 num; #ifdef CONFIG_PACKET_MULTICAST @@ -214,6 +215,8 @@ struct packet_sock { #endif }; +#define PACKET_SKB_CB(__skb) ((struct tpacket_auxdata *)((__skb)->cb)) + #ifdef CONFIG_PACKET_MMAP static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position) @@ -462,6 +465,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet u8 * skb_head = skb->data; int skb_len = skb->len; unsigned int snaplen, res; + struct tpacket_auxdata *aux; if (skb->pkt_type == PACKET_LOOPBACK) goto drop; @@ -523,6 +527,15 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet if (dev->hard_header_parse) sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); + aux = PACKET_SKB_CB(skb); + aux->tp_status = TP_STATUS_USER; + if (skb->ip_summed == CHECKSUM_PARTIAL) + aux->tp_status |= TP_STATUS_CSUMNOTREADY; + aux->tp_len = skb->len; + aux->tp_snaplen = snaplen; + aux->tp_mac = 0; + aux->tp_net = skb->nh.raw - skb->data; + if (pskb_trim(skb, snaplen)) goto drop_n_acct; @@ -582,11 +595,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe else if (skb->pkt_type == PACKET_OUTGOING) { /* Special case: outgoing packets have ll header at head */ skb_pull(skb, skb->nh.raw - skb->data); - if (skb->ip_summed == CHECKSUM_PARTIAL) - status |= TP_STATUS_CSUMNOTREADY; } } + if (skb->ip_summed == CHECKSUM_PARTIAL) + status |= TP_STATUS_CSUMNOTREADY; + snaplen = skb->len; res = run_filter(skb, sk, snaplen); @@ -1119,6 +1133,11 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, if (msg->msg_name) memcpy(msg->msg_name, skb->cb, msg->msg_namelen); + if (pkt_sk(sk)->auxdata) { + struct tpacket_auxdata *aux = PACKET_SKB_CB(skb); + put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(*aux), aux); + } + /* * Free or return the buffer as appropriate. Again this * hides all the races and re-entrancy issues from us. @@ -1317,6 +1336,7 @@ static int packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) { struct sock *sk = sock->sk; + struct packet_sock *po = pkt_sk(sk); int ret; if (level != SOL_PACKET) @@ -1369,6 +1389,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv return 0; } #endif + case PACKET_AUXDATA: + { + int val; + + if (optlen < sizeof(val)) + return -EINVAL; + if (copy_from_user(&val, optval, sizeof(val))) + return -EFAULT; + + po->auxdata = !!val; + return 0; + } default: return -ENOPROTOOPT; } @@ -1378,8 +1410,11 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { int len; + int val; struct sock *sk = sock->sk; struct packet_sock *po = pkt_sk(sk); + void *data; + struct tpacket_stats st; if (level != SOL_PACKET) return -ENOPROTOOPT; @@ -1392,9 +1427,6 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, switch(optname) { case PACKET_STATISTICS: - { - struct tpacket_stats st; - if (len > sizeof(struct tpacket_stats)) len = sizeof(struct tpacket_stats); spin_lock_bh(&sk->sk_receive_queue.lock); @@ -1403,16 +1435,23 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, spin_unlock_bh(&sk->sk_receive_queue.lock); st.tp_packets += st.tp_drops; - if (copy_to_user(optval, &st, len)) - return -EFAULT; + data = &st; + break; + case PACKET_AUXDATA: + if (len > sizeof(int)) + len = sizeof(int); + val = po->auxdata; + + data = &val; break; - } default: return -ENOPROTOOPT; } if (put_user(len, optlen)) return -EFAULT; + if (copy_to_user(optval, data, len)) + return -EFAULT; return 0; } -- cgit v1.2.3 From 6f74651ae626ec672028587bc700538076dfbefb Mon Sep 17 00:00:00 2001 From: Baruch Even Date: Sun, 4 Feb 2007 23:36:42 -0800 Subject: [TCP]: Seperate DSACK from SACK fast path Move DSACK code outside the SACK fast-path checking code. If the DSACK determined that the information was too old we stayed with a partial cache copied. Most likely this matters very little since the next packet will not be DSACK and we will find it in the cache. but it's still not good form and there is little reason to couple the two checks. Since the SACK receive cache doesn't need the data to be in host order we also remove the ntohl in the checking loop. Signed-off-by: Baruch Even Signed-off-by: David S. Miller --- include/linux/tcp.h | 2 +- net/ipv4/tcp_input.c | 66 ++++++++++++++++++++++++---------------------------- 2 files changed, 32 insertions(+), 36 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 3cc70d1a3504..29d3089038ab 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -316,7 +316,7 @@ struct tcp_sock { struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */ struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/ - struct tcp_sack_block recv_sack_cache[4]; + struct tcp_sack_block_wire recv_sack_cache[4]; /* 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 7670ef968dce..870f53afd363 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -951,16 +951,43 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ tp->fackets_out = 0; prior_fackets = tp->fackets_out; + /* Check for D-SACK. */ + if (before(ntohl(sp[0].start_seq), 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 && + !after(ntohl(sp[0].end_seq), ntohl(sp[1].end_seq)) && + !before(ntohl(sp[0].start_seq), ntohl(sp[1].start_seq))) { + 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(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 + * contain valid SACK info. + */ + if (before(TCP_SKB_CB(ack_skb)->ack_seq, prior_snd_una - tp->max_window)) + return 0; + /* SACK fastpath: * if the only SACK change is the increase of the end_seq of * the first block then only apply that SACK block * and use retrans queue hinting otherwise slowpath */ flag = 1; - for (i = 0; i< num_sacks; i++) { - __u32 start_seq = ntohl(sp[i].start_seq); - __u32 end_seq = ntohl(sp[i].end_seq); + for (i = 0; i < num_sacks; i++) { + __be32 start_seq = sp[i].start_seq; + __be32 end_seq = sp[i].end_seq; - if (i == 0){ + if (i == 0) { if (tp->recv_sack_cache[i].start_seq != start_seq) flag = 0; } else { @@ -970,37 +997,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ } tp->recv_sack_cache[i].start_seq = start_seq; tp->recv_sack_cache[i].end_seq = end_seq; - - /* Check for D-SACK. */ - if (i == 0) { - u32 ack = TCP_SKB_CB(ack_skb)->ack_seq; - - if (before(start_seq, ack)) { - dup_sack = 1; - tp->rx_opt.sack_ok |= 4; - NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV); - } else if (num_sacks > 1 && - !after(end_seq, ntohl(sp[1].end_seq)) && - !before(start_seq, ntohl(sp[1].start_seq))) { - 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, prior_snd_una) && - after(end_seq, tp->undo_marker)) - tp->undo_retrans--; - - /* Eliminate too old ACKs, but take into - * account more or less fresh ones, they can - * contain valid SACK info. - */ - if (before(ack, prior_snd_una - tp->max_window)) - return 0; - } } first_sack_index = 0; -- cgit v1.2.3 From 97353cb4c05c2edf260e9d1b19a29d3cc0060a09 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 5 Feb 2007 18:07:27 -0800 Subject: [NET] net/wanrouter/wanmain.c: cleanups This patch contains the following cleanups: - make the following needlessly global functions static: - lock_adapter_irq() - unlock_adapter_irq() - #if 0 the following unused global functions: - wanrouter_encapsulate() - wanrouter_type_trans() Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- include/linux/wanrouter.h | 8 -------- net/wanrouter/wanmain.c | 17 ++++++++--------- 2 files changed, 8 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/include/linux/wanrouter.h b/include/linux/wanrouter.h index 2cd05013edfc..3add87465b1f 100644 --- a/include/linux/wanrouter.h +++ b/include/linux/wanrouter.h @@ -516,9 +516,6 @@ struct wan_device { /* Public functions available for device drivers */ extern int register_wan_device(struct wan_device *wandev); extern int unregister_wan_device(char *name); -__be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev); -int wanrouter_encapsulate(struct sk_buff *skb, struct net_device *dev, - unsigned short type); /* Proc interface functions. These must not be called by the drivers! */ extern int wanrouter_proc_init(void); @@ -527,11 +524,6 @@ extern int wanrouter_proc_add(struct wan_device *wandev); extern int wanrouter_proc_delete(struct wan_device *wandev); extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -extern void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); -extern void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); - - - /* Public Data */ /* list of registered devices */ extern struct wan_device *wanrouter_router_devlist; diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c index 769cdd62c1bb..4d90a179aeda 100644 --- a/net/wanrouter/wanmain.c +++ b/net/wanrouter/wanmain.c @@ -86,8 +86,8 @@ static int wanrouter_device_del_if(struct wan_device *wandev, static struct wan_device *wanrouter_find_device(char *name); static int wanrouter_delete_interface(struct wan_device *wandev, char *name); -void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); -void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); +static void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); +static void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); @@ -104,8 +104,8 @@ struct wan_device* wanrouter_router_devlist; /* list of registered devices */ * Organize Unique Identifiers for encapsulation/decapsulation */ -static unsigned char wanrouter_oui_ether[] = { 0x00, 0x00, 0x00 }; #if 0 +static unsigned char wanrouter_oui_ether[] = { 0x00, 0x00, 0x00 }; static unsigned char wanrouter_oui_802_2[] = { 0x00, 0x80, 0xC2 }; #endif @@ -246,6 +246,8 @@ int unregister_wan_device(char *name) return 0; } +#if 0 + /* * Encapsulate packet. * @@ -341,6 +343,7 @@ __be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev) return ethertype; } +#endif /* 0 */ /* * WAN device IOCTL. @@ -799,23 +802,19 @@ static int wanrouter_delete_interface(struct wan_device *wandev, char *name) return 0; } -void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) +static void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) { spin_lock_irqsave(lock, *smp_flags); } -void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) +static void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) { spin_unlock_irqrestore(lock, *smp_flags); } EXPORT_SYMBOL(register_wan_device); EXPORT_SYMBOL(unregister_wan_device); -EXPORT_SYMBOL(wanrouter_encapsulate); -EXPORT_SYMBOL(wanrouter_type_trans); -EXPORT_SYMBOL(lock_adapter_irq); -EXPORT_SYMBOL(unlock_adapter_irq); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 22f8cde5bc336fd19603bb8c4572b33d14f14f87 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 7 Feb 2007 00:09:58 -0800 Subject: [NET]: unregister_netdevice as void There was no real useful information from the unregister_netdevice() return code, the only error occurred in a situation that was a driver bug. So change it to a void function. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- net/core/dev.c | 13 +++++-------- net/ipv4/ip_gre.c | 3 ++- net/ipv4/ipip.c | 3 ++- net/ipv6/ip6_tunnel.c | 3 ++- net/ipv6/sit.c | 3 ++- 6 files changed, 14 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2e37f5012788..1a528548cd1d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -589,7 +589,7 @@ extern int dev_open(struct net_device *dev); extern int dev_close(struct net_device *dev); extern int dev_queue_xmit(struct sk_buff *skb); extern int register_netdevice(struct net_device *dev); -extern int unregister_netdevice(struct net_device *dev); +extern void unregister_netdevice(struct net_device *dev); extern void free_netdev(struct net_device *dev); extern void synchronize_net(void); extern int register_netdevice_notifier(struct notifier_block *nb); diff --git a/net/core/dev.c b/net/core/dev.c index 455d589683e8..1e94a1b9a0f4 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3247,7 +3247,7 @@ void synchronize_net(void) * unregister_netdev() instead of this. */ -int unregister_netdevice(struct net_device *dev) +void unregister_netdevice(struct net_device *dev) { struct net_device *d, **dp; @@ -3258,7 +3258,9 @@ int unregister_netdevice(struct net_device *dev) if (dev->reg_state == NETREG_UNINITIALIZED) { printk(KERN_DEBUG "unregister_netdevice: device %s/%p never " "was registered\n", dev->name, dev); - return -ENODEV; + + WARN_ON(1); + return; } BUG_ON(dev->reg_state != NETREG_REGISTERED); @@ -3280,11 +3282,7 @@ int unregister_netdevice(struct net_device *dev) break; } } - if (!d) { - printk(KERN_ERR "unregister net_device: '%s' not found\n", - dev->name); - return -ENODEV; - } + BUG_ON(!d); dev->reg_state = NETREG_UNREGISTERING; @@ -3316,7 +3314,6 @@ int unregister_netdevice(struct net_device *dev) synchronize_net(); dev_put(dev); - return 0; } /** diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 476cb6084c75..51c83500790f 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1008,7 +1008,8 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) goto done; dev = t->dev; } - err = unregister_netdevice(dev); + unregister_netdevice(dev); + err = 0; break; default: diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 9d719d664e5b..da8bbd20c7ed 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -754,7 +754,8 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) goto done; dev = t->dev; } - err = unregister_netdevice(dev); + unregister_netdevice(dev); + err = 0; break; default: diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 8d918348f5bb..2b9e3bb7da65 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -999,7 +999,8 @@ ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) break; dev = t->dev; } - err = unregister_netdevice(dev); + err = 0; + unregister_netdevice(dev); break; default: err = -EINVAL; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 77b7b0911438..47cfeadac6dd 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -686,7 +686,8 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) goto done; dev = t->dev; } - err = unregister_netdevice(dev); + unregister_netdevice(dev); + err = 0; break; default: -- cgit v1.2.3 From 6fecd1985116fb08bdee3b9db6719e159fe5e43d Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Wed, 7 Feb 2007 15:05:12 -0800 Subject: [NETFILTER]: Add SANE connection tracking helper This is nf_conntrack_sane, a netfilter connection tracking helper module for the SANE protocol used by the 'saned' daemon to make scanners available via network. The SANE protocol uses separate control & data connections, similar to passive FTP. The helper module is needed to recognize the data connection as RELATED to the control one. Signed-off-by: Michal Schmidt Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sane.h | 21 +++ include/net/netfilter/nf_conntrack.h | 2 + net/netfilter/Kconfig | 13 ++ net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_sane.c | 242 ++++++++++++++++++++++++++++ 5 files changed, 279 insertions(+) create mode 100644 include/linux/netfilter/nf_conntrack_sane.h create mode 100644 net/netfilter/nf_conntrack_sane.c (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_sane.h b/include/linux/netfilter/nf_conntrack_sane.h new file mode 100644 index 000000000000..4767d6e23e97 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_sane.h @@ -0,0 +1,21 @@ +#ifndef _NF_CONNTRACK_SANE_H +#define _NF_CONNTRACK_SANE_H +/* SANE tracking. */ + +#ifdef __KERNEL__ + +#define SANE_PORT 6566 + +enum sane_state { + SANE_STATE_NORMAL, + SANE_STATE_START_REQUESTED, +}; + +/* This structure exists only once per master */ +struct nf_ct_sane_master { + enum sane_state state; +}; + +#endif /* __KERNEL__ */ + +#endif /* _NF_CONNTRACK_SANE_H */ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index bd01b4633ee2..68ec27490c20 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -45,6 +45,7 @@ union nf_conntrack_expect_proto { #include #include #include +#include /* per conntrack: application helper private data */ union nf_conntrack_help { @@ -52,6 +53,7 @@ union nf_conntrack_help { struct nf_ct_ftp_master ct_ftp_info; struct nf_ct_pptp_master ct_pptp_info; struct nf_ct_h323_master ct_h323_info; + struct nf_ct_sane_master ct_sane_info; }; #include diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 80107d4909c5..614c92c17835 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -235,6 +235,19 @@ config NF_CONNTRACK_PPTP To compile it as a module, choose M here. If unsure, say N. +config NF_CONNTRACK_SANE + tristate "SANE protocol support (EXPERIMENTAL)" + depends on EXPERIMENTAL && NF_CONNTRACK + help + SANE is a protocol for remote access to scanners as implemented + by the 'saned' daemon. Like FTP, it uses separate control and + data connections. + + With this module you can support SANE on a connection tracking + firewall. + + To compile it as a module, choose M here. If unsure, say N. + config NF_CONNTRACK_SIP tristate "SIP protocol support (EXPERIMENTAL)" depends on EXPERIMENTAL && NF_CONNTRACK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 5dc5574f7e99..5054b0ff8096 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o +obj-$(CONFIG_NF_CONNTRACK_SANE) += nf_conntrack_sane.o obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c new file mode 100644 index 000000000000..eb2d1dc46d45 --- /dev/null +++ b/net/netfilter/nf_conntrack_sane.c @@ -0,0 +1,242 @@ +/* SANE connection tracking helper + * (SANE = Scanner Access Now Easy) + * For documentation about the SANE network protocol see + * http://www.sane-project.org/html/doc015.html + */ + +/* Copyright (C) 2007 Red Hat, Inc. + * Author: Michal Schmidt + * Based on the FTP conntrack helper (net/netfilter/nf_conntrack_ftp.c): + * (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2004 Netfilter Core Team + * (C) 2003,2004 USAGI/WIDE Project + * (C) 2003 Yasuyuki Kozakai @USAGI + * + * 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 + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michal Schmidt "); +MODULE_DESCRIPTION("SANE connection tracking helper"); + +static char *sane_buffer; + +static DEFINE_SPINLOCK(nf_sane_lock); + +#define MAX_PORTS 8 +static u_int16_t ports[MAX_PORTS]; +static unsigned int ports_c; +module_param_array(ports, ushort, &ports_c, 0400); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +struct sane_request { + __be32 RPC_code; +#define SANE_NET_START 7 /* RPC code */ + + __be32 handle; +}; + +struct sane_reply_net_start { + __be32 status; +#define SANE_STATUS_SUCCESS 0 + + __be16 zero; + __be16 port; + /* other fields aren't interesting for conntrack */ +}; + +static int help(struct sk_buff **pskb, + unsigned int protoff, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo) +{ + unsigned int dataoff, datalen; + struct tcphdr _tcph, *th; + char *sb_ptr; + int ret = NF_ACCEPT; + int dir = CTINFO2DIR(ctinfo); + struct nf_ct_sane_master *ct_sane_info; + struct nf_conntrack_expect *exp; + struct nf_conntrack_tuple *tuple; + struct sane_request *req; + struct sane_reply_net_start *reply; + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + + ct_sane_info = &nfct_help(ct)->help.ct_sane_info; + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED && + ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) + return NF_ACCEPT; + + /* Not a full tcp header? */ + th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph); + if (th == NULL) + return NF_ACCEPT; + + /* No data? */ + dataoff = protoff + th->doff * 4; + if (dataoff >= (*pskb)->len) + return NF_ACCEPT; + + datalen = (*pskb)->len - dataoff; + + spin_lock_bh(&nf_sane_lock); + sb_ptr = skb_header_pointer(*pskb, dataoff, datalen, sane_buffer); + BUG_ON(sb_ptr == NULL); + + if (dir == IP_CT_DIR_ORIGINAL) { + if (datalen != sizeof(struct sane_request)) + goto out; + + req = (struct sane_request *)sb_ptr; + if (req->RPC_code != htonl(SANE_NET_START)) { + /* Not an interesting command */ + ct_sane_info->state = SANE_STATE_NORMAL; + goto out; + } + + /* We're interested in the next reply */ + ct_sane_info->state = SANE_STATE_START_REQUESTED; + goto out; + } + + /* Is it a reply to an uninteresting command? */ + if (ct_sane_info->state != SANE_STATE_START_REQUESTED) + goto out; + + /* It's a reply to SANE_NET_START. */ + ct_sane_info->state = SANE_STATE_NORMAL; + + if (datalen < sizeof(struct sane_reply_net_start)) { + DEBUGP("nf_ct_sane: NET_START reply too short\n"); + goto out; + } + + reply = (struct sane_reply_net_start *)sb_ptr; + if (reply->status != htonl(SANE_STATUS_SUCCESS)) { + /* saned refused the command */ + DEBUGP("nf_ct_sane: unsuccessful SANE_STATUS = %u\n", + ntohl(reply->status)); + goto out; + } + + /* Invalid saned reply? Ignore it. */ + if (reply->zero != 0) + goto out; + + exp = nf_conntrack_expect_alloc(ct); + if (exp == NULL) { + ret = NF_DROP; + goto out; + } + + tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + nf_conntrack_expect_init(exp, family, + &tuple->src.u3, &tuple->dst.u3, + IPPROTO_TCP, + NULL, &reply->port); + + DEBUGP("nf_ct_sane: expect: "); + NF_CT_DUMP_TUPLE(&exp->tuple); + NF_CT_DUMP_TUPLE(&exp->mask); + + /* Can't expect this? Best to drop packet now. */ + if (nf_conntrack_expect_related(exp) != 0) + ret = NF_DROP; + + nf_conntrack_expect_put(exp); + +out: + spin_unlock_bh(&nf_sane_lock); + return ret; +} + +static struct nf_conntrack_helper sane[MAX_PORTS][2]; +static char sane_names[MAX_PORTS][2][sizeof("sane-65535")]; + +/* don't make this __exit, since it's called from __init ! */ +static void nf_conntrack_sane_fini(void) +{ + int i, j; + + for (i = 0; i < ports_c; i++) { + for (j = 0; j < 2; j++) { + DEBUGP("nf_ct_sane: unregistering helper for pf: %d " + "port: %d\n", + sane[i][j].tuple.src.l3num, ports[i]); + nf_conntrack_helper_unregister(&sane[i][j]); + } + } + + kfree(sane_buffer); +} + +static int __init nf_conntrack_sane_init(void) +{ + int i, j = -1, ret = 0; + char *tmpname; + + sane_buffer = kmalloc(65536, GFP_KERNEL); + if (!sane_buffer) + return -ENOMEM; + + if (ports_c == 0) + ports[ports_c++] = SANE_PORT; + + /* FIXME should be configurable whether IPv4 and IPv6 connections + are tracked or not - YK */ + for (i = 0; i < ports_c; i++) { + sane[i][0].tuple.src.l3num = PF_INET; + sane[i][1].tuple.src.l3num = PF_INET6; + for (j = 0; j < 2; j++) { + sane[i][j].tuple.src.u.tcp.port = htons(ports[i]); + sane[i][j].tuple.dst.protonum = IPPROTO_TCP; + sane[i][j].mask.src.u.tcp.port = 0xFFFF; + sane[i][j].mask.dst.protonum = 0xFF; + sane[i][j].max_expected = 1; + sane[i][j].timeout = 5 * 60; /* 5 Minutes */ + sane[i][j].me = THIS_MODULE; + sane[i][j].help = help; + tmpname = &sane_names[i][j][0]; + if (ports[i] == SANE_PORT) + sprintf(tmpname, "sane"); + else + sprintf(tmpname, "sane-%d", ports[i]); + sane[i][j].name = tmpname; + + DEBUGP("nf_ct_sane: registering helper for pf: %d " + "port: %d\n", + sane[i][j].tuple.src.l3num, ports[i]); + ret = nf_conntrack_helper_register(&sane[i][j]); + if (ret) { + printk(KERN_ERR "nf_ct_sane: failed to " + "register helper for pf: %d port: %d\n", + sane[i][j].tuple.src.l3num, ports[i]); + nf_conntrack_sane_fini(); + return ret; + } + } + } + + return 0; +} + +module_init(nf_conntrack_sane_init); +module_exit(nf_conntrack_sane_fini); -- cgit v1.2.3 From a09113c2c8ec59a5cc228efa5869aade2b8f13f7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 7 Feb 2007 15:05:33 -0800 Subject: [NETFILTER]: tcp conntrack: do liberal tracking for picked up connections Do liberal tracking (only RSTs need to be in-window) for connections picked up without seeing a SYN to deal with window scaling. Also change logging of invalid packets not to log packets accepted by liberal tracking to avoid spamming the logs. Based on suggestion from James Ralston Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_tcp.h | 4 ++- net/ipv4/netfilter/ip_conntrack_proto_tcp.c | 40 +++++++++++------------------ net/netfilter/nf_conntrack_proto_tcp.c | 40 +++++++++++------------------ 3 files changed, 33 insertions(+), 51 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter/nf_conntrack_tcp.h b/include/linux/netfilter/nf_conntrack_tcp.h index 2f4e98b90cc0..007af4c2770b 100644 --- a/include/linux/netfilter/nf_conntrack_tcp.h +++ b/include/linux/netfilter/nf_conntrack_tcp.h @@ -27,6 +27,9 @@ enum tcp_conntrack { /* This sender sent FIN first */ #define IP_CT_TCP_FLAG_CLOSE_INIT 0x04 +/* Be liberal in window checking */ +#define IP_CT_TCP_FLAG_BE_LIBERAL 0x08 + #ifdef __KERNEL__ struct ip_ct_tcp_state { @@ -34,7 +37,6 @@ struct ip_ct_tcp_state { u_int32_t td_maxend; /* max of ack + max(win, 1) */ u_int32_t td_maxwin; /* max(win) */ u_int8_t td_scale; /* window scale factor */ - u_int8_t loose; /* used when connection picked up from the middle */ u_int8_t flags; /* per direction options */ }; diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index 06e4e8a6dd9f..c34f48fe5478 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c @@ -50,12 +50,9 @@ static DEFINE_RWLOCK(tcp_lock); If it's non-zero, we mark only out of window RST segments as INVALID. */ int ip_ct_tcp_be_liberal __read_mostly = 0; -/* When connection is picked up from the middle, how many packets are required - to pass in each direction when we assume we are in sync - if any side uses - window scaling, we lost the game. - If it is set to zero, we disable picking up already established +/* If it is set to zero, we disable picking up already established connections. */ -int ip_ct_tcp_loose __read_mostly = 3; +int ip_ct_tcp_loose __read_mostly = 1; /* Max number of the retransmitted packets without receiving an (acceptable) ACK from the destination. If this number is reached, a shorter timer @@ -694,11 +691,10 @@ static int tcp_in_window(struct ip_ct_tcp *state, before(sack, receiver->td_end + 1), after(ack, receiver->td_end - MAXACKWINDOW(sender))); - if (sender->loose || receiver->loose || - (before(seq, sender->td_maxend + 1) && - after(end, sender->td_end - receiver->td_maxwin - 1) && - before(sack, receiver->td_end + 1) && - after(ack, receiver->td_end - MAXACKWINDOW(sender)))) { + if (before(seq, sender->td_maxend + 1) && + after(end, sender->td_end - receiver->td_maxwin - 1) && + before(sack, receiver->td_end + 1) && + after(ack, receiver->td_end - MAXACKWINDOW(sender))) { /* * Take into account window scaling (RFC 1323). */ @@ -743,15 +739,13 @@ static int tcp_in_window(struct ip_ct_tcp *state, state->retrans = 0; } } - /* - * Close the window of disabled window tracking :-) - */ - if (sender->loose) - sender->loose--; - res = 1; } else { - if (LOG_INVALID(IPPROTO_TCP)) + res = 0; + if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL || + ip_ct_tcp_be_liberal) + res = 1; + if (!res && LOG_INVALID(IPPROTO_TCP)) nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, "ip_ct_tcp: %s ", before(seq, sender->td_maxend + 1) ? @@ -762,8 +756,6 @@ static int tcp_in_window(struct ip_ct_tcp *state, : "ACK is over the upper bound (ACKed data not seen yet)" : "SEQ is under the lower bound (already ACKed data retransmitted)" : "SEQ is over the upper bound (over the window of the receiver)"); - - res = ip_ct_tcp_be_liberal; } DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u " @@ -1105,8 +1097,6 @@ static int tcp_new(struct ip_conntrack *conntrack, tcp_options(skb, iph, th, &conntrack->proto.tcp.seen[0]); conntrack->proto.tcp.seen[1].flags = 0; - conntrack->proto.tcp.seen[0].loose = - conntrack->proto.tcp.seen[1].loose = 0; } else if (ip_ct_tcp_loose == 0) { /* Don't try to pick up connections. */ return 0; @@ -1127,11 +1117,11 @@ static int tcp_new(struct ip_conntrack *conntrack, conntrack->proto.tcp.seen[0].td_maxwin; conntrack->proto.tcp.seen[0].td_scale = 0; - /* We assume SACK. Should we assume window scaling too? */ + /* We assume SACK and liberal window checking to handle + * window scaling */ conntrack->proto.tcp.seen[0].flags = - conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM; - conntrack->proto.tcp.seen[0].loose = - conntrack->proto.tcp.seen[1].loose = ip_ct_tcp_loose; + conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM | + IP_CT_TCP_FLAG_BE_LIBERAL; } conntrack->proto.tcp.seen[1].td_end = 0; diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 626b0011dd89..6fccdcf43e08 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -60,12 +60,9 @@ static DEFINE_RWLOCK(tcp_lock); If it's non-zero, we mark only out of window RST segments as INVALID. */ int nf_ct_tcp_be_liberal __read_mostly = 0; -/* When connection is picked up from the middle, how many packets are required - to pass in each direction when we assume we are in sync - if any side uses - window scaling, we lost the game. - If it is set to zero, we disable picking up already established +/* If it is set to zero, we disable picking up already established connections. */ -int nf_ct_tcp_loose __read_mostly = 3; +int nf_ct_tcp_loose __read_mostly = 1; /* Max number of the retransmitted packets without receiving an (acceptable) ACK from the destination. If this number is reached, a shorter timer @@ -650,11 +647,10 @@ static int tcp_in_window(struct ip_ct_tcp *state, before(sack, receiver->td_end + 1), after(ack, receiver->td_end - MAXACKWINDOW(sender))); - if (sender->loose || receiver->loose || - (before(seq, sender->td_maxend + 1) && - after(end, sender->td_end - receiver->td_maxwin - 1) && - before(sack, receiver->td_end + 1) && - after(ack, receiver->td_end - MAXACKWINDOW(sender)))) { + if (before(seq, sender->td_maxend + 1) && + after(end, sender->td_end - receiver->td_maxwin - 1) && + before(sack, receiver->td_end + 1) && + after(ack, receiver->td_end - MAXACKWINDOW(sender))) { /* * Take into account window scaling (RFC 1323). */ @@ -699,15 +695,13 @@ static int tcp_in_window(struct ip_ct_tcp *state, state->retrans = 0; } } - /* - * Close the window of disabled window tracking :-) - */ - if (sender->loose) - sender->loose--; - res = 1; } else { - if (LOG_INVALID(IPPROTO_TCP)) + res = 0; + if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL || + nf_ct_tcp_be_liberal) + res = 1; + if (!res && LOG_INVALID(IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: %s ", before(seq, sender->td_maxend + 1) ? @@ -718,8 +712,6 @@ static int tcp_in_window(struct ip_ct_tcp *state, : "ACK is over the upper bound (ACKed data not seen yet)" : "SEQ is under the lower bound (already ACKed data retransmitted)" : "SEQ is over the upper bound (over the window of the receiver)"); - - res = nf_ct_tcp_be_liberal; } DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u " @@ -1063,8 +1055,6 @@ static int tcp_new(struct nf_conn *conntrack, tcp_options(skb, dataoff, th, &conntrack->proto.tcp.seen[0]); conntrack->proto.tcp.seen[1].flags = 0; - conntrack->proto.tcp.seen[0].loose = - conntrack->proto.tcp.seen[1].loose = 0; } else if (nf_ct_tcp_loose == 0) { /* Don't try to pick up connections. */ return 0; @@ -1085,11 +1075,11 @@ static int tcp_new(struct nf_conn *conntrack, conntrack->proto.tcp.seen[0].td_maxwin; conntrack->proto.tcp.seen[0].td_scale = 0; - /* We assume SACK. Should we assume window scaling too? */ + /* We assume SACK and liberal window checking to handle + * window scaling */ conntrack->proto.tcp.seen[0].flags = - conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM; - conntrack->proto.tcp.seen[0].loose = - conntrack->proto.tcp.seen[1].loose = nf_ct_tcp_loose; + conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM | + IP_CT_TCP_FLAG_BE_LIBERAL; } conntrack->proto.tcp.seen[1].td_end = 0; -- cgit v1.2.3 From cdd289a2f833b93e65b9a09a02c37f47a58140a8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 7 Feb 2007 15:09:46 -0800 Subject: [NETFILTER]: add IPv6-capable TCPMSS target Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/Kbuild | 1 + include/linux/netfilter/xt_TCPMSS.h | 10 + include/linux/netfilter_ipv4/ipt_TCPMSS.h | 7 +- net/ipv4/netfilter/Kconfig | 26 --- net/ipv4/netfilter/Makefile | 1 - net/ipv4/netfilter/ipt_TCPMSS.c | 207 --------------------- net/netfilter/Kconfig | 26 +++ net/netfilter/Makefile | 1 + net/netfilter/xt_TCPMSS.c | 296 ++++++++++++++++++++++++++++++ 9 files changed, 337 insertions(+), 238 deletions(-) create mode 100644 include/linux/netfilter/xt_TCPMSS.h delete mode 100644 net/ipv4/netfilter/ipt_TCPMSS.c create mode 100644 net/netfilter/xt_TCPMSS.c (limited to 'include/linux') diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index 6328175a1c3a..43397a414cd6 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild @@ -33,6 +33,7 @@ header-y += xt_tcpmss.h header-y += xt_tcpudp.h header-y += xt_SECMARK.h header-y += xt_CONNSECMARK.h +header-y += xt_TCPMSS.h unifdef-y += nf_conntrack_common.h unifdef-y += nf_conntrack_ftp.h diff --git a/include/linux/netfilter/xt_TCPMSS.h b/include/linux/netfilter/xt_TCPMSS.h new file mode 100644 index 000000000000..53a292cd47f3 --- /dev/null +++ b/include/linux/netfilter/xt_TCPMSS.h @@ -0,0 +1,10 @@ +#ifndef _XT_TCPMSS_H +#define _XT_TCPMSS_H + +struct xt_tcpmss_info { + u_int16_t mss; +}; + +#define XT_TCPMSS_CLAMP_PMTU 0xffff + +#endif /* _XT_TCPMSS_H */ diff --git a/include/linux/netfilter_ipv4/ipt_TCPMSS.h b/include/linux/netfilter_ipv4/ipt_TCPMSS.h index aadb39580cd3..7a850f945824 100644 --- a/include/linux/netfilter_ipv4/ipt_TCPMSS.h +++ b/include/linux/netfilter_ipv4/ipt_TCPMSS.h @@ -1,10 +1,9 @@ #ifndef _IPT_TCPMSS_H #define _IPT_TCPMSS_H -struct ipt_tcpmss_info { - u_int16_t mss; -}; +#include -#define IPT_TCPMSS_CLAMP_PMTU 0xffff +#define ipt_tcpmss_info xt_tcpmss_info +#define IPT_TCPMSS_CLAMP_PMTU XT_TCPMSS_CLAMP_PMTU #endif /*_IPT_TCPMSS_H*/ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 47bd3ad18b71..9b08e7ad71bc 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -361,32 +361,6 @@ config IP_NF_TARGET_ULOG To compile it as a module, choose M here. If unsure, say N. -config IP_NF_TARGET_TCPMSS - tristate "TCPMSS target support" - depends on IP_NF_IPTABLES - ---help--- - This option adds a `TCPMSS' target, which allows you to alter the - MSS value of TCP SYN packets, to control the maximum size for that - connection (usually limiting it to your outgoing interface's MTU - minus 40). - - This is used to overcome criminally braindead ISPs or servers which - block ICMP Fragmentation Needed packets. The symptoms of this - problem are that everything works fine from your Linux - firewall/router, but machines behind it can never exchange large - packets: - 1) Web browsers connect, then hang with no data received. - 2) Small mail works fine, but large emails hang. - 3) ssh works fine, but scp hangs after initial handshaking. - - Workaround: activate this option and add a rule to your firewall - configuration like: - - iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \ - -j TCPMSS --clamp-mss-to-pmtu - - To compile it as a module, choose M here. If unsure, say N. - # NAT + specific targets: ip_conntrack config IP_NF_NAT tristate "Full NAT" diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 16d177b71bf8..6625ec68180c 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -103,7 +103,6 @@ obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o -obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c deleted file mode 100644 index 93eb5c3c1884..000000000000 --- a/net/ipv4/netfilter/ipt_TCPMSS.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * This is a module which is used for setting the MSS option in TCP packets. - * - * Copyright (C) 2000 Marc Boucher - * - * 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 - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Marc Boucher "); -MODULE_DESCRIPTION("iptables TCP MSS modification module"); - -static inline unsigned int -optlen(const u_int8_t *opt, unsigned int offset) -{ - /* Beware zero-length options: make finite progress */ - if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0) - return 1; - else - return opt[offset+1]; -} - -static unsigned int -ipt_tcpmss_target(struct sk_buff **pskb, - const struct net_device *in, - const struct net_device *out, - unsigned int hooknum, - const struct xt_target *target, - const void *targinfo) -{ - const struct ipt_tcpmss_info *tcpmssinfo = targinfo; - struct tcphdr *tcph; - struct iphdr *iph; - u_int16_t tcplen, newmss; - __be16 newtotlen, oldval; - unsigned int i; - u_int8_t *opt; - - if (!skb_make_writable(pskb, (*pskb)->len)) - return NF_DROP; - - iph = (*pskb)->nh.iph; - tcplen = (*pskb)->len - iph->ihl*4; - tcph = (void *)iph + iph->ihl*4; - - /* Since it passed flags test in tcp match, we know it is is - not a fragment, and has data >= tcp header length. SYN - packets should not contain data: if they did, then we risk - running over MTU, sending Frag Needed and breaking things - badly. --RR */ - if (tcplen != tcph->doff*4) { - if (net_ratelimit()) - printk(KERN_ERR - "ipt_tcpmss_target: bad length (%d bytes)\n", - (*pskb)->len); - return NF_DROP; - } - - if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) { - if (dst_mtu((*pskb)->dst) <= sizeof(struct iphdr) + - sizeof(struct tcphdr)) { - if (net_ratelimit()) - printk(KERN_ERR "ipt_tcpmss_target: " - "unknown or invalid path-MTU (%d)\n", - dst_mtu((*pskb)->dst)); - return NF_DROP; /* or IPT_CONTINUE ?? */ - } - - newmss = dst_mtu((*pskb)->dst) - sizeof(struct iphdr) - - sizeof(struct tcphdr); - } else - newmss = tcpmssinfo->mss; - - opt = (u_int8_t *)tcph; - for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) { - if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS && - opt[i+1] == TCPOLEN_MSS) { - u_int16_t oldmss; - - oldmss = (opt[i+2] << 8) | opt[i+3]; - - if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU && - oldmss <= newmss) - return IPT_CONTINUE; - - opt[i+2] = (newmss & 0xff00) >> 8; - opt[i+3] = (newmss & 0x00ff); - - nf_proto_csum_replace2(&tcph->check, *pskb, - htons(oldmss), htons(newmss), 0); - return IPT_CONTINUE; - } - } - - /* - * MSS Option not found ?! add it.. - */ - if (skb_tailroom((*pskb)) < TCPOLEN_MSS) { - struct sk_buff *newskb; - - newskb = skb_copy_expand(*pskb, skb_headroom(*pskb), - TCPOLEN_MSS, GFP_ATOMIC); - if (!newskb) - return NF_DROP; - kfree_skb(*pskb); - *pskb = newskb; - iph = (*pskb)->nh.iph; - tcph = (void *)iph + iph->ihl*4; - } - - skb_put((*pskb), TCPOLEN_MSS); - - opt = (u_int8_t *)tcph + sizeof(struct tcphdr); - memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); - - nf_proto_csum_replace2(&tcph->check, *pskb, - htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1); - opt[0] = TCPOPT_MSS; - opt[1] = TCPOLEN_MSS; - opt[2] = (newmss & 0xff00) >> 8; - opt[3] = (newmss & 0x00ff); - - nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0); - - oldval = ((__be16 *)tcph)[6]; - tcph->doff += TCPOLEN_MSS/4; - nf_proto_csum_replace2(&tcph->check, *pskb, - oldval, ((__be16 *)tcph)[6], 0); - - newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS); - nf_csum_replace2(&iph->check, iph->tot_len, newtotlen); - iph->tot_len = newtotlen; - return IPT_CONTINUE; -} - -#define TH_SYN 0x02 - -static inline int find_syn_match(const struct ipt_entry_match *m) -{ - const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data; - - if (strcmp(m->u.kernel.match->name, "tcp") == 0 && - tcpinfo->flg_cmp & TH_SYN && - !(tcpinfo->invflags & IPT_TCP_INV_FLAGS)) - return 1; - - return 0; -} - -/* Must specify -p tcp --syn/--tcp-flags SYN */ -static int -ipt_tcpmss_checkentry(const char *tablename, - const void *e_void, - const struct xt_target *target, - void *targinfo, - unsigned int hook_mask) -{ - const struct ipt_tcpmss_info *tcpmssinfo = targinfo; - const struct ipt_entry *e = e_void; - - if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU && - (hook_mask & ~((1 << NF_IP_FORWARD) | - (1 << NF_IP_LOCAL_OUT) | - (1 << NF_IP_POST_ROUTING))) != 0) { - printk("TCPMSS: path-MTU clamping only supported in " - "FORWARD, OUTPUT and POSTROUTING hooks\n"); - return 0; - } - - if (IPT_MATCH_ITERATE(e, find_syn_match)) - return 1; - printk("TCPMSS: Only works on TCP SYN packets\n"); - return 0; -} - -static struct ipt_target ipt_tcpmss_reg = { - .name = "TCPMSS", - .target = ipt_tcpmss_target, - .targetsize = sizeof(struct ipt_tcpmss_info), - .proto = IPPROTO_TCP, - .checkentry = ipt_tcpmss_checkentry, - .me = THIS_MODULE, -}; - -static int __init ipt_tcpmss_init(void) -{ - return ipt_register_target(&ipt_tcpmss_reg); -} - -static void __exit ipt_tcpmss_fini(void) -{ - ipt_unregister_target(&ipt_tcpmss_reg); -} - -module_init(ipt_tcpmss_init); -module_exit(ipt_tcpmss_fini); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 614c92c17835..748f7f00909a 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -395,6 +395,32 @@ config NETFILTER_XT_TARGET_CONNSECMARK To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_TARGET_TCPMSS + tristate '"TCPMSS" target support' + depends on NETFILTER_XTABLES && (IPV6 || IPV6=n) + ---help--- + This option adds a `TCPMSS' target, which allows you to alter the + MSS value of TCP SYN packets, to control the maximum size for that + connection (usually limiting it to your outgoing interface's MTU + minus 40). + + This is used to overcome criminally braindead ISPs or servers which + block ICMP Fragmentation Needed packets. The symptoms of this + problem are that everything works fine from your Linux + firewall/router, but machines behind it can never exchange large + packets: + 1) Web browsers connect, then hang with no data received. + 2) Small mail works fine, but large emails hang. + 3) ssh works fine, but scp hangs after initial handshaking. + + Workaround: activate this option and add a rule to your firewall + configuration like: + + iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \ + -j TCPMSS --clamp-mss-to-pmtu + + To compile it as a module, choose M here. If unsure, say N. + config NETFILTER_XT_MATCH_COMMENT tristate '"comment" match support' depends on NETFILTER_XTABLES diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 5054b0ff8096..b2b5c7566b26 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o +obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o # matches diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c new file mode 100644 index 000000000000..db7e38c08de2 --- /dev/null +++ b/net/netfilter/xt_TCPMSS.c @@ -0,0 +1,296 @@ +/* + * This is a module which is used for setting the MSS option in TCP packets. + * + * Copyright (C) 2000 Marc Boucher + * + * 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 + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marc Boucher "); +MODULE_DESCRIPTION("x_tables TCP MSS modification module"); +MODULE_ALIAS("ipt_TCPMSS"); +MODULE_ALIAS("ip6t_TCPMSS"); + +static inline unsigned int +optlen(const u_int8_t *opt, unsigned int offset) +{ + /* Beware zero-length options: make finite progress */ + if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0) + return 1; + else + return opt[offset+1]; +} + +static int +tcpmss_mangle_packet(struct sk_buff **pskb, + const struct xt_tcpmss_info *info, + unsigned int tcphoff, + unsigned int minlen) +{ + struct tcphdr *tcph; + unsigned int tcplen, i; + __be16 oldval; + u16 newmss; + u8 *opt; + + if (!skb_make_writable(pskb, (*pskb)->len)) + return -1; + + tcplen = (*pskb)->len - tcphoff; + tcph = (struct tcphdr *)((*pskb)->nh.raw + tcphoff); + + /* Since it passed flags test in tcp match, we know it is is + not a fragment, and has data >= tcp header length. SYN + packets should not contain data: if they did, then we risk + running over MTU, sending Frag Needed and breaking things + badly. --RR */ + if (tcplen != tcph->doff*4) { + if (net_ratelimit()) + printk(KERN_ERR "xt_TCPMSS: bad length (%u bytes)\n", + (*pskb)->len); + return -1; + } + + if (info->mss == XT_TCPMSS_CLAMP_PMTU) { + if (dst_mtu((*pskb)->dst) <= minlen) { + if (net_ratelimit()) + printk(KERN_ERR "xt_TCPMSS: " + "unknown or invalid path-MTU (%u)\n", + dst_mtu((*pskb)->dst)); + return -1; + } + newmss = dst_mtu((*pskb)->dst) - minlen; + } else + newmss = info->mss; + + opt = (u_int8_t *)tcph; + for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) { + if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS && + opt[i+1] == TCPOLEN_MSS) { + u_int16_t oldmss; + + oldmss = (opt[i+2] << 8) | opt[i+3]; + + if (info->mss == XT_TCPMSS_CLAMP_PMTU && + oldmss <= newmss) + return 0; + + opt[i+2] = (newmss & 0xff00) >> 8; + opt[i+3] = (newmss & 0x00ff); + + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(oldmss), htons(newmss), 0); + return 0; + } + } + + /* + * MSS Option not found ?! add it.. + */ + if (skb_tailroom((*pskb)) < TCPOLEN_MSS) { + struct sk_buff *newskb; + + newskb = skb_copy_expand(*pskb, skb_headroom(*pskb), + TCPOLEN_MSS, GFP_ATOMIC); + if (!newskb) + return -1; + kfree_skb(*pskb); + *pskb = newskb; + tcph = (struct tcphdr *)((*pskb)->nh.raw + tcphoff); + } + + skb_put((*pskb), TCPOLEN_MSS); + + opt = (u_int8_t *)tcph + sizeof(struct tcphdr); + memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr)); + + nf_proto_csum_replace2(&tcph->check, *pskb, + htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1); + opt[0] = TCPOPT_MSS; + opt[1] = TCPOLEN_MSS; + opt[2] = (newmss & 0xff00) >> 8; + opt[3] = (newmss & 0x00ff); + + nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0); + + oldval = ((__be16 *)tcph)[6]; + tcph->doff += TCPOLEN_MSS/4; + nf_proto_csum_replace2(&tcph->check, *pskb, + oldval, ((__be16 *)tcph)[6], 0); + return TCPOLEN_MSS; +} + +static unsigned int +xt_tcpmss_target4(struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const struct xt_target *target, + const void *targinfo) +{ + struct iphdr *iph = (*pskb)->nh.iph; + __be16 newlen; + int ret; + + ret = tcpmss_mangle_packet(pskb, targinfo, iph->ihl * 4, + sizeof(*iph) + sizeof(struct tcphdr)); + if (ret < 0) + return NF_DROP; + if (ret > 0) { + iph = (*pskb)->nh.iph; + newlen = htons(ntohs(iph->tot_len) + ret); + nf_csum_replace2(&iph->check, iph->tot_len, newlen); + iph->tot_len = newlen; + } + return XT_CONTINUE; +} + +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) +static unsigned int +xt_tcpmss_target6(struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const struct xt_target *target, + const void *targinfo) +{ + struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h; + u8 nexthdr; + int tcphoff; + int ret; + + nexthdr = ipv6h->nexthdr; + tcphoff = ipv6_skip_exthdr(*pskb, sizeof(*ipv6h), &nexthdr); + if (tcphoff < 0) { + WARN_ON(1); + return NF_DROP; + } + ret = tcpmss_mangle_packet(pskb, targinfo, tcphoff, + sizeof(*ipv6h) + sizeof(struct tcphdr)); + if (ret < 0) + return NF_DROP; + if (ret > 0) { + ipv6h = (*pskb)->nh.ipv6h; + ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) + ret); + } + return XT_CONTINUE; +} +#endif + +#define TH_SYN 0x02 + +/* Must specify -p tcp --syn */ +static inline int find_syn_match(const struct xt_entry_match *m) +{ + const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data; + + if (strcmp(m->u.kernel.match->name, "tcp") == 0 && + tcpinfo->flg_cmp & TH_SYN && + !(tcpinfo->invflags & XT_TCP_INV_FLAGS)) + return 1; + + return 0; +} + +static int +xt_tcpmss_checkentry4(const char *tablename, + const void *entry, + const struct xt_target *target, + void *targinfo, + unsigned int hook_mask) +{ + const struct xt_tcpmss_info *info = targinfo; + const struct ipt_entry *e = entry; + + if (info->mss == XT_TCPMSS_CLAMP_PMTU && + (hook_mask & ~((1 << NF_IP_FORWARD) | + (1 << NF_IP_LOCAL_OUT) | + (1 << NF_IP_POST_ROUTING))) != 0) { + printk("xt_TCPMSS: path-MTU clamping only supported in " + "FORWARD, OUTPUT and POSTROUTING hooks\n"); + return 0; + } + if (IPT_MATCH_ITERATE(e, find_syn_match)) + return 1; + printk("xt_TCPMSS: Only works on TCP SYN packets\n"); + return 0; +} + +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) +static int +xt_tcpmss_checkentry6(const char *tablename, + const void *entry, + const struct xt_target *target, + void *targinfo, + unsigned int hook_mask) +{ + const struct xt_tcpmss_info *info = targinfo; + const struct ip6t_entry *e = entry; + + if (info->mss == XT_TCPMSS_CLAMP_PMTU && + (hook_mask & ~((1 << NF_IP6_FORWARD) | + (1 << NF_IP6_LOCAL_OUT) | + (1 << NF_IP6_POST_ROUTING))) != 0) { + printk("xt_TCPMSS: path-MTU clamping only supported in " + "FORWARD, OUTPUT and POSTROUTING hooks\n"); + return 0; + } + if (IP6T_MATCH_ITERATE(e, find_syn_match)) + return 1; + printk("xt_TCPMSS: Only works on TCP SYN packets\n"); + return 0; +} +#endif + +static struct xt_target xt_tcpmss_reg[] = { + { + .family = AF_INET, + .name = "TCPMSS", + .checkentry = xt_tcpmss_checkentry4, + .target = xt_tcpmss_target4, + .targetsize = sizeof(struct xt_tcpmss_info), + .proto = IPPROTO_TCP, + .me = THIS_MODULE, + }, +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) + { + .family = AF_INET6, + .name = "TCPMSS", + .checkentry = xt_tcpmss_checkentry6, + .target = xt_tcpmss_target6, + .targetsize = sizeof(struct xt_tcpmss_info), + .proto = IPPROTO_TCP, + .me = THIS_MODULE, + }, +#endif +}; + +static int __init xt_tcpmss_init(void) +{ + return xt_register_targets(xt_tcpmss_reg, ARRAY_SIZE(xt_tcpmss_reg)); +} + +static void __exit xt_tcpmss_fini(void) +{ + xt_unregister_targets(xt_tcpmss_reg, ARRAY_SIZE(xt_tcpmss_reg)); +} + +module_init(xt_tcpmss_init); +module_exit(xt_tcpmss_fini); -- cgit v1.2.3 From 41f4689a7c8cd76b77864461b3c58fde8f322b2c Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 7 Feb 2007 15:10:09 -0800 Subject: [NETFILTER]: NAT: optional source port randomization support This patch adds support to NAT to randomize source ports. Signed-off-by: Eric Leblond Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_nat.h | 1 + include/net/netfilter/nf_nat.h | 1 + net/ipv4/netfilter/ip_nat_core.c | 12 ++++++++++-- net/ipv4/netfilter/ip_nat_proto_tcp.c | 5 +++++ net/ipv4/netfilter/ip_nat_proto_udp.c | 5 +++++ net/ipv4/netfilter/ip_nat_rule.c | 4 ++++ net/ipv4/netfilter/nf_nat_core.c | 12 ++++++++++-- net/ipv4/netfilter/nf_nat_proto_tcp.c | 4 ++++ net/ipv4/netfilter/nf_nat_proto_udp.c | 4 ++++ net/ipv4/netfilter/nf_nat_rule.c | 4 ++++ 10 files changed, 48 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_nat.h b/include/linux/netfilter_ipv4/ip_nat.h index bdf553620ca1..bbca89aab813 100644 --- a/include/linux/netfilter_ipv4/ip_nat.h +++ b/include/linux/netfilter_ipv4/ip_nat.h @@ -16,6 +16,7 @@ enum ip_nat_manip_type #define IP_NAT_RANGE_MAP_IPS 1 #define IP_NAT_RANGE_PROTO_SPECIFIED 2 +#define IP_NAT_RANGE_PROTO_RANDOM 4 /* add randomness to "port" selection */ /* NAT sequence number modifications */ struct ip_nat_seq { diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h index 61c62068ca6b..bc57dd7b9b5c 100644 --- a/include/net/netfilter/nf_nat.h +++ b/include/net/netfilter/nf_nat.h @@ -16,6 +16,7 @@ enum nf_nat_manip_type #define IP_NAT_RANGE_MAP_IPS 1 #define IP_NAT_RANGE_PROTO_SPECIFIED 2 +#define IP_NAT_RANGE_PROTO_RANDOM 4 /* NAT sequence number modifications */ struct nf_nat_seq { diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 9d1a5175dcd4..5e08c2bf887d 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -246,8 +246,9 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple, if (maniptype == IP_NAT_MANIP_SRC) { if (find_appropriate_src(orig_tuple, tuple, range)) { DEBUGP("get_unique_tuple: Found current src map\n"); - if (!ip_nat_used_tuple(tuple, conntrack)) - return; + if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) + if (!ip_nat_used_tuple(tuple, conntrack)) + return; } } @@ -261,6 +262,13 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple, proto = ip_nat_proto_find_get(orig_tuple->dst.protonum); + /* Change protocol info to have some randomization */ + if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) { + proto->unique_tuple(tuple, range, maniptype, conntrack); + ip_nat_proto_put(proto); + return; + } + /* Only bother mapping if it's not already in range and unique */ if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || proto->in_range(tuple, maniptype, &range->min, &range->max)) diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c index b586d18b3fb3..14ff24f53a7a 100644 --- a/net/ipv4/netfilter/ip_nat_proto_tcp.c +++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -75,6 +76,10 @@ tcp_unique_tuple(struct ip_conntrack_tuple *tuple, range_size = ntohs(range->max.tcp.port) - min + 1; } + /* Start from random port to avoid prediction */ + if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) + port = net_random(); + for (i = 0; i < range_size; i++, port++) { *portptr = htons(min + port % range_size); if (!ip_nat_used_tuple(tuple, conntrack)) { diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c index 5ced0877b32f..dfd521672891 100644 --- a/net/ipv4/netfilter/ip_nat_proto_udp.c +++ b/net/ipv4/netfilter/ip_nat_proto_udp.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -74,6 +75,10 @@ udp_unique_tuple(struct ip_conntrack_tuple *tuple, range_size = ntohs(range->max.udp.port) - min + 1; } + /* Start from random port to avoid prediction */ + if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) + port = net_random(); + for (i = 0; i < range_size; i++, port++) { *portptr = htons(min + port % range_size); if (!ip_nat_used_tuple(tuple, conntrack)) diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c index a176aa3031e0..6ebaad36c06d 100644 --- a/net/ipv4/netfilter/ip_nat_rule.c +++ b/net/ipv4/netfilter/ip_nat_rule.c @@ -193,6 +193,10 @@ static int ipt_dnat_checkentry(const char *tablename, printk("DNAT: multiple ranges no longer supported\n"); return 0; } + if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) { + printk("DNAT: port randomization not supported\n"); + return 0; + } return 1; } diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 86a92272b053..998b2557692c 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -254,8 +254,9 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, if (maniptype == IP_NAT_MANIP_SRC) { if (find_appropriate_src(orig_tuple, tuple, range)) { DEBUGP("get_unique_tuple: Found current src map\n"); - if (!nf_nat_used_tuple(tuple, ct)) - return; + if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) + if (!nf_nat_used_tuple(tuple, ct)) + return; } } @@ -269,6 +270,13 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, proto = nf_nat_proto_find_get(orig_tuple->dst.protonum); + /* Change protocol info to have some randomization */ + if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) { + proto->unique_tuple(tuple, range, maniptype, ct); + nf_nat_proto_put(proto); + return; + } + /* Only bother mapping if it's not already in range and unique */ if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || proto->in_range(tuple, maniptype, &range->min, &range->max)) && diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c index 7e26a7e9bee1..439164c7a626 100644 --- a/net/ipv4/netfilter/nf_nat_proto_tcp.c +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -75,6 +76,9 @@ tcp_unique_tuple(struct nf_conntrack_tuple *tuple, range_size = ntohs(range->max.tcp.port) - min + 1; } + if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) + port = net_random(); + for (i = 0; i < range_size; i++, port++) { *portptr = htons(min + port % range_size); if (!nf_nat_used_tuple(tuple, ct)) diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c index ab0ce4c8699f..8cae6e063bb6 100644 --- a/net/ipv4/netfilter/nf_nat_proto_udp.c +++ b/net/ipv4/netfilter/nf_nat_proto_udp.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -73,6 +74,9 @@ udp_unique_tuple(struct nf_conntrack_tuple *tuple, range_size = ntohs(range->max.udp.port) - min + 1; } + if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) + port = net_random(); + for (i = 0; i < range_size; i++, port++) { *portptr = htons(min + port % range_size); if (!nf_nat_used_tuple(tuple, ct)) diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c index b868ee0195d4..3745efe70302 100644 --- a/net/ipv4/netfilter/nf_nat_rule.c +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -226,6 +226,10 @@ static int ipt_dnat_checkentry(const char *tablename, printk("DNAT: multiple ranges no longer supported\n"); return 0; } + if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) { + printk("DNAT: port randomization not supported\n"); + return 0; + } return 1; } -- cgit v1.2.3 From 6709dbbb1978abe039ea4b76c364bf003bf40de5 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 7 Feb 2007 15:11:19 -0800 Subject: [NETFILTER]: {ip,ip6}_tables: remove x_tables wrapper functions Use the x_tables functions directly to make it better visible which parts are shared between ip_tables and ip6_tables. Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_tables.h | 12 +----------- include/linux/netfilter_ipv6/ip6_tables.h | 10 ---------- net/ipv4/netfilter/ip_nat_rule.c | 26 ++++++++++++++------------ net/ipv4/netfilter/ip_tables.c | 20 ++++++++++---------- net/ipv4/netfilter/ipt_CLUSTERIP.c | 14 ++++++++------ net/ipv4/netfilter/ipt_ECN.c | 13 ++++++++----- net/ipv4/netfilter/ipt_LOG.c | 11 ++++++----- net/ipv4/netfilter/ipt_MASQUERADE.c | 9 +++++---- net/ipv4/netfilter/ipt_NETMAP.c | 8 +++++--- net/ipv4/netfilter/ipt_REDIRECT.c | 8 +++++--- net/ipv4/netfilter/ipt_REJECT.c | 10 ++++++---- net/ipv4/netfilter/ipt_SAME.c | 8 +++++--- net/ipv4/netfilter/ipt_TOS.c | 11 ++++++----- net/ipv4/netfilter/ipt_TTL.c | 11 ++++++----- net/ipv4/netfilter/ipt_ULOG.c | 13 ++++++------- net/ipv4/netfilter/ipt_addrtype.c | 9 +++++---- net/ipv4/netfilter/ipt_ah.c | 10 ++++++---- net/ipv4/netfilter/ipt_ecn.c | 10 +++++++--- net/ipv4/netfilter/ipt_iprange.c | 10 +++++----- net/ipv4/netfilter/ipt_owner.c | 9 +++++---- net/ipv4/netfilter/ipt_recent.c | 12 +++++++----- net/ipv4/netfilter/ipt_tos.c | 10 ++++++---- net/ipv4/netfilter/ipt_ttl.c | 11 ++++++----- net/ipv4/netfilter/nf_nat_rule.c | 2 +- net/ipv6/netfilter/ip6_tables.c | 12 ++++++------ net/ipv6/netfilter/ip6t_HL.c | 14 ++++++++------ net/ipv6/netfilter/ip6t_LOG.c | 10 ++++++---- net/ipv6/netfilter/ip6t_REJECT.c | 10 ++++++---- net/ipv6/netfilter/ip6t_ah.c | 8 +++++--- net/ipv6/netfilter/ip6t_eui64.c | 8 +++++--- net/ipv6/netfilter/ip6t_frag.c | 8 +++++--- net/ipv6/netfilter/ip6t_hbh.c | 1 + net/ipv6/netfilter/ip6t_hl.c | 11 ++++++----- net/ipv6/netfilter/ip6t_ipv6header.c | 8 +++++--- net/ipv6/netfilter/ip6t_owner.c | 8 +++++--- net/ipv6/netfilter/ip6t_rt.c | 8 +++++--- 36 files changed, 202 insertions(+), 171 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index 98d566c5e32a..c59bc6ff2280 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h @@ -272,16 +272,6 @@ ipt_get_target(struct ipt_entry *e) #include extern void ipt_init(void) __init; -#define ipt_register_target(tgt) \ -({ (tgt)->family = AF_INET; \ - xt_register_target(tgt); }) -#define ipt_unregister_target(tgt) xt_unregister_target(tgt) - -#define ipt_register_match(mtch) \ -({ (mtch)->family = AF_INET; \ - xt_register_match(mtch); }) -#define ipt_unregister_match(mtch) xt_unregister_match(mtch) - //#define ipt_register_table(tbl, repl) xt_register_table(AF_INET, tbl, repl) //#define ipt_unregister_table(tbl) xt_unregister_table(AF_INET, tbl) @@ -290,7 +280,7 @@ extern int ipt_register_table(struct ipt_table *table, extern void ipt_unregister_table(struct ipt_table *table); /* net/sched/ipt.c: Gimme access to your targets! Gets target->me. */ -extern struct ipt_target *ipt_find_target(const char *name, u8 revision); +extern struct xt_target *ipt_find_target(const char *name, u8 revision); /* Standard entry. */ struct ipt_standard diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 4aed340401db..2fbabab30d21 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h @@ -286,16 +286,6 @@ ip6t_get_target(struct ip6t_entry *e) #include extern void ip6t_init(void) __init; -#define ip6t_register_target(tgt) \ -({ (tgt)->family = AF_INET6; \ - xt_register_target(tgt); }) -#define ip6t_unregister_target(tgt) xt_unregister_target(tgt) - -#define ip6t_register_match(match) \ -({ (match)->family = AF_INET6; \ - xt_register_match(match); }) -#define ip6t_unregister_match(match) xt_unregister_match(match) - extern int ip6t_register_table(struct ip6t_table *table, const struct ip6t_replace *repl); extern void ip6t_unregister_table(struct ip6t_table *table); diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c index 6ebaad36c06d..7a8e7bb577e2 100644 --- a/net/ipv4/netfilter/ip_nat_rule.c +++ b/net/ipv4/netfilter/ip_nat_rule.c @@ -99,7 +99,7 @@ static unsigned int ipt_snat_target(struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, unsigned int hooknum, - const struct ipt_target *target, + const struct xt_target *target, const void *targinfo) { struct ip_conntrack *ct; @@ -141,7 +141,7 @@ static unsigned int ipt_dnat_target(struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, unsigned int hooknum, - const struct ipt_target *target, + const struct xt_target *target, const void *targinfo) { struct ip_conntrack *ct; @@ -166,7 +166,7 @@ static unsigned int ipt_dnat_target(struct sk_buff **pskb, static int ipt_snat_checkentry(const char *tablename, const void *entry, - const struct ipt_target *target, + const struct xt_target *target, void *targinfo, unsigned int hook_mask) { @@ -182,7 +182,7 @@ static int ipt_snat_checkentry(const char *tablename, static int ipt_dnat_checkentry(const char *tablename, const void *entry, - const struct ipt_target *target, + const struct xt_target *target, void *targinfo, unsigned int hook_mask) { @@ -261,8 +261,9 @@ int ip_nat_rule_find(struct sk_buff **pskb, return ret; } -static struct ipt_target ipt_snat_reg = { +static struct xt_target ipt_snat_reg = { .name = "SNAT", + .family = AF_INET, .target = ipt_snat_target, .targetsize = sizeof(struct ip_nat_multi_range_compat), .table = "nat", @@ -270,8 +271,9 @@ static struct ipt_target ipt_snat_reg = { .checkentry = ipt_snat_checkentry, }; -static struct ipt_target ipt_dnat_reg = { +static struct xt_target ipt_dnat_reg = { .name = "DNAT", + .family = AF_INET, .target = ipt_dnat_target, .targetsize = sizeof(struct ip_nat_multi_range_compat), .table = "nat", @@ -286,27 +288,27 @@ int __init ip_nat_rule_init(void) ret = ipt_register_table(&nat_table, &nat_initial_table.repl); if (ret != 0) return ret; - ret = ipt_register_target(&ipt_snat_reg); + ret = xt_register_target(&ipt_snat_reg); if (ret != 0) goto unregister_table; - ret = ipt_register_target(&ipt_dnat_reg); + ret = xt_register_target(&ipt_dnat_reg); if (ret != 0) goto unregister_snat; return ret; unregister_snat: - ipt_unregister_target(&ipt_snat_reg); + xt_unregister_target(&ipt_snat_reg); unregister_table: - ipt_unregister_table(&nat_table); + xt_unregister_table(&nat_table); return ret; } void ip_nat_rule_cleanup(void) { - ipt_unregister_target(&ipt_dnat_reg); - ipt_unregister_target(&ipt_snat_reg); + xt_unregister_target(&ipt_dnat_reg); + xt_unregister_target(&ipt_snat_reg); ipt_unregister_table(&nat_table); } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index fc1f153c86ba..0043e908b130 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -507,7 +507,7 @@ check_entry(struct ipt_entry *e, const char *name) static inline int check_match(struct ipt_entry_match *m, const char *name, const struct ipt_ip *ip, unsigned int hookmask) { - struct ipt_match *match; + struct xt_match *match; int ret; match = m->u.kernel.match; @@ -531,7 +531,7 @@ find_check_match(struct ipt_entry_match *m, unsigned int hookmask, unsigned int *i) { - struct ipt_match *match; + struct xt_match *match; int ret; match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name, @@ -557,7 +557,7 @@ err: static inline int check_target(struct ipt_entry *e, const char *name) { struct ipt_entry_target *t; - struct ipt_target *target; + struct xt_target *target; int ret; t = ipt_get_target(e); @@ -580,7 +580,7 @@ find_check_entry(struct ipt_entry *e, const char *name, unsigned int size, unsigned int *i) { struct ipt_entry_target *t; - struct ipt_target *target; + struct xt_target *target; int ret; unsigned int j; @@ -1437,7 +1437,7 @@ compat_check_calc_match(struct ipt_entry_match *m, unsigned int hookmask, int *size, int *i) { - struct ipt_match *match; + struct xt_match *match; match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name, m->u.user.revision), @@ -1466,7 +1466,7 @@ check_compat_entry_size_and_hooks(struct ipt_entry *e, const char *name) { struct ipt_entry_target *t; - struct ipt_target *target; + struct xt_target *target; unsigned int entry_offset; int ret, off, h, j; @@ -1550,7 +1550,7 @@ static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr, struct xt_table_info *newinfo, unsigned char *base) { struct ipt_entry_target *t; - struct ipt_target *target; + struct xt_target *target; struct ipt_entry *de; unsigned int origsize; int ret, h; @@ -2124,7 +2124,7 @@ icmp_checkentry(const char *tablename, } /* The built-in targets: standard (NULL) and error. */ -static struct ipt_target ipt_standard_target = { +static struct xt_target ipt_standard_target = { .name = IPT_STANDARD_TARGET, .targetsize = sizeof(int), .family = AF_INET, @@ -2135,7 +2135,7 @@ static struct ipt_target ipt_standard_target = { #endif }; -static struct ipt_target ipt_error_target = { +static struct xt_target ipt_error_target = { .name = IPT_ERROR_TARGET, .target = ipt_error, .targetsize = IPT_FUNCTION_MAXNAMELEN, @@ -2158,7 +2158,7 @@ static struct nf_sockopt_ops ipt_sockopts = { #endif }; -static struct ipt_match icmp_matchstruct = { +static struct xt_match icmp_matchstruct = { .name = "icmp", .match = icmp_match, .matchsize = sizeof(struct ipt_icmp), diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 018fea3fcb5f..343c2abdc1a0 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -26,6 +26,7 @@ #include +#include #include #include #include @@ -330,7 +331,7 @@ target(struct sk_buff **pskb, if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP && (ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED+IP_CT_IS_REPLY)) - return IPT_CONTINUE; + return XT_CONTINUE; /* ip_conntrack_icmp guarantees us that we only have ICMP_ECHO, * TIMESTAMP, INFO_REQUEST or ADDRESS type icmp packets from here @@ -368,7 +369,7 @@ target(struct sk_buff **pskb, * actually a unicast IP packet. TCP doesn't like PACKET_MULTICAST */ (*pskb)->pkt_type = PACKET_HOST; - return IPT_CONTINUE; + return XT_CONTINUE; } static int @@ -471,8 +472,9 @@ static void destroy(const struct xt_target *target, void *targinfo) nf_ct_l3proto_module_put(target->family); } -static struct ipt_target clusterip_tgt = { +static struct xt_target clusterip_tgt = { .name = "CLUSTERIP", + .family = AF_INET, .target = target, .targetsize = sizeof(struct ipt_clusterip_tgt_info), .checkentry = checkentry, @@ -728,7 +730,7 @@ static int __init ipt_clusterip_init(void) { int ret; - ret = ipt_register_target(&clusterip_tgt); + ret = xt_register_target(&clusterip_tgt); if (ret < 0) return ret; @@ -754,7 +756,7 @@ cleanup_hook: nf_unregister_hook(&cip_arp_ops); #endif /* CONFIG_PROC_FS */ cleanup_target: - ipt_unregister_target(&clusterip_tgt); + xt_unregister_target(&clusterip_tgt); return ret; } @@ -766,7 +768,7 @@ static void __exit ipt_clusterip_fini(void) remove_proc_entry(clusterip_procdir->name, clusterip_procdir->parent); #endif nf_unregister_hook(&cip_arp_ops); - ipt_unregister_target(&clusterip_tgt); + xt_unregister_target(&clusterip_tgt); } module_init(ipt_clusterip_init); diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index b55d670a24df..b5ca5938d1fe 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c @@ -9,12 +9,14 @@ * ipt_ECN.c,v 1.5 2002/08/18 19:36:51 laforge Exp */ +#include #include #include #include #include #include +#include #include #include @@ -95,7 +97,7 @@ target(struct sk_buff **pskb, if (!set_ect_tcp(pskb, einfo)) return NF_DROP; - return IPT_CONTINUE; + return XT_CONTINUE; } static int @@ -119,7 +121,7 @@ checkentry(const char *tablename, return 0; } if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)) - && (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO))) { + && (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & XT_INV_PROTO))) { printk(KERN_WARNING "ECN: cannot use TCP operations on a " "non-tcp rule\n"); return 0; @@ -127,8 +129,9 @@ checkentry(const char *tablename, return 1; } -static struct ipt_target ipt_ecn_reg = { +static struct xt_target ipt_ecn_reg = { .name = "ECN", + .family = AF_INET, .target = target, .targetsize = sizeof(struct ipt_ECN_info), .table = "mangle", @@ -138,12 +141,12 @@ static struct ipt_target ipt_ecn_reg = { static int __init ipt_ecn_init(void) { - return ipt_register_target(&ipt_ecn_reg); + return xt_register_target(&ipt_ecn_reg); } static void __exit ipt_ecn_fini(void) { - ipt_unregister_target(&ipt_ecn_reg); + xt_unregister_target(&ipt_ecn_reg); } module_init(ipt_ecn_init); diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index 37778c72aeaa..f68370ffb43f 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include MODULE_LICENSE("GPL"); @@ -432,7 +432,7 @@ ipt_log_target(struct sk_buff **pskb, ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li, loginfo->prefix); - return IPT_CONTINUE; + return XT_CONTINUE; } static int ipt_log_checkentry(const char *tablename, @@ -455,8 +455,9 @@ static int ipt_log_checkentry(const char *tablename, return 1; } -static struct ipt_target ipt_log_reg = { +static struct xt_target ipt_log_reg = { .name = "LOG", + .family = AF_INET, .target = ipt_log_target, .targetsize = sizeof(struct ipt_log_info), .checkentry = ipt_log_checkentry, @@ -473,7 +474,7 @@ static int __init ipt_log_init(void) { int ret; - ret = ipt_register_target(&ipt_log_reg); + ret = xt_register_target(&ipt_log_reg); if (ret < 0) return ret; if (nf_log_register(PF_INET, &ipt_log_logger) < 0) { @@ -489,7 +490,7 @@ static int __init ipt_log_init(void) static void __exit ipt_log_fini(void) { nf_log_unregister_logger(&ipt_log_logger); - ipt_unregister_target(&ipt_log_reg); + xt_unregister_target(&ipt_log_reg); } module_init(ipt_log_init); diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index d669685afd04..91c42efcd533 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -25,7 +25,7 @@ #else #include #endif -#include +#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); @@ -190,8 +190,9 @@ static struct notifier_block masq_inet_notifier = { .notifier_call = masq_inet_event, }; -static struct ipt_target masquerade = { +static struct xt_target masquerade = { .name = "MASQUERADE", + .family = AF_INET, .target = masquerade_target, .targetsize = sizeof(struct ip_nat_multi_range_compat), .table = "nat", @@ -204,7 +205,7 @@ static int __init ipt_masquerade_init(void) { int ret; - ret = ipt_register_target(&masquerade); + ret = xt_register_target(&masquerade); if (ret == 0) { /* Register for device down reports */ @@ -218,7 +219,7 @@ static int __init ipt_masquerade_init(void) static void __exit ipt_masquerade_fini(void) { - ipt_unregister_target(&masquerade); + xt_unregister_target(&masquerade); unregister_netdevice_notifier(&masq_dev_notifier); unregister_inetaddr_notifier(&masq_inet_notifier); } diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c index 9390e90f2b25..b4acc241d898 100644 --- a/net/ipv4/netfilter/ipt_NETMAP.c +++ b/net/ipv4/netfilter/ipt_NETMAP.c @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef CONFIG_NF_NAT_NEEDED #include #else @@ -88,8 +89,9 @@ target(struct sk_buff **pskb, return ip_nat_setup_info(ct, &newrange, hooknum); } -static struct ipt_target target_module = { +static struct xt_target target_module = { .name = MODULENAME, + .family = AF_INET, .target = target, .targetsize = sizeof(struct ip_nat_multi_range_compat), .table = "nat", @@ -101,12 +103,12 @@ static struct ipt_target target_module = { static int __init ipt_netmap_init(void) { - return ipt_register_target(&target_module); + return xt_register_target(&target_module); } static void __exit ipt_netmap_fini(void) { - ipt_unregister_target(&target_module); + xt_unregister_target(&target_module); } module_init(ipt_netmap_init); diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c index 462eceb3a1b1..54cd021aa5a8 100644 --- a/net/ipv4/netfilter/ipt_REDIRECT.c +++ b/net/ipv4/netfilter/ipt_REDIRECT.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef CONFIG_NF_NAT_NEEDED #include #else @@ -104,8 +105,9 @@ redirect_target(struct sk_buff **pskb, return ip_nat_setup_info(ct, &newrange, hooknum); } -static struct ipt_target redirect_reg = { +static struct xt_target redirect_reg = { .name = "REDIRECT", + .family = AF_INET, .target = redirect_target, .targetsize = sizeof(struct ip_nat_multi_range_compat), .table = "nat", @@ -116,12 +118,12 @@ static struct ipt_target redirect_reg = { static int __init ipt_redirect_init(void) { - return ipt_register_target(&redirect_reg); + return xt_register_target(&redirect_reg); } static void __exit ipt_redirect_fini(void) { - ipt_unregister_target(&redirect_reg); + xt_unregister_target(&redirect_reg); } module_init(ipt_redirect_init); diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index c9cad23844d7..e4a1ddb386a7 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_BRIDGE_NETFILTER @@ -230,7 +231,7 @@ static int check(const char *tablename, } else if (rejinfo->with == IPT_TCP_RESET) { /* Must specify that it's a TCP packet */ if (e->ip.proto != IPPROTO_TCP - || (e->ip.invflags & IPT_INV_PROTO)) { + || (e->ip.invflags & XT_INV_PROTO)) { DEBUGP("REJECT: TCP_RESET invalid for non-tcp\n"); return 0; } @@ -238,8 +239,9 @@ static int check(const char *tablename, return 1; } -static struct ipt_target ipt_reject_reg = { +static struct xt_target ipt_reject_reg = { .name = "REJECT", + .family = AF_INET, .target = reject, .targetsize = sizeof(struct ipt_reject_info), .table = "filter", @@ -251,12 +253,12 @@ static struct ipt_target ipt_reject_reg = { static int __init ipt_reject_init(void) { - return ipt_register_target(&ipt_reject_reg); + return xt_register_target(&ipt_reject_reg); } static void __exit ipt_reject_fini(void) { - ipt_unregister_target(&ipt_reject_reg); + xt_unregister_target(&ipt_reject_reg); } module_init(ipt_reject_init); diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c index 3dcf29411337..a1cdd1262de2 100644 --- a/net/ipv4/netfilter/ipt_SAME.c +++ b/net/ipv4/netfilter/ipt_SAME.c @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef CONFIG_NF_NAT_NEEDED #include #else @@ -186,8 +187,9 @@ same_target(struct sk_buff **pskb, return ip_nat_setup_info(ct, &newrange, hooknum); } -static struct ipt_target same_reg = { +static struct xt_target same_reg = { .name = "SAME", + .family = AF_INET, .target = same_target, .targetsize = sizeof(struct ipt_same_info), .table = "nat", @@ -199,12 +201,12 @@ static struct ipt_target same_reg = { static int __init ipt_same_init(void) { - return ipt_register_target(&same_reg); + return xt_register_target(&same_reg); } static void __exit ipt_same_fini(void) { - ipt_unregister_target(&same_reg); + xt_unregister_target(&same_reg); } module_init(ipt_same_init); diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c index 18e74ac4d425..29b05a6bd108 100644 --- a/net/ipv4/netfilter/ipt_TOS.c +++ b/net/ipv4/netfilter/ipt_TOS.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include MODULE_LICENSE("GPL"); @@ -40,7 +40,7 @@ target(struct sk_buff **pskb, iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos; nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos)); } - return IPT_CONTINUE; + return XT_CONTINUE; } static int @@ -63,8 +63,9 @@ checkentry(const char *tablename, return 1; } -static struct ipt_target ipt_tos_reg = { +static struct xt_target ipt_tos_reg = { .name = "TOS", + .family = AF_INET, .target = target, .targetsize = sizeof(struct ipt_tos_target_info), .table = "mangle", @@ -74,12 +75,12 @@ static struct ipt_target ipt_tos_reg = { static int __init ipt_tos_init(void) { - return ipt_register_target(&ipt_tos_reg); + return xt_register_target(&ipt_tos_reg); } static void __exit ipt_tos_fini(void) { - ipt_unregister_target(&ipt_tos_reg); + xt_unregister_target(&ipt_tos_reg); } module_init(ipt_tos_init); diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c index fffe5ca82e91..d2b6fa3f9dcd 100644 --- a/net/ipv4/netfilter/ipt_TTL.c +++ b/net/ipv4/netfilter/ipt_TTL.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include MODULE_AUTHOR("Harald Welte "); @@ -59,7 +59,7 @@ ipt_ttl_target(struct sk_buff **pskb, iph->ttl = new_ttl; } - return IPT_CONTINUE; + return XT_CONTINUE; } static int ipt_ttl_checkentry(const char *tablename, @@ -80,8 +80,9 @@ static int ipt_ttl_checkentry(const char *tablename, return 1; } -static struct ipt_target ipt_TTL = { +static struct xt_target ipt_TTL = { .name = "TTL", + .family = AF_INET, .target = ipt_ttl_target, .targetsize = sizeof(struct ipt_TTL_info), .table = "mangle", @@ -91,12 +92,12 @@ static struct ipt_target ipt_TTL = { static int __init ipt_ttl_init(void) { - return ipt_register_target(&ipt_TTL); + return xt_register_target(&ipt_TTL); } static void __exit ipt_ttl_fini(void) { - ipt_unregister_target(&ipt_TTL); + xt_unregister_target(&ipt_TTL); } module_init(ipt_ttl_init); diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index a47e279eaac2..7af57a3a1f36 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c @@ -57,7 +57,7 @@ #include #include #include -#include +#include #include #include #include @@ -132,7 +132,6 @@ static void ulog_send(unsigned int nlgroupnum) ub->qlen = 0; ub->skb = NULL; ub->lastnlh = NULL; - } @@ -314,7 +313,7 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb, ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, NULL); - return IPT_CONTINUE; + return XT_CONTINUE; } static void ipt_logfn(unsigned int pf, @@ -363,8 +362,9 @@ static int ipt_ulog_checkentry(const char *tablename, return 1; } -static struct ipt_target ipt_ulog_reg = { +static struct xt_target ipt_ulog_reg = { .name = "ULOG", + .family = AF_INET, .target = ipt_ulog_target, .targetsize = sizeof(struct ipt_ulog_info), .checkentry = ipt_ulog_checkentry, @@ -400,7 +400,7 @@ static int __init ipt_ulog_init(void) if (!nflognl) return -ENOMEM; - ret = ipt_register_target(&ipt_ulog_reg); + ret = xt_register_target(&ipt_ulog_reg); if (ret < 0) { sock_release(nflognl->sk_socket); return ret; @@ -420,7 +420,7 @@ static void __exit ipt_ulog_fini(void) if (nflog) nf_log_unregister_logger(&ipt_ulog_logger); - ipt_unregister_target(&ipt_ulog_reg); + xt_unregister_target(&ipt_ulog_reg); sock_release(nflognl->sk_socket); /* remove pending timers and free allocated skb's */ @@ -436,7 +436,6 @@ static void __exit ipt_ulog_fini(void) ub->skb = NULL; } } - } module_init(ipt_ulog_init); diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c index 7b60eb74788b..648f555c4d16 100644 --- a/net/ipv4/netfilter/ipt_addrtype.c +++ b/net/ipv4/netfilter/ipt_addrtype.c @@ -16,7 +16,7 @@ #include #include -#include +#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Patrick McHardy "); @@ -44,8 +44,9 @@ static int match(const struct sk_buff *skb, return ret; } -static struct ipt_match addrtype_match = { +static struct xt_match addrtype_match = { .name = "addrtype", + .family = AF_INET, .match = match, .matchsize = sizeof(struct ipt_addrtype_info), .me = THIS_MODULE @@ -53,12 +54,12 @@ static struct ipt_match addrtype_match = { static int __init ipt_addrtype_init(void) { - return ipt_register_match(&addrtype_match); + return xt_register_match(&addrtype_match); } static void __exit ipt_addrtype_fini(void) { - ipt_unregister_match(&addrtype_match); + xt_unregister_match(&addrtype_match); } module_init(ipt_addrtype_init); diff --git a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c index 1798f86bc534..42f41224a43a 100644 --- a/net/ipv4/netfilter/ipt_ah.c +++ b/net/ipv4/netfilter/ipt_ah.c @@ -6,12 +6,13 @@ * published by the Free Software Foundation. */ +#include #include #include #include #include -#include +#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Yon Uriarte "); @@ -86,8 +87,9 @@ checkentry(const char *tablename, return 1; } -static struct ipt_match ah_match = { +static struct xt_match ah_match = { .name = "ah", + .family = AF_INET, .match = match, .matchsize = sizeof(struct ipt_ah), .proto = IPPROTO_AH, @@ -97,12 +99,12 @@ static struct ipt_match ah_match = { static int __init ipt_ah_init(void) { - return ipt_register_match(&ah_match); + return xt_register_match(&ah_match); } static void __exit ipt_ah_fini(void) { - ipt_unregister_match(&ah_match); + xt_unregister_match(&ah_match); } module_init(ipt_ah_init); diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c index dafbdec0efc0..37508b2cfea6 100644 --- a/net/ipv4/netfilter/ipt_ecn.c +++ b/net/ipv4/netfilter/ipt_ecn.c @@ -9,10 +9,13 @@ * published by the Free Software Foundation. */ +#include +#include #include #include #include +#include #include #include @@ -109,8 +112,9 @@ static int checkentry(const char *tablename, const void *ip_void, return 1; } -static struct ipt_match ecn_match = { +static struct xt_match ecn_match = { .name = "ecn", + .family = AF_INET, .match = match, .matchsize = sizeof(struct ipt_ecn_info), .checkentry = checkentry, @@ -119,12 +123,12 @@ static struct ipt_match ecn_match = { static int __init ipt_ecn_init(void) { - return ipt_register_match(&ecn_match); + return xt_register_match(&ecn_match); } static void __exit ipt_ecn_fini(void) { - ipt_unregister_match(&ecn_match); + xt_unregister_match(&ecn_match); } module_init(ipt_ecn_init); diff --git a/net/ipv4/netfilter/ipt_iprange.c b/net/ipv4/netfilter/ipt_iprange.c index 5202edd8d333..05de593be94c 100644 --- a/net/ipv4/netfilter/ipt_iprange.c +++ b/net/ipv4/netfilter/ipt_iprange.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include MODULE_LICENSE("GPL"); @@ -63,22 +63,22 @@ match(const struct sk_buff *skb, return 1; } -static struct ipt_match iprange_match = { +static struct xt_match iprange_match = { .name = "iprange", + .family = AF_INET, .match = match, .matchsize = sizeof(struct ipt_iprange_info), - .destroy = NULL, .me = THIS_MODULE }; static int __init ipt_iprange_init(void) { - return ipt_register_match(&iprange_match); + return xt_register_match(&iprange_match); } static void __exit ipt_iprange_fini(void) { - ipt_unregister_match(&iprange_match); + xt_unregister_match(&iprange_match); } module_init(ipt_iprange_init); diff --git a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c index 78c336f12a9e..9f496ac834b5 100644 --- a/net/ipv4/netfilter/ipt_owner.c +++ b/net/ipv4/netfilter/ipt_owner.c @@ -15,7 +15,7 @@ #include #include -#include +#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marc Boucher "); @@ -68,8 +68,9 @@ checkentry(const char *tablename, return 1; } -static struct ipt_match owner_match = { +static struct xt_match owner_match = { .name = "owner", + .family = AF_INET, .match = match, .matchsize = sizeof(struct ipt_owner_info), .hooks = (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING), @@ -79,12 +80,12 @@ static struct ipt_match owner_match = { static int __init ipt_owner_init(void) { - return ipt_register_match(&owner_match); + return xt_register_match(&owner_match); } static void __exit ipt_owner_fini(void) { - ipt_unregister_match(&owner_match); + xt_unregister_match(&owner_match); } module_init(ipt_owner_init); diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c index 4db0e73c56f1..6b97b6796173 100644 --- a/net/ipv4/netfilter/ipt_recent.c +++ b/net/ipv4/netfilter/ipt_recent.c @@ -12,6 +12,7 @@ * Copyright 2002-2003, Stephen Frost, 2.5.x port by laforge@netfilter.org */ #include +#include #include #include #include @@ -24,7 +25,7 @@ #include #include -#include +#include #include MODULE_AUTHOR("Patrick McHardy "); @@ -462,8 +463,9 @@ static struct file_operations recent_fops = { }; #endif /* CONFIG_PROC_FS */ -static struct ipt_match recent_match = { +static struct xt_match recent_match = { .name = "recent", + .family = AF_INET, .match = ipt_recent_match, .matchsize = sizeof(struct ipt_recent_info), .checkentry = ipt_recent_checkentry, @@ -479,13 +481,13 @@ static int __init ipt_recent_init(void) return -EINVAL; ip_list_hash_size = 1 << fls(ip_list_tot); - err = ipt_register_match(&recent_match); + err = xt_register_match(&recent_match); #ifdef CONFIG_PROC_FS if (err) return err; proc_dir = proc_mkdir("ipt_recent", proc_net); if (proc_dir == NULL) { - ipt_unregister_match(&recent_match); + xt_unregister_match(&recent_match); err = -ENOMEM; } #endif @@ -495,7 +497,7 @@ static int __init ipt_recent_init(void) static void __exit ipt_recent_exit(void) { BUG_ON(!list_empty(&tables)); - ipt_unregister_match(&recent_match); + xt_unregister_match(&recent_match); #ifdef CONFIG_PROC_FS remove_proc_entry("ipt_recent", proc_net); #endif diff --git a/net/ipv4/netfilter/ipt_tos.c b/net/ipv4/netfilter/ipt_tos.c index 5549c39c7851..5d33b51d49d8 100644 --- a/net/ipv4/netfilter/ipt_tos.c +++ b/net/ipv4/netfilter/ipt_tos.c @@ -8,11 +8,12 @@ * published by the Free Software Foundation. */ +#include #include #include #include -#include +#include MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("iptables TOS match module"); @@ -32,8 +33,9 @@ match(const struct sk_buff *skb, return (skb->nh.iph->tos == info->tos) ^ info->invert; } -static struct ipt_match tos_match = { +static struct xt_match tos_match = { .name = "tos", + .family = AF_INET, .match = match, .matchsize = sizeof(struct ipt_tos_info), .me = THIS_MODULE, @@ -41,12 +43,12 @@ static struct ipt_match tos_match = { static int __init ipt_multiport_init(void) { - return ipt_register_match(&tos_match); + return xt_register_match(&tos_match); } static void __exit ipt_multiport_fini(void) { - ipt_unregister_match(&tos_match); + xt_unregister_match(&tos_match); } module_init(ipt_multiport_init); diff --git a/net/ipv4/netfilter/ipt_ttl.c b/net/ipv4/netfilter/ipt_ttl.c index a5243bdb87d7..d5cd984e5ed2 100644 --- a/net/ipv4/netfilter/ipt_ttl.c +++ b/net/ipv4/netfilter/ipt_ttl.c @@ -9,11 +9,12 @@ * published by the Free Software Foundation. */ +#include #include #include #include -#include +#include MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("IP tables TTL matching module"); @@ -48,8 +49,9 @@ static int match(const struct sk_buff *skb, return 0; } -static struct ipt_match ttl_match = { +static struct xt_match ttl_match = { .name = "ttl", + .family = AF_INET, .match = match, .matchsize = sizeof(struct ipt_ttl_info), .me = THIS_MODULE, @@ -57,13 +59,12 @@ static struct ipt_match ttl_match = { static int __init ipt_ttl_init(void) { - return ipt_register_match(&ttl_match); + return xt_register_match(&ttl_match); } static void __exit ipt_ttl_fini(void) { - ipt_unregister_match(&ttl_match); - + xt_unregister_match(&ttl_match); } module_init(ipt_ttl_init); diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c index 3745efe70302..de25d63f543c 100644 --- a/net/ipv4/netfilter/nf_nat_rule.c +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -294,7 +294,7 @@ int nf_nat_rule_find(struct sk_buff **pskb, return ret; } -static struct ipt_target ipt_snat_reg = { +static struct xt_target ipt_snat_reg = { .name = "SNAT", .target = ipt_snat_target, .targetsize = sizeof(struct nf_nat_multi_range_compat), diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 99502c5da4c4..7083e1cfb2f5 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -530,7 +530,7 @@ check_match(struct ip6t_entry_match *m, unsigned int hookmask, unsigned int *i) { - struct ip6t_match *match; + struct xt_match *match; int ret; match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name, @@ -564,14 +564,14 @@ err: return ret; } -static struct ip6t_target ip6t_standard_target; +static struct xt_target ip6t_standard_target; static inline int check_entry(struct ip6t_entry *e, const char *name, unsigned int size, unsigned int *i) { struct ip6t_entry_target *t; - struct ip6t_target *target; + struct xt_target *target; int ret; unsigned int j; @@ -1348,13 +1348,13 @@ icmp6_checkentry(const char *tablename, } /* The built-in targets: standard (NULL) and error. */ -static struct ip6t_target ip6t_standard_target = { +static struct xt_target ip6t_standard_target = { .name = IP6T_STANDARD_TARGET, .targetsize = sizeof(int), .family = AF_INET6, }; -static struct ip6t_target ip6t_error_target = { +static struct xt_target ip6t_error_target = { .name = IP6T_ERROR_TARGET, .target = ip6t_error, .targetsize = IP6T_FUNCTION_MAXNAMELEN, @@ -1371,7 +1371,7 @@ static struct nf_sockopt_ops ip6t_sockopts = { .get = do_ip6t_get_ctl, }; -static struct ip6t_match icmp6_matchstruct = { +static struct xt_match icmp6_matchstruct = { .name = "icmp6", .match = &icmp6_match, .matchsize = sizeof(struct ip6t_icmp), diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c index 7e5d51386f56..04e500172fb4 100644 --- a/net/ipv6/netfilter/ip6t_HL.c +++ b/net/ipv6/netfilter/ip6t_HL.c @@ -9,12 +9,13 @@ #include #include #include +#include -#include +#include #include MODULE_AUTHOR("Maciej Soltysiak "); -MODULE_DESCRIPTION("IP tables Hop Limit modification module"); +MODULE_DESCRIPTION("IP6 tables Hop Limit modification module"); MODULE_LICENSE("GPL"); static unsigned int ip6t_hl_target(struct sk_buff **pskb, @@ -54,7 +55,7 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb, ip6h->hop_limit = new_hl; - return IP6T_CONTINUE; + return XT_CONTINUE; } static int ip6t_hl_checkentry(const char *tablename, @@ -78,8 +79,9 @@ static int ip6t_hl_checkentry(const char *tablename, return 1; } -static struct ip6t_target ip6t_HL = { +static struct xt_target ip6t_HL = { .name = "HL", + .family = AF_INET6, .target = ip6t_hl_target, .targetsize = sizeof(struct ip6t_HL_info), .table = "mangle", @@ -89,12 +91,12 @@ static struct ip6t_target ip6t_HL = { static int __init ip6t_hl_init(void) { - return ip6t_register_target(&ip6t_HL); + return xt_register_target(&ip6t_HL); } static void __exit ip6t_hl_fini(void) { - ip6t_unregister_target(&ip6t_HL); + xt_unregister_target(&ip6t_HL); } module_init(ip6t_hl_init); diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 9fe0816bb21d..5587a77b884c 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c @@ -21,6 +21,7 @@ #include #include #include +#include #include MODULE_AUTHOR("Jan Rekorajski "); @@ -442,7 +443,7 @@ ip6t_log_target(struct sk_buff **pskb, ip6t_log_packet(PF_INET6, hooknum, *pskb, in, out, &li, loginfo->prefix); - return IP6T_CONTINUE; + return XT_CONTINUE; } @@ -466,8 +467,9 @@ static int ip6t_log_checkentry(const char *tablename, return 1; } -static struct ip6t_target ip6t_log_reg = { +static struct xt_target ip6t_log_reg = { .name = "LOG", + .family = AF_INET6, .target = ip6t_log_target, .targetsize = sizeof(struct ip6t_log_info), .checkentry = ip6t_log_checkentry, @@ -484,7 +486,7 @@ static int __init ip6t_log_init(void) { int ret; - ret = ip6t_register_target(&ip6t_log_reg); + ret = xt_register_target(&ip6t_log_reg); if (ret < 0) return ret; if (nf_log_register(PF_INET6, &ip6t_logger) < 0) { @@ -500,7 +502,7 @@ static int __init ip6t_log_init(void) static void __exit ip6t_log_fini(void) { nf_log_unregister_logger(&ip6t_logger); - ip6t_unregister_target(&ip6t_log_reg); + xt_unregister_target(&ip6t_log_reg); } module_init(ip6t_log_init); diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 311eae82feb3..278349c18793 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -234,7 +235,7 @@ static int check(const char *tablename, } else if (rejinfo->with == IP6T_TCP_RESET) { /* Must specify that it's a TCP packet */ if (e->ipv6.proto != IPPROTO_TCP - || (e->ipv6.invflags & IP6T_INV_PROTO)) { + || (e->ipv6.invflags & XT_INV_PROTO)) { DEBUGP("ip6t_REJECT: TCP_RESET illegal for non-tcp\n"); return 0; } @@ -242,8 +243,9 @@ static int check(const char *tablename, return 1; } -static struct ip6t_target ip6t_reject_reg = { +static struct xt_target ip6t_reject_reg = { .name = "REJECT", + .family = AF_INET6, .target = reject6_target, .targetsize = sizeof(struct ip6t_reject_info), .table = "filter", @@ -255,12 +257,12 @@ static struct ip6t_target ip6t_reject_reg = { static int __init ip6t_reject_init(void) { - return ip6t_register_target(&ip6t_reject_reg); + return xt_register_target(&ip6t_reject_reg); } static void __exit ip6t_reject_fini(void) { - ip6t_unregister_target(&ip6t_reject_reg); + xt_unregister_target(&ip6t_reject_reg); } module_init(ip6t_reject_init); diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index 46486645eb75..456c76adcbf6 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -118,8 +119,9 @@ checkentry(const char *tablename, return 1; } -static struct ip6t_match ah_match = { +static struct xt_match ah_match = { .name = "ah", + .family = AF_INET6, .match = match, .matchsize = sizeof(struct ip6t_ah), .checkentry = checkentry, @@ -128,12 +130,12 @@ static struct ip6t_match ah_match = { static int __init ip6t_ah_init(void) { - return ip6t_register_match(&ah_match); + return xt_register_match(&ah_match); } static void __exit ip6t_ah_fini(void) { - ip6t_unregister_match(&ah_match); + xt_unregister_match(&ah_match); } module_init(ip6t_ah_init); diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c index 4f6b84c8f4ab..967bed71d4a8 100644 --- a/net/ipv6/netfilter/ip6t_eui64.c +++ b/net/ipv6/netfilter/ip6t_eui64.c @@ -12,6 +12,7 @@ #include #include +#include #include MODULE_DESCRIPTION("IPv6 EUI64 address checking match"); @@ -61,8 +62,9 @@ match(const struct sk_buff *skb, return 0; } -static struct ip6t_match eui64_match = { +static struct xt_match eui64_match = { .name = "eui64", + .family = AF_INET6, .match = match, .matchsize = sizeof(int), .hooks = (1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) | @@ -72,12 +74,12 @@ static struct ip6t_match eui64_match = { static int __init ip6t_eui64_init(void) { - return ip6t_register_match(&eui64_match); + return xt_register_match(&eui64_match); } static void __exit ip6t_eui64_fini(void) { - ip6t_unregister_match(&eui64_match); + xt_unregister_match(&eui64_match); } module_init(ip6t_eui64_init); diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index cd22eaaccdca..5a5da71321b6 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -135,8 +136,9 @@ checkentry(const char *tablename, return 1; } -static struct ip6t_match frag_match = { +static struct xt_match frag_match = { .name = "frag", + .family = AF_INET6, .match = match, .matchsize = sizeof(struct ip6t_frag), .checkentry = checkentry, @@ -145,12 +147,12 @@ static struct ip6t_match frag_match = { static int __init ip6t_frag_init(void) { - return ip6t_register_match(&frag_match); + return xt_register_match(&frag_match); } static void __exit ip6t_frag_fini(void) { - ip6t_unregister_match(&frag_match); + xt_unregister_match(&frag_match); } module_init(ip6t_frag_init); diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c index 3f25babe0440..d2373c7cd354 100644 --- a/net/ipv6/netfilter/ip6t_hbh.c +++ b/net/ipv6/netfilter/ip6t_hbh.c @@ -16,6 +16,7 @@ #include +#include #include #include diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c index 44a729e17c48..601cc1211c62 100644 --- a/net/ipv6/netfilter/ip6t_hl.c +++ b/net/ipv6/netfilter/ip6t_hl.c @@ -8,11 +8,12 @@ * published by the Free Software Foundation. */ +#include #include #include #include -#include +#include MODULE_AUTHOR("Maciej Soltysiak "); MODULE_DESCRIPTION("IP tables Hop Limit matching module"); @@ -48,8 +49,9 @@ static int match(const struct sk_buff *skb, return 0; } -static struct ip6t_match hl_match = { +static struct xt_match hl_match = { .name = "hl", + .family = AF_INET6, .match = match, .matchsize = sizeof(struct ip6t_hl_info), .me = THIS_MODULE, @@ -57,13 +59,12 @@ static struct ip6t_match hl_match = { static int __init ip6t_hl_init(void) { - return ip6t_register_match(&hl_match); + return xt_register_match(&hl_match); } static void __exit ip6t_hl_fini(void) { - ip6t_unregister_match(&hl_match); - + xt_unregister_match(&hl_match); } module_init(ip6t_hl_init); diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c index 3093c398002f..26ac084adefc 100644 --- a/net/ipv6/netfilter/ip6t_ipv6header.c +++ b/net/ipv6/netfilter/ip6t_ipv6header.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -140,8 +141,9 @@ ipv6header_checkentry(const char *tablename, return 1; } -static struct ip6t_match ip6t_ipv6header_match = { +static struct xt_match ip6t_ipv6header_match = { .name = "ipv6header", + .family = AF_INET6, .match = &ipv6header_match, .matchsize = sizeof(struct ip6t_ipv6header_info), .checkentry = &ipv6header_checkentry, @@ -151,12 +153,12 @@ static struct ip6t_match ip6t_ipv6header_match = { static int __init ipv6header_init(void) { - return ip6t_register_match(&ip6t_ipv6header_match); + return xt_register_match(&ip6t_ipv6header_match); } static void __exit ipv6header_exit(void) { - ip6t_unregister_match(&ip6t_ipv6header_match); + xt_unregister_match(&ip6t_ipv6header_match); } module_init(ipv6header_init); diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c index 4eb9bbc4ebc3..43738bba00b5 100644 --- a/net/ipv6/netfilter/ip6t_owner.c +++ b/net/ipv6/netfilter/ip6t_owner.c @@ -16,6 +16,7 @@ #include #include +#include MODULE_AUTHOR("Marc Boucher "); MODULE_DESCRIPTION("IP6 tables owner matching module"); @@ -69,8 +70,9 @@ checkentry(const char *tablename, return 1; } -static struct ip6t_match owner_match = { +static struct xt_match owner_match = { .name = "owner", + .family = AF_INET6, .match = match, .matchsize = sizeof(struct ip6t_owner_info), .hooks = (1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING), @@ -80,12 +82,12 @@ static struct ip6t_match owner_match = { static int __init ip6t_owner_init(void) { - return ip6t_register_match(&owner_match); + return xt_register_match(&owner_match); } static void __exit ip6t_owner_fini(void) { - ip6t_unregister_match(&owner_match); + xt_unregister_match(&owner_match); } module_init(ip6t_owner_init); diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index 54d7d14134fd..81ab00d8c182 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c @@ -16,6 +16,7 @@ #include +#include #include #include @@ -221,8 +222,9 @@ checkentry(const char *tablename, return 1; } -static struct ip6t_match rt_match = { +static struct xt_match rt_match = { .name = "rt", + .family = AF_INET6, .match = match, .matchsize = sizeof(struct ip6t_rt), .checkentry = checkentry, @@ -231,12 +233,12 @@ static struct ip6t_match rt_match = { static int __init ip6t_rt_init(void) { - return ip6t_register_match(&rt_match); + return xt_register_match(&rt_match); } static void __exit ip6t_rt_fini(void) { - ip6t_unregister_match(&rt_match); + xt_unregister_match(&rt_match); } module_init(ip6t_rt_init); -- cgit v1.2.3 From e60a13e030867078f3c9fef8dca6cd8a5b883478 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 7 Feb 2007 15:12:33 -0800 Subject: [NETFILTER]: {ip,ip6}_tables: use struct xt_table instead of redefined structure names Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_tables.h | 9 +++------ include/linux/netfilter_ipv6/ip6_tables.h | 6 +++--- net/ipv4/netfilter/ip_nat_rule.c | 2 +- net/ipv4/netfilter/ip_tables.c | 20 ++++++++++---------- net/ipv4/netfilter/iptable_filter.c | 2 +- net/ipv4/netfilter/iptable_mangle.c | 2 +- net/ipv4/netfilter/iptable_raw.c | 2 +- net/ipv4/netfilter/nf_nat_rule.c | 2 +- net/ipv6/netfilter/ip6table_filter.c | 2 +- net/ipv6/netfilter/ip6table_mangle.c | 2 +- net/sched/act_ipt.c | 2 +- 11 files changed, 24 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index c59bc6ff2280..fccf4b873232 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h @@ -272,12 +272,9 @@ ipt_get_target(struct ipt_entry *e) #include extern void ipt_init(void) __init; -//#define ipt_register_table(tbl, repl) xt_register_table(AF_INET, tbl, repl) -//#define ipt_unregister_table(tbl) xt_unregister_table(AF_INET, tbl) - -extern int ipt_register_table(struct ipt_table *table, +extern int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl); -extern void ipt_unregister_table(struct ipt_table *table); +extern void ipt_unregister_table(struct xt_table *table); /* net/sched/ipt.c: Gimme access to your targets! Gets target->me. */ extern struct xt_target *ipt_find_target(const char *name, u8 revision); @@ -305,7 +302,7 @@ extern unsigned int ipt_do_table(struct sk_buff **pskb, unsigned int hook, const struct net_device *in, const struct net_device *out, - struct ipt_table *table); + struct xt_table *table); #define IPT_ALIGN(s) XT_ALIGN(s) diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 2fbabab30d21..e37698c337ad 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h @@ -286,14 +286,14 @@ ip6t_get_target(struct ip6t_entry *e) #include extern void ip6t_init(void) __init; -extern int ip6t_register_table(struct ip6t_table *table, +extern int ip6t_register_table(struct xt_table *table, const struct ip6t_replace *repl); -extern void ip6t_unregister_table(struct ip6t_table *table); +extern void ip6t_unregister_table(struct xt_table *table); extern unsigned int ip6t_do_table(struct sk_buff **pskb, unsigned int hook, const struct net_device *in, const struct net_device *out, - struct ip6t_table *table); + struct xt_table *table); /* Check for an extension */ extern int ip6t_ext_hdr(u8 nexthdr); diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c index 7a8e7bb577e2..e1c8a05f3dc6 100644 --- a/net/ipv4/netfilter/ip_nat_rule.c +++ b/net/ipv4/netfilter/ip_nat_rule.c @@ -86,7 +86,7 @@ static struct } }; -static struct ipt_table nat_table = { +static struct xt_table nat_table = { .name = "nat", .valid_hooks = NAT_VALID_HOOKS, .lock = RW_LOCK_UNLOCKED, diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 0043e908b130..5a7b3a341389 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -216,7 +216,7 @@ ipt_do_table(struct sk_buff **pskb, unsigned int hook, const struct net_device *in, const struct net_device *out, - struct ipt_table *table) + struct xt_table *table) { static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); u_int16_t offset; @@ -818,7 +818,7 @@ get_counters(const struct xt_table_info *t, } } -static inline struct xt_counters * alloc_counters(struct ipt_table *table) +static inline struct xt_counters * alloc_counters(struct xt_table *table) { unsigned int countersize; struct xt_counters *counters; @@ -843,7 +843,7 @@ static inline struct xt_counters * alloc_counters(struct ipt_table *table) static int copy_entries_to_user(unsigned int total_size, - struct ipt_table *table, + struct xt_table *table, void __user *userptr) { unsigned int off, num; @@ -1046,7 +1046,7 @@ static int compat_table_info(struct xt_table_info *info, static int get_info(void __user *user, int *len, int compat) { char name[IPT_TABLE_MAXNAMELEN]; - struct ipt_table *t; + struct xt_table *t; int ret; if (*len != sizeof(struct ipt_getinfo)) { @@ -1107,7 +1107,7 @@ get_entries(struct ipt_get_entries __user *uptr, int *len) { int ret; struct ipt_get_entries get; - struct ipt_table *t; + struct xt_table *t; if (*len < sizeof(get)) { duprintf("get_entries: %u < %d\n", *len, @@ -1151,7 +1151,7 @@ __do_replace(const char *name, unsigned int valid_hooks, void __user *counters_ptr) { int ret; - struct ipt_table *t; + struct xt_table *t; struct xt_table_info *oldinfo; struct xt_counters *counters; void *loc_cpu_old_entry; @@ -1302,7 +1302,7 @@ do_add_counters(void __user *user, unsigned int len, int compat) char *name; int size; void *ptmp; - struct ipt_table *t; + struct xt_table *t; struct xt_table_info *private; int ret = 0; void *loc_cpu_entry; @@ -1795,7 +1795,7 @@ struct compat_ipt_get_entries }; static int compat_copy_entries_to_user(unsigned int total_size, - struct ipt_table *table, void __user *userptr) + struct xt_table *table, void __user *userptr) { unsigned int off, num; struct compat_ipt_entry e; @@ -1869,7 +1869,7 @@ compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len) { int ret; struct compat_ipt_get_entries get; - struct ipt_table *t; + struct xt_table *t; if (*len < sizeof(get)) { @@ -2052,7 +2052,7 @@ int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl) return 0; } -void ipt_unregister_table(struct ipt_table *table) +void ipt_unregister_table(struct xt_table *table) { struct xt_table_info *private; void *loc_cpu_entry; diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index e2e7dd8d7903..51053cb42f43 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -74,7 +74,7 @@ static struct } }; -static struct ipt_table packet_filter = { +static struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, .lock = RW_LOCK_UNLOCKED, diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index af2939889444..a532e4d84332 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -103,7 +103,7 @@ static struct } }; -static struct ipt_table packet_mangler = { +static struct xt_table packet_mangler = { .name = "mangle", .valid_hooks = MANGLE_VALID_HOOKS, .lock = RW_LOCK_UNLOCKED, diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index bcbeb4aeacd9..5277550fa6b5 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -79,7 +79,7 @@ static struct } }; -static struct ipt_table packet_raw = { +static struct xt_table packet_raw = { .name = "raw", .valid_hooks = RAW_VALID_HOOKS, .lock = RW_LOCK_UNLOCKED, diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c index de25d63f543c..7f95b4e2eb31 100644 --- a/net/ipv4/netfilter/nf_nat_rule.c +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -119,7 +119,7 @@ static struct } }; -static struct ipt_table nat_table = { +static struct xt_table nat_table = { .name = "nat", .valid_hooks = NAT_VALID_HOOKS, .lock = RW_LOCK_UNLOCKED, diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 2fc07c74decf..45b8342875a8 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -92,7 +92,7 @@ static struct } }; -static struct ip6t_table packet_filter = { +static struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, .lock = RW_LOCK_UNLOCKED, diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 6250e86a6ddc..6f67ee190fa7 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -122,7 +122,7 @@ static struct } }; -static struct ip6t_table packet_mangler = { +static struct xt_table packet_mangler = { .name = "mangle", .valid_hooks = MANGLE_VALID_HOOKS, .lock = RW_LOCK_UNLOCKED, diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index 01e69138578d..4c68c718f5ec 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -52,7 +52,7 @@ static struct tcf_hashinfo ipt_hash_info = { static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook) { - struct ipt_target *target; + struct xt_target *target; int ret = 0; target = xt_request_find_target(AF_INET, t->u.user.name, -- cgit v1.2.3 From a0ca215a730b2c4d5024143e64b0d80d50858667 Mon Sep 17 00:00:00 2001 From: Masahide NAKAMURA Date: Wed, 7 Feb 2007 15:12:57 -0800 Subject: [NETFILTER]: ip6_tables: support MH match This introduces match for Mobility Header (MH) described by Mobile IPv6 specification (RFC3775). User can specify the MH type or its range to be matched. Signed-off-by: Masahide NAKAMURA Signed-off-by: Yasuyuki Kozakai Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter_ipv6/ip6t_mh.h | 15 +++++ net/ipv6/netfilter/Kconfig | 8 +++ net/ipv6/netfilter/Makefile | 1 + net/ipv6/netfilter/ip6t_mh.c | 108 +++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+) create mode 100644 include/linux/netfilter_ipv6/ip6t_mh.h create mode 100644 net/ipv6/netfilter/ip6t_mh.c (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv6/ip6t_mh.h b/include/linux/netfilter_ipv6/ip6t_mh.h new file mode 100644 index 000000000000..b9ca9a5f74d0 --- /dev/null +++ b/include/linux/netfilter_ipv6/ip6t_mh.h @@ -0,0 +1,15 @@ +#ifndef _IP6T_MH_H +#define _IP6T_MH_H + +/* MH matching stuff */ +struct ip6t_mh +{ + u_int8_t types[2]; /* MH type range */ + u_int8_t invflags; /* Inverse flags */ +}; + +/* Values for "invflags" field in struct ip6t_mh. */ +#define IP6T_MH_INV_TYPE 0x01 /* Invert the sense of type. */ +#define IP6T_MH_INV_MASK 0x01 /* All possible flags. */ + +#endif /*_IP6T_MH_H*/ diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index adcd6131df2a..cd549aea84f0 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig @@ -114,6 +114,14 @@ config IP6_NF_MATCH_AH To compile it as a module, choose M here. If unsure, say N. +config IP6_NF_MATCH_MH + tristate "MH match support" + depends on IP6_NF_IPTABLES + help + This module allows one to match MH packets. + + To compile it as a module, choose M here. If unsure, say N. + config IP6_NF_MATCH_EUI64 tristate "EUI64 address check" depends on IP6_NF_IPTABLES diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index ac1dfebde175..4513eab77397 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o +obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o # objects for l3 independent conntrack nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o diff --git a/net/ipv6/netfilter/ip6t_mh.c b/net/ipv6/netfilter/ip6t_mh.c new file mode 100644 index 000000000000..2c7efc6a506d --- /dev/null +++ b/net/ipv6/netfilter/ip6t_mh.c @@ -0,0 +1,108 @@ +/* + * Copyright (C)2006 USAGI/WIDE Project + * + * 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. + * + * Author: + * Masahide NAKAMURA @USAGI + * + * Based on net/netfilter/xt_tcpudp.c + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_DESCRIPTION("ip6t_tables match for MH"); +MODULE_LICENSE("GPL"); + +#ifdef DEBUG_IP_FIREWALL_USER +#define duprintf(format, args...) printk(format , ## args) +#else +#define duprintf(format, args...) +#endif + +/* Returns 1 if the type is matched by the range, 0 otherwise */ +static inline int +type_match(u_int8_t min, u_int8_t max, u_int8_t type, int invert) +{ + int ret; + + ret = (type >= min && type <= max) ^ invert; + return ret; +} + +static int +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, + int *hotdrop) +{ + struct ip6_mh _mh, *mh; + const struct ip6t_mh *mhinfo = matchinfo; + + /* Must not be a fragment. */ + if (offset) + return 0; + + mh = skb_header_pointer(skb, protoff, sizeof(_mh), &_mh); + if (mh == NULL) { + /* We've been asked to examine this packet, and we + can't. Hence, no choice but to drop. */ + duprintf("Dropping evil MH tinygram.\n"); + *hotdrop = 1; + return 0; + } + + return type_match(mhinfo->types[0], mhinfo->types[1], mh->ip6mh_type, + !!(mhinfo->invflags & IP6T_MH_INV_TYPE)); +} + +/* Called when user tries to insert an entry of this type. */ +static int +mh_checkentry(const char *tablename, + const void *entry, + const struct xt_match *match, + void *matchinfo, + unsigned int hook_mask) +{ + const struct ip6t_mh *mhinfo = matchinfo; + + /* Must specify no unknown invflags */ + return !(mhinfo->invflags & ~IP6T_MH_INV_MASK); +} + +static struct xt_match mh_match = { + .name = "mh", + .family = AF_INET6, + .checkentry = mh_checkentry, + .match = match, + .matchsize = sizeof(struct ip6t_mh), + .proto = IPPROTO_MH, + .me = THIS_MODULE, +}; + +static int __init ip6t_mh_init(void) +{ + return xt_register_match(&mh_match); +} + +static void __exit ip6t_mh_fini(void) +{ + xt_unregister_match(&mh_match); +} + +module_init(ip6t_mh_init); +module_exit(ip6t_mh_fini); -- cgit v1.2.3 From c3e79c05b45c3d6115d8c46e3012939c71573f13 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 7 Feb 2007 15:13:20 -0800 Subject: [NETFILTER]: ip_tables: remove declaration of non-existant ipt_find_target function Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_tables.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index fccf4b873232..9527296595cd 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h @@ -276,9 +276,6 @@ extern int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl); extern void ipt_unregister_table(struct xt_table *table); -/* net/sched/ipt.c: Gimme access to your targets! Gets target->me. */ -extern struct xt_target *ipt_find_target(const char *name, u8 revision); - /* Standard entry. */ struct ipt_standard { -- cgit v1.2.3 From 9934e81c8c4981342dab3e386aff5d4499bea0d2 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 7 Feb 2007 15:14:28 -0800 Subject: [NETFILTER]: ip6_tables: remove redundant structure definitions Move ip6t_standard/ip6t_error_target/ip6t_error definitions to ip6_tables.h instead of defining them in each table individually. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter_ipv6/ip6_tables.h | 19 +++++++++++++++++++ net/ipv6/netfilter/ip6table_filter.c | 19 ------------------- net/ipv6/netfilter/ip6table_mangle.c | 19 ------------------- net/ipv6/netfilter/ip6table_raw.c | 19 ------------------- 4 files changed, 19 insertions(+), 57 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index e37698c337ad..61aa10412fc8 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h @@ -104,6 +104,25 @@ struct ip6t_entry unsigned char elems[0]; }; +/* Standard entry */ +struct ip6t_standard +{ + struct ip6t_entry entry; + struct ip6t_standard_target target; +}; + +struct ip6t_error_target +{ + struct ip6t_entry_target target; + char errorname[IP6T_FUNCTION_MAXNAMELEN]; +}; + +struct ip6t_error +{ + struct ip6t_entry entry; + struct ip6t_error_target target; +}; + /* * New IP firewall options for [gs]etsockopt at the RAW IP level. * Unlike BSD Linux inherits IP options so you don't have to use diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 45b8342875a8..112a21d0c6da 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -19,25 +19,6 @@ MODULE_DESCRIPTION("ip6tables filter table"); #define FILTER_VALID_HOOKS ((1 << NF_IP6_LOCAL_IN) | (1 << NF_IP6_FORWARD) | (1 << NF_IP6_LOCAL_OUT)) -/* Standard entry. */ -struct ip6t_standard -{ - struct ip6t_entry entry; - struct ip6t_standard_target target; -}; - -struct ip6t_error_target -{ - struct ip6t_entry_target target; - char errorname[IP6T_FUNCTION_MAXNAMELEN]; -}; - -struct ip6t_error -{ - struct ip6t_entry entry; - struct ip6t_error_target target; -}; - static struct { struct ip6t_replace repl; diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 6f67ee190fa7..5f5aa0e51478 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -29,25 +29,6 @@ MODULE_DESCRIPTION("ip6tables mangle table"); #define DEBUGP(x, args...) #endif -/* Standard entry. */ -struct ip6t_standard -{ - struct ip6t_entry entry; - struct ip6t_standard_target target; -}; - -struct ip6t_error_target -{ - struct ip6t_entry_target target; - char errorname[IP6T_FUNCTION_MAXNAMELEN]; -}; - -struct ip6t_error -{ - struct ip6t_entry entry; - struct ip6t_error_target target; -}; - static struct { struct ip6t_replace repl; diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index b4154da575c0..277bf34638b4 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -14,25 +14,6 @@ #define DEBUGP(x, args...) #endif -/* Standard entry. */ -struct ip6t_standard -{ - struct ip6t_entry entry; - struct ip6t_standard_target target; -}; - -struct ip6t_error_target -{ - struct ip6t_entry_target target; - char errorname[IP6T_FUNCTION_MAXNAMELEN]; -}; - -struct ip6t_error -{ - struct ip6t_entry entry; - struct ip6t_error_target target; -}; - static struct { struct ip6t_replace repl; -- cgit v1.2.3 From 80c9abaabf4283f7cf4a0b3597cd302506635b7f Mon Sep 17 00:00:00 2001 From: Shinta Sugimoto Date: Thu, 8 Feb 2007 13:11:42 -0800 Subject: [XFRM]: Extension for dynamic update of endpoint address(es) Extend the XFRM framework so that endpoint address(es) in the XFRM databases could be dynamically updated according to a request (MIGRATE message) from user application. Target XFRM policy is first identified by the selector in the MIGRATE message. Next, the endpoint addresses of the matching templates and XFRM states are updated according to the MIGRATE message. Signed-off-by: Shinta Sugimoto Signed-off-by: Masahide NAKAMURA Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/linux/xfrm.h | 19 ++++ include/net/xfrm.h | 44 ++++++++++ net/xfrm/xfrm_policy.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++ net/xfrm/xfrm_state.c | 174 +++++++++++++++++++++++++++++++++++++ 4 files changed, 467 insertions(+) (limited to 'include/linux') diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 9529ea1ae392..15ca89e9961b 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -178,6 +178,9 @@ enum { XFRM_MSG_REPORT, #define XFRM_MSG_REPORT XFRM_MSG_REPORT + XFRM_MSG_MIGRATE, +#define XFRM_MSG_MIGRATE XFRM_MSG_MIGRATE + __XFRM_MSG_MAX }; #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1) @@ -256,6 +259,7 @@ enum xfrm_attr_type_t { XFRMA_COADDR, /* xfrm_address_t */ XFRMA_LASTUSED, XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */ + XFRMA_MIGRATE, __XFRMA_MAX #define XFRMA_MAX (__XFRMA_MAX - 1) @@ -351,6 +355,19 @@ struct xfrm_user_report { struct xfrm_selector sel; }; +struct xfrm_user_migrate { + xfrm_address_t old_daddr; + xfrm_address_t old_saddr; + xfrm_address_t new_daddr; + xfrm_address_t new_saddr; + __u8 proto; + __u8 mode; + __u16 reserved; + __u32 reqid; + __u16 old_family; + __u16 new_family; +}; + #ifndef __KERNEL__ /* backwards compatibility for userspace */ #define XFRMGRP_ACQUIRE 1 @@ -375,6 +392,8 @@ enum xfrm_nlgroups { #define XFRMNLGRP_AEVENTS XFRMNLGRP_AEVENTS XFRMNLGRP_REPORT, #define XFRMNLGRP_REPORT XFRMNLGRP_REPORT + XFRMNLGRP_MIGRATE, +#define XFRMNLGRP_MIGRATE XFRMNLGRP_MIGRATE __XFRMNLGRP_MAX }; #define XFRMNLGRP_MAX (__XFRMNLGRP_MAX - 1) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index bf91d632901d..16924cb772c9 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -362,6 +362,19 @@ struct xfrm_policy struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; }; +struct xfrm_migrate { + xfrm_address_t old_daddr; + xfrm_address_t old_saddr; + xfrm_address_t new_daddr; + xfrm_address_t new_saddr; + u8 proto; + u8 mode; + u16 reserved; + u32 reqid; + u16 old_family; + u16 new_family; +}; + #define XFRM_KM_TIMEOUT 30 /* which seqno */ #define XFRM_REPLAY_SEQ 1 @@ -388,6 +401,7 @@ struct xfrm_mgr int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c); int (*report)(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); + int (*migrate)(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_bundles); }; extern int xfrm_register_km(struct xfrm_mgr *km); @@ -988,6 +1002,16 @@ extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst, struct flowi *fl, int family, int strict); extern void xfrm_init_pmtu(struct dst_entry *dst); +#ifdef CONFIG_XFRM_MIGRATE +extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, + struct xfrm_migrate *m, int num_bundles); +extern struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m); +extern struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, + struct xfrm_migrate *m); +extern int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, + struct xfrm_migrate *m, int num_bundles); +#endif + extern wait_queue_head_t km_waitq; extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid); @@ -1053,5 +1077,25 @@ static inline void xfrm_aevent_doreplay(struct xfrm_state *x) xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); } +#ifdef CONFIG_XFRM_MIGRATE +static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig) +{ + return (struct xfrm_algo *)kmemdup(orig, sizeof(*orig) + orig->alg_key_len, GFP_KERNEL); +} + +static inline void xfrm_states_put(struct xfrm_state **states, int n) +{ + int i; + for (i = 0; i < n; i++) + xfrm_state_put(*(states + i)); +} + +static inline void xfrm_states_delete(struct xfrm_state **states, int n) +{ + int i; + for (i = 0; i < n; i++) + xfrm_state_delete(*(states + i)); +} +#endif #endif /* _NET_XFRM_H */ diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index b7e537fe2d75..825c60af7723 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2236,3 +2236,233 @@ void __init xfrm_init(void) xfrm_input_init(); } +#ifdef CONFIG_XFRM_MIGRATE +static int xfrm_migrate_selector_match(struct xfrm_selector *sel_cmp, + struct xfrm_selector *sel_tgt) +{ + if (sel_cmp->proto == IPSEC_ULPROTO_ANY) { + if (sel_tgt->family == sel_cmp->family && + xfrm_addr_cmp(&sel_tgt->daddr, &sel_cmp->daddr, + sel_cmp->family) == 0 && + xfrm_addr_cmp(&sel_tgt->saddr, &sel_cmp->saddr, + sel_cmp->family) == 0 && + sel_tgt->prefixlen_d == sel_cmp->prefixlen_d && + sel_tgt->prefixlen_s == sel_cmp->prefixlen_s) { + return 1; + } + } else { + if (memcmp(sel_tgt, sel_cmp, sizeof(*sel_tgt)) == 0) { + return 1; + } + } + return 0; +} + +static struct xfrm_policy * xfrm_migrate_policy_find(struct xfrm_selector *sel, + u8 dir, u8 type) +{ + struct xfrm_policy *pol, *ret = NULL; + struct hlist_node *entry; + struct hlist_head *chain; + u32 priority = ~0U; + + read_lock_bh(&xfrm_policy_lock); + chain = policy_hash_direct(&sel->daddr, &sel->saddr, sel->family, dir); + hlist_for_each_entry(pol, entry, chain, bydst) { + if (xfrm_migrate_selector_match(sel, &pol->selector) && + pol->type == type) { + ret = pol; + priority = ret->priority; + break; + } + } + chain = &xfrm_policy_inexact[dir]; + hlist_for_each_entry(pol, entry, chain, bydst) { + if (xfrm_migrate_selector_match(sel, &pol->selector) && + pol->type == type && + pol->priority < priority) { + ret = pol; + break; + } + } + + if (ret) + xfrm_pol_hold(ret); + + read_unlock_bh(&xfrm_policy_lock); + + return ret; +} + +static int migrate_tmpl_match(struct xfrm_migrate *m, struct xfrm_tmpl *t) +{ + int match = 0; + + if (t->mode == m->mode && t->id.proto == m->proto && + (m->reqid == 0 || t->reqid == m->reqid)) { + switch (t->mode) { + case XFRM_MODE_TUNNEL: + case XFRM_MODE_BEET: + if (xfrm_addr_cmp(&t->id.daddr, &m->old_daddr, + m->old_family) == 0 && + xfrm_addr_cmp(&t->saddr, &m->old_saddr, + m->old_family) == 0) { + match = 1; + } + break; + case XFRM_MODE_TRANSPORT: + /* in case of transport mode, template does not store + any IP addresses, hence we just compare mode and + protocol */ + match = 1; + break; + default: + break; + } + } + return match; +} + +/* update endpoint address(es) of template(s) */ +static int xfrm_policy_migrate(struct xfrm_policy *pol, + struct xfrm_migrate *m, int num_migrate) +{ + struct xfrm_migrate *mp; + struct dst_entry *dst; + int i, j, n = 0; + + write_lock_bh(&pol->lock); + if (unlikely(pol->dead)) { + /* target policy has been deleted */ + write_unlock_bh(&pol->lock); + return -ENOENT; + } + + for (i = 0; i < pol->xfrm_nr; i++) { + for (j = 0, mp = m; j < num_migrate; j++, mp++) { + if (!migrate_tmpl_match(mp, &pol->xfrm_vec[i])) + continue; + n++; + if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL) + continue; + /* update endpoints */ + memcpy(&pol->xfrm_vec[i].id.daddr, &mp->new_daddr, + sizeof(pol->xfrm_vec[i].id.daddr)); + memcpy(&pol->xfrm_vec[i].saddr, &mp->new_saddr, + sizeof(pol->xfrm_vec[i].saddr)); + pol->xfrm_vec[i].encap_family = mp->new_family; + /* flush bundles */ + while ((dst = pol->bundles) != NULL) { + pol->bundles = dst->next; + dst_free(dst); + } + } + } + + write_unlock_bh(&pol->lock); + + if (!n) + return -ENODATA; + + return 0; +} + +static int xfrm_migrate_check(struct xfrm_migrate *m, int num_migrate) +{ + int i, j; + + if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH) + return -EINVAL; + + for (i = 0; i < num_migrate; i++) { + if ((xfrm_addr_cmp(&m[i].old_daddr, &m[i].new_daddr, + m[i].old_family) == 0) && + (xfrm_addr_cmp(&m[i].old_saddr, &m[i].new_saddr, + m[i].old_family) == 0)) + return -EINVAL; + if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) || + xfrm_addr_any(&m[i].new_saddr, m[i].new_family)) + return -EINVAL; + + /* check if there is any duplicated entry */ + for (j = i + 1; j < num_migrate; j++) { + if (!memcmp(&m[i].old_daddr, &m[j].old_daddr, + sizeof(m[i].old_daddr)) && + !memcmp(&m[i].old_saddr, &m[j].old_saddr, + sizeof(m[i].old_saddr)) && + m[i].proto == m[j].proto && + m[i].mode == m[j].mode && + m[i].reqid == m[j].reqid && + m[i].old_family == m[j].old_family) + return -EINVAL; + } + } + + return 0; +} + +int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, + struct xfrm_migrate *m, int num_migrate) +{ + int i, err, nx_cur = 0, nx_new = 0; + struct xfrm_policy *pol = NULL; + struct xfrm_state *x, *xc; + struct xfrm_state *x_cur[XFRM_MAX_DEPTH]; + struct xfrm_state *x_new[XFRM_MAX_DEPTH]; + struct xfrm_migrate *mp; + + if ((err = xfrm_migrate_check(m, num_migrate)) < 0) + goto out; + + /* Stage 1 - find policy */ + if ((pol = xfrm_migrate_policy_find(sel, dir, type)) == NULL) { + err = -ENOENT; + goto out; + } + + /* Stage 2 - find and update state(s) */ + for (i = 0, mp = m; i < num_migrate; i++, mp++) { + if ((x = xfrm_migrate_state_find(mp))) { + x_cur[nx_cur] = x; + nx_cur++; + if ((xc = xfrm_state_migrate(x, mp))) { + x_new[nx_new] = xc; + nx_new++; + } else { + err = -ENODATA; + goto restore_state; + } + } + } + + /* Stage 3 - update policy */ + if ((err = xfrm_policy_migrate(pol, m, num_migrate)) < 0) + goto restore_state; + + /* Stage 4 - delete old state(s) */ + if (nx_cur) { + xfrm_states_put(x_cur, nx_cur); + xfrm_states_delete(x_cur, nx_cur); + } + + /* Stage 5 - announce */ + km_migrate(sel, dir, type, m, num_migrate); + + xfrm_pol_put(pol); + + return 0; +out: + return err; + +restore_state: + if (pol) + xfrm_pol_put(pol); + if (nx_cur) + xfrm_states_put(x_cur, nx_cur); + if (nx_new) + xfrm_states_delete(x_new, nx_new); + + return err; +} +#endif + diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 24f7bfd07af2..91b02687db52 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -828,6 +828,160 @@ out: } EXPORT_SYMBOL(xfrm_state_add); +#ifdef CONFIG_XFRM_MIGRATE +struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) +{ + int err = -ENOMEM; + struct xfrm_state *x = xfrm_state_alloc(); + if (!x) + goto error; + + memcpy(&x->id, &orig->id, sizeof(x->id)); + memcpy(&x->sel, &orig->sel, sizeof(x->sel)); + memcpy(&x->lft, &orig->lft, sizeof(x->lft)); + x->props.mode = orig->props.mode; + x->props.replay_window = orig->props.replay_window; + x->props.reqid = orig->props.reqid; + x->props.family = orig->props.family; + x->props.saddr = orig->props.saddr; + + if (orig->aalg) { + x->aalg = xfrm_algo_clone(orig->aalg); + if (!x->aalg) + goto error; + } + x->props.aalgo = orig->props.aalgo; + + if (orig->ealg) { + x->ealg = xfrm_algo_clone(orig->ealg); + if (!x->ealg) + goto error; + } + x->props.ealgo = orig->props.ealgo; + + if (orig->calg) { + x->calg = xfrm_algo_clone(orig->calg); + if (!x->calg) + goto error; + } + x->props.calgo = orig->props.calgo; + + if (orig->encap) { + x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL); + if (!x->encap) + goto error; + } + + if (orig->coaddr) { + x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), + GFP_KERNEL); + if (!x->coaddr) + goto error; + } + + err = xfrm_init_state(x); + if (err) + goto error; + + x->props.flags = orig->props.flags; + + x->curlft.add_time = orig->curlft.add_time; + x->km.state = orig->km.state; + x->km.seq = orig->km.seq; + + return x; + + error: + if (errp) + *errp = err; + if (x) { + kfree(x->aalg); + kfree(x->ealg); + kfree(x->calg); + kfree(x->encap); + kfree(x->coaddr); + } + kfree(x); + return NULL; +} +EXPORT_SYMBOL(xfrm_state_clone); + +/* xfrm_state_lock is held */ +struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) +{ + unsigned int h; + struct xfrm_state *x; + struct hlist_node *entry; + + if (m->reqid) { + h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr, + m->reqid, m->old_family); + hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { + if (x->props.mode != m->mode || + x->id.proto != m->proto) + continue; + if (m->reqid && x->props.reqid != m->reqid) + continue; + if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, + m->old_family) || + xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, + m->old_family)) + continue; + xfrm_state_hold(x); + return x; + } + } else { + h = xfrm_src_hash(&m->old_daddr, &m->old_saddr, + m->old_family); + hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { + if (x->props.mode != m->mode || + x->id.proto != m->proto) + continue; + if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, + m->old_family) || + xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, + m->old_family)) + continue; + xfrm_state_hold(x); + return x; + } + } + + return NULL; +} +EXPORT_SYMBOL(xfrm_migrate_state_find); + +struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, + struct xfrm_migrate *m) +{ + struct xfrm_state *xc; + int err; + + xc = xfrm_state_clone(x, &err); + if (!xc) + return NULL; + + memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); + memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); + + /* add state */ + if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) { + /* a care is needed when the destination address of the + state is to be updated as it is a part of triplet */ + xfrm_state_insert(xc); + } else { + if ((err = xfrm_state_add(xc)) < 0) + goto error; + } + + return xc; +error: + kfree(xc); + return NULL; +} +EXPORT_SYMBOL(xfrm_state_migrate); +#endif + int xfrm_state_update(struct xfrm_state *x) { struct xfrm_state *x1; @@ -1342,6 +1496,26 @@ void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid) } EXPORT_SYMBOL(km_policy_expired); +int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, + struct xfrm_migrate *m, int num_migrate) +{ + int err = -EINVAL; + int ret; + struct xfrm_mgr *km; + + read_lock(&xfrm_km_lock); + list_for_each_entry(km, &xfrm_km_list, list) { + if (km->migrate) { + ret = km->migrate(sel, dir, type, m, num_migrate); + if (!ret) + err = ret; + } + } + read_unlock(&xfrm_km_lock); + return err; +} +EXPORT_SYMBOL(km_migrate); + int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) { int err = -EINVAL; -- cgit v1.2.3 From 08de61beab8a21c8e0b3906a97defda5f1f66ece Mon Sep 17 00:00:00 2001 From: Shinta Sugimoto Date: Thu, 8 Feb 2007 13:14:33 -0800 Subject: [PFKEYV2]: Extension for dynamic update of endpoint address(es) Extend PF_KEYv2 framework so that user application can take advantage of MIGRATE feature via PF_KEYv2 interface. User application can either send or receive an MIGRATE message to/from PF_KEY socket. Detail information can be found in the internet-draft . Signed-off-by: Shinta Sugimoto Signed-off-by: Masahide NAKAMURA Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/linux/pfkeyv2.h | 3 +- net/key/af_key.c | 422 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 424 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index 265bafab6494..26a518b67c02 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h @@ -251,7 +251,8 @@ struct sadb_x_sec_ctx { #define SADB_X_SPDEXPIRE 21 #define SADB_X_SPDDELETE2 22 #define SADB_X_NAT_T_NEW_MAPPING 23 -#define SADB_MAX 23 +#define SADB_X_MIGRATE 24 +#define SADB_MAX 24 /* Security Association flags */ #define SADB_SAFLAGS_PFS 1 diff --git a/net/key/af_key.c b/net/key/af_key.c index 5dd5094659a1..b4e444063d1f 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2345,6 +2345,196 @@ out: return err; } +#ifdef CONFIG_NET_KEY_MIGRATE +static int pfkey_sockaddr_pair_size(sa_family_t family) +{ + switch (family) { + case AF_INET: + return PFKEY_ALIGN8(sizeof(struct sockaddr_in) * 2); +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + return PFKEY_ALIGN8(sizeof(struct sockaddr_in6) * 2); +#endif + default: + return 0; + } + /* NOTREACHED */ +} + +static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq, + xfrm_address_t *saddr, xfrm_address_t *daddr, + u16 *family) +{ + struct sockaddr *sa = (struct sockaddr *)(rq + 1); + if (rq->sadb_x_ipsecrequest_len < + pfkey_sockaddr_pair_size(sa->sa_family)) + return -EINVAL; + + switch (sa->sa_family) { + case AF_INET: + { + struct sockaddr_in *sin; + sin = (struct sockaddr_in *)sa; + if ((sin+1)->sin_family != AF_INET) + return -EINVAL; + memcpy(&saddr->a4, &sin->sin_addr, sizeof(saddr->a4)); + sin++; + memcpy(&daddr->a4, &sin->sin_addr, sizeof(daddr->a4)); + *family = AF_INET; + break; + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + { + struct sockaddr_in6 *sin6; + sin6 = (struct sockaddr_in6 *)sa; + if ((sin6+1)->sin6_family != AF_INET6) + return -EINVAL; + memcpy(&saddr->a6, &sin6->sin6_addr, + sizeof(saddr->a6)); + sin6++; + memcpy(&daddr->a6, &sin6->sin6_addr, + sizeof(daddr->a6)); + *family = AF_INET6; + break; + } +#endif + default: + return -EINVAL; + } + + return 0; +} + +static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, + struct xfrm_migrate *m) +{ + int err; + struct sadb_x_ipsecrequest *rq2; + + if (len <= sizeof(struct sadb_x_ipsecrequest) || + len < rq1->sadb_x_ipsecrequest_len) + return -EINVAL; + + /* old endoints */ + err = parse_sockaddr_pair(rq1, &m->old_saddr, &m->old_daddr, + &m->old_family); + if (err) + return err; + + rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len); + len -= rq1->sadb_x_ipsecrequest_len; + + if (len <= sizeof(struct sadb_x_ipsecrequest) || + len < rq2->sadb_x_ipsecrequest_len) + return -EINVAL; + + /* new endpoints */ + err = parse_sockaddr_pair(rq2, &m->new_saddr, &m->new_daddr, + &m->new_family); + if (err) + return err; + + if (rq1->sadb_x_ipsecrequest_proto != rq2->sadb_x_ipsecrequest_proto || + rq1->sadb_x_ipsecrequest_mode != rq2->sadb_x_ipsecrequest_mode || + rq1->sadb_x_ipsecrequest_reqid != rq2->sadb_x_ipsecrequest_reqid) + return -EINVAL; + + m->proto = rq1->sadb_x_ipsecrequest_proto; + m->mode = rq1->sadb_x_ipsecrequest_mode - 1; + m->reqid = rq1->sadb_x_ipsecrequest_reqid; + + return ((int)(rq1->sadb_x_ipsecrequest_len + + rq2->sadb_x_ipsecrequest_len)); +} + +static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, + struct sadb_msg *hdr, void **ext_hdrs) +{ + int i, len, ret, err = -EINVAL; + u8 dir; + struct sadb_address *sa; + struct sadb_x_policy *pol; + struct sadb_x_ipsecrequest *rq; + struct xfrm_selector sel; + struct xfrm_migrate m[XFRM_MAX_DEPTH]; + + if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1], + ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) || + !ext_hdrs[SADB_X_EXT_POLICY - 1]) { + err = -EINVAL; + goto out; + } + + pol = ext_hdrs[SADB_X_EXT_POLICY - 1]; + if (!pol) { + err = -EINVAL; + goto out; + } + + if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) { + err = -EINVAL; + goto out; + } + + dir = pol->sadb_x_policy_dir - 1; + memset(&sel, 0, sizeof(sel)); + + /* set source address info of selector */ + sa = ext_hdrs[SADB_EXT_ADDRESS_SRC - 1]; + sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr); + sel.prefixlen_s = sa->sadb_address_prefixlen; + sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); + sel.sport = ((struct sockaddr_in *)(sa + 1))->sin_port; + if (sel.sport) + sel.sport_mask = ~0; + + /* set destination address info of selector */ + sa = ext_hdrs[SADB_EXT_ADDRESS_DST - 1], + pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr); + sel.prefixlen_d = sa->sadb_address_prefixlen; + sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); + sel.dport = ((struct sockaddr_in *)(sa + 1))->sin_port; + if (sel.dport) + sel.dport_mask = ~0; + + rq = (struct sadb_x_ipsecrequest *)(pol + 1); + + /* extract ipsecrequests */ + i = 0; + len = pol->sadb_x_policy_len * 8 - sizeof(struct sadb_x_policy); + + while (len > 0 && i < XFRM_MAX_DEPTH) { + ret = ipsecrequests_to_migrate(rq, len, &m[i]); + if (ret < 0) { + err = ret; + goto out; + } else { + rq = (struct sadb_x_ipsecrequest *)((u8 *)rq + ret); + len -= ret; + i++; + } + } + + if (!i || len > 0) { + err = -EINVAL; + goto out; + } + + return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i); + + out: + return err; +} +#else +static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, + struct sadb_msg *hdr, void **ext_hdrs) +{ + return -ENOPROTOOPT; +} +#endif + + static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { unsigned int dir; @@ -2473,6 +2663,7 @@ static pfkey_handler pfkey_funcs[SADB_MAX + 1] = { [SADB_X_SPDFLUSH] = pfkey_spdflush, [SADB_X_SPDSETIDX] = pfkey_spdadd, [SADB_X_SPDDELETE2] = pfkey_spdget, + [SADB_X_MIGRATE] = pfkey_migrate, }; static int pfkey_process(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr) @@ -3118,6 +3309,236 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); } +#ifdef CONFIG_NET_KEY_MIGRATE +static int set_sadb_address(struct sk_buff *skb, int sasize, int type, + struct xfrm_selector *sel) +{ + struct sadb_address *addr; + struct sockaddr_in *sin; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct sockaddr_in6 *sin6; +#endif + addr = (struct sadb_address *)skb_put(skb, sizeof(struct sadb_address) + sasize); + addr->sadb_address_len = (sizeof(struct sadb_address) + sasize)/8; + addr->sadb_address_exttype = type; + addr->sadb_address_proto = sel->proto; + addr->sadb_address_reserved = 0; + + switch (type) { + case SADB_EXT_ADDRESS_SRC: + if (sel->family == AF_INET) { + addr->sadb_address_prefixlen = sel->prefixlen_s; + sin = (struct sockaddr_in *)(addr + 1); + sin->sin_family = AF_INET; + memcpy(&sin->sin_addr.s_addr, &sel->saddr, + sizeof(sin->sin_addr.s_addr)); + sin->sin_port = 0; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (sel->family == AF_INET6) { + addr->sadb_address_prefixlen = sel->prefixlen_s; + sin6 = (struct sockaddr_in6 *)(addr + 1); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + sin6->sin6_flowinfo = 0; + sin6->sin6_scope_id = 0; + memcpy(&sin6->sin6_addr.s6_addr, &sel->saddr, + sizeof(sin6->sin6_addr.s6_addr)); + } +#endif + break; + case SADB_EXT_ADDRESS_DST: + if (sel->family == AF_INET) { + addr->sadb_address_prefixlen = sel->prefixlen_d; + sin = (struct sockaddr_in *)(addr + 1); + sin->sin_family = AF_INET; + memcpy(&sin->sin_addr.s_addr, &sel->daddr, + sizeof(sin->sin_addr.s_addr)); + sin->sin_port = 0; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (sel->family == AF_INET6) { + addr->sadb_address_prefixlen = sel->prefixlen_d; + sin6 = (struct sockaddr_in6 *)(addr + 1); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + sin6->sin6_flowinfo = 0; + sin6->sin6_scope_id = 0; + memcpy(&sin6->sin6_addr.s6_addr, &sel->daddr, + sizeof(sin6->sin6_addr.s6_addr)); + } +#endif + break; + default: + return -EINVAL; + } + + return 0; +} + +static int set_ipsecrequest(struct sk_buff *skb, + uint8_t proto, uint8_t mode, int level, + uint32_t reqid, uint8_t family, + xfrm_address_t *src, xfrm_address_t *dst) +{ + struct sadb_x_ipsecrequest *rq; + struct sockaddr_in *sin; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct sockaddr_in6 *sin6; +#endif + int size_req; + + size_req = sizeof(struct sadb_x_ipsecrequest) + + pfkey_sockaddr_pair_size(family); + + rq = (struct sadb_x_ipsecrequest *)skb_put(skb, size_req); + memset(rq, 0, size_req); + rq->sadb_x_ipsecrequest_len = size_req; + rq->sadb_x_ipsecrequest_proto = proto; + rq->sadb_x_ipsecrequest_mode = mode; + rq->sadb_x_ipsecrequest_level = level; + rq->sadb_x_ipsecrequest_reqid = reqid; + + switch (family) { + case AF_INET: + sin = (struct sockaddr_in *)(rq + 1); + sin->sin_family = AF_INET; + memcpy(&sin->sin_addr.s_addr, src, + sizeof(sin->sin_addr.s_addr)); + sin++; + sin->sin_family = AF_INET; + memcpy(&sin->sin_addr.s_addr, dst, + sizeof(sin->sin_addr.s_addr)); + break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case AF_INET6: + sin6 = (struct sockaddr_in6 *)(rq + 1); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + sin6->sin6_flowinfo = 0; + sin6->sin6_scope_id = 0; + memcpy(&sin6->sin6_addr.s6_addr, src, + sizeof(sin6->sin6_addr.s6_addr)); + sin6++; + sin6->sin6_family = AF_INET6; + sin6->sin6_port = 0; + sin6->sin6_flowinfo = 0; + sin6->sin6_scope_id = 0; + memcpy(&sin6->sin6_addr.s6_addr, dst, + sizeof(sin6->sin6_addr.s6_addr)); + break; +#endif + default: + return -EINVAL; + } + + return 0; +} +#endif + +#ifdef CONFIG_NET_KEY_MIGRATE +static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, + struct xfrm_migrate *m, int num_bundles) +{ + int i; + int sasize_sel; + int size = 0; + int size_pol = 0; + struct sk_buff *skb; + struct sadb_msg *hdr; + struct sadb_x_policy *pol; + struct xfrm_migrate *mp; + + if (type != XFRM_POLICY_TYPE_MAIN) + return 0; + + if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH) + return -EINVAL; + + /* selector */ + sasize_sel = pfkey_sockaddr_size(sel->family); + if (!sasize_sel) + return -EINVAL; + size += (sizeof(struct sadb_address) + sasize_sel) * 2; + + /* policy info */ + size_pol += sizeof(struct sadb_x_policy); + + /* ipsecrequests */ + for (i = 0, mp = m; i < num_bundles; i++, mp++) { + /* old locator pair */ + size_pol += sizeof(struct sadb_x_ipsecrequest) + + pfkey_sockaddr_pair_size(mp->old_family); + /* new locator pair */ + size_pol += sizeof(struct sadb_x_ipsecrequest) + + pfkey_sockaddr_pair_size(mp->new_family); + } + + size += sizeof(struct sadb_msg) + size_pol; + + /* alloc buffer */ + skb = alloc_skb(size, GFP_ATOMIC); + if (skb == NULL) + return -ENOMEM; + + hdr = (struct sadb_msg *)skb_put(skb, sizeof(struct sadb_msg)); + hdr->sadb_msg_version = PF_KEY_V2; + hdr->sadb_msg_type = SADB_X_MIGRATE; + hdr->sadb_msg_satype = pfkey_proto2satype(m->proto); + hdr->sadb_msg_len = size / 8; + hdr->sadb_msg_errno = 0; + hdr->sadb_msg_reserved = 0; + hdr->sadb_msg_seq = 0; + hdr->sadb_msg_pid = 0; + + /* selector src */ + set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel); + + /* selector dst */ + set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_DST, sel); + + /* policy information */ + pol = (struct sadb_x_policy *)skb_put(skb, sizeof(struct sadb_x_policy)); + pol->sadb_x_policy_len = size_pol / 8; + pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; + pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; + pol->sadb_x_policy_dir = dir + 1; + pol->sadb_x_policy_id = 0; + pol->sadb_x_policy_priority = 0; + + for (i = 0, mp = m; i < num_bundles; i++, mp++) { + /* old ipsecrequest */ + if (set_ipsecrequest(skb, mp->proto, mp->mode + 1, + (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), + mp->reqid, mp->old_family, + &mp->old_saddr, &mp->old_daddr) < 0) { + return -EINVAL; + } + + /* new ipsecrequest */ + if (set_ipsecrequest(skb, mp->proto, mp->mode + 1, + (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), + mp->reqid, mp->new_family, + &mp->new_saddr, &mp->new_daddr) < 0) { + return -EINVAL; + } + } + + /* broadcast migrate message to sockets */ + pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); + + return 0; +} +#else +static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, + struct xfrm_migrate *m, int num_bundles) +{ + return -ENOPROTOOPT; +} +#endif + static int pfkey_sendmsg(struct kiocb *kiocb, struct socket *sock, struct msghdr *msg, size_t len) { @@ -3287,6 +3708,7 @@ static struct xfrm_mgr pfkeyv2_mgr = .compile_policy = pfkey_compile_policy, .new_mapping = pfkey_send_new_mapping, .notify_policy = pfkey_send_policy_notify, + .migrate = pfkey_send_migrate, }; static void __exit ipsec_pfkey_exit(void) -- cgit v1.2.3 From 39e21c0d34fe769d06839679fa920217359a58b0 Mon Sep 17 00:00:00 2001 From: Andrew Hendry Date: Thu, 8 Feb 2007 13:34:36 -0800 Subject: [X.25]: Adds /proc/sys/net/x25/x25_forward to control forwarding. echo "1" > /proc/sys/net/x25/x25_forward To turn on x25_forwarding, defaults to off Requires the previous patch. Signed-off-by: Andrew Hendry Signed-off-by: David S. Miller --- include/linux/sysctl.h | 3 ++- include/net/x25.h | 1 + net/x25/af_x25.c | 4 +++- net/x25/sysctl_net_x25.c | 8 ++++++++ 4 files changed, 14 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 81480e613467..665412c4f4b9 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -699,7 +699,8 @@ enum { NET_X25_CALL_REQUEST_TIMEOUT=2, NET_X25_RESET_REQUEST_TIMEOUT=3, NET_X25_CLEAR_REQUEST_TIMEOUT=4, - NET_X25_ACK_HOLD_BACK_TIMEOUT=5 + NET_X25_ACK_HOLD_BACK_TIMEOUT=5, + NET_X25_FORWARD=6 }; /* /proc/sys/net/token-ring */ diff --git a/include/net/x25.h b/include/net/x25.h index 3b1190514d92..fc3f03d976f8 100644 --- a/include/net/x25.h +++ b/include/net/x25.h @@ -180,6 +180,7 @@ extern int sysctl_x25_call_request_timeout; extern int sysctl_x25_reset_request_timeout; extern int sysctl_x25_clear_request_timeout; extern int sysctl_x25_ack_holdback_timeout; +extern int sysctl_x25_forward; extern int x25_addr_ntoa(unsigned char *, struct x25_address *, struct x25_address *); diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 0872025821c5..b37d894358ec 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -63,6 +63,7 @@ int sysctl_x25_call_request_timeout = X25_DEFAULT_T21; int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22; int sysctl_x25_clear_request_timeout = X25_DEFAULT_T23; int sysctl_x25_ack_holdback_timeout = X25_DEFAULT_T2; +int sysctl_x25_forward = 0; HLIST_HEAD(x25_list); DEFINE_RWLOCK(x25_list_lock); @@ -884,7 +885,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, */ if (sk == NULL) { skb_push(skb, addr_len + X25_STD_MIN_LEN); - if (x25_forward_call(&dest_addr, nb, skb, lci) > 0) + if (sysctl_x25_forward && + x25_forward_call(&dest_addr, nb, skb, lci) > 0) { /* Call was forwarded, dont process it any more */ kfree_skb(skb); diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c index aabda59c824e..2b2e7fd689f3 100644 --- a/net/x25/sysctl_net_x25.c +++ b/net/x25/sysctl_net_x25.c @@ -73,6 +73,14 @@ static struct ctl_table x25_table[] = { .extra1 = &min_timer, .extra2 = &max_timer, }, + { + .ctl_name = NET_X25_FORWARD, + .procname = "x25_forward", + .data = &sysctl_x25_forward, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, { 0, }, }; -- cgit v1.2.3 From eac3731bd04c7131478722a3c148b78774553116 Mon Sep 17 00:00:00 2001 From: Jennifer Hunt Date: Thu, 8 Feb 2007 13:51:54 -0800 Subject: [S390]: Add AF_IUCV socket support From: Jennifer Hunt This patch adds AF_IUCV socket support. Signed-off-by: Frank Pavlic Signed-off-by: Martin Schwidefsky Signed-off-by: David S. Miller --- arch/s390/defconfig | 1 + include/linux/net.h | 2 +- include/linux/socket.h | 4 +- include/net/iucv/af_iucv.h | 106 +++++ net/iucv/Kconfig | 8 + net/iucv/Makefile | 1 + net/iucv/af_iucv.c | 1077 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1197 insertions(+), 2 deletions(-) create mode 100644 include/net/iucv/af_iucv.h create mode 100644 net/iucv/af_iucv.c (limited to 'include/linux') diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 46f2d4578e6b..1406400bf3ea 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -180,6 +180,7 @@ CONFIG_XFRM=y # CONFIG_XFRM_SUB_POLICY is not set CONFIG_NET_KEY=y CONFIG_IUCV=m +CONFIG_AFIUCV=m CONFIG_INET=y CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set diff --git a/include/linux/net.h b/include/linux/net.h index f28d8a2e2c91..4db21e63d8d2 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -24,7 +24,7 @@ struct poll_table_struct; struct inode; -#define NPROTO 32 /* should be enough for now.. */ +#define NPROTO 33 /* should be enough for now.. */ #define SYS_SOCKET 1 /* sys_socket(2) */ #define SYS_BIND 2 /* sys_bind(2) */ diff --git a/include/linux/socket.h b/include/linux/socket.h index 92cd38efad7f..fcd35a210e7f 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -187,7 +187,8 @@ struct ucred { #define AF_LLC 26 /* Linux LLC */ #define AF_TIPC 30 /* TIPC sockets */ #define AF_BLUETOOTH 31 /* Bluetooth sockets */ -#define AF_MAX 32 /* For now.. */ +#define AF_IUCV 32 /* IUCV sockets */ +#define AF_MAX 33 /* For now.. */ /* Protocol families, same as address families. */ #define PF_UNSPEC AF_UNSPEC @@ -220,6 +221,7 @@ struct ucred { #define PF_LLC AF_LLC #define PF_TIPC AF_TIPC #define PF_BLUETOOTH AF_BLUETOOTH +#define PF_IUCV AF_IUCV #define PF_MAX AF_MAX /* Maximum queue length specifiable by listen. */ diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h new file mode 100644 index 000000000000..04d1abb72d25 --- /dev/null +++ b/include/net/iucv/af_iucv.h @@ -0,0 +1,106 @@ +/* + * Copyright 2006 IBM Corporation + * IUCV protocol stack for Linux on zSeries + * Version 1.0 + * Author(s): Jennifer Hunt + * + */ + +#ifndef __AFIUCV_H +#define __AFIUCV_H + +#include +#include +#include +#include +#include + +#ifndef AF_IUCV +#define AF_IUCV 32 +#define PF_IUCV AF_IUCV +#endif + +/* Connection and socket states */ +enum { + IUCV_CONNECTED = 1, + IUCV_OPEN, + IUCV_BOUND, + IUCV_LISTEN, + IUCV_SEVERED, + IUCV_DISCONN, + IUCV_CLOSED +}; + +#define IUCV_QUEUELEN_DEFAULT 65535 +#define IUCV_CONN_TIMEOUT (HZ * 40) +#define IUCV_DISCONN_TIMEOUT (HZ * 2) +#define IUCV_CONN_IDLE_TIMEOUT (HZ * 60) +#define IUCV_BUFSIZE_DEFAULT 32768 + +/* IUCV socket address */ +struct sockaddr_iucv { + sa_family_t siucv_family; + unsigned short siucv_port; /* Reserved */ + unsigned int siucv_addr; /* Reserved */ + char siucv_nodeid[8]; /* Reserved */ + char siucv_user_id[8]; /* Guest User Id */ + char siucv_name[8]; /* Application Name */ +}; + + +/* Common socket structures and functions */ + +#define iucv_sk(__sk) ((struct iucv_sock *) __sk) + +struct iucv_sock { + struct sock sk; + char src_user_id[8]; + char src_name[8]; + char dst_user_id[8]; + char dst_name[8]; + struct list_head accept_q; + struct sock *parent; + struct iucv_path *path; + struct sk_buff_head send_skb_q; + unsigned int send_tag; +}; + +struct iucv_sock_list { + struct hlist_head head; + rwlock_t lock; + 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_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, + 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, + unsigned long timeo); +int iucv_sock_wait_cnt(struct sock *sk, unsigned long timeo); +void iucv_accept_enqueue(struct sock *parent, struct sock *sk); +void iucv_accept_unlink(struct sock *sk); +struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock); + +#endif /* __IUCV_H */ diff --git a/net/iucv/Kconfig b/net/iucv/Kconfig index 45ecf0b62d52..f8fcc3d10327 100644 --- a/net/iucv/Kconfig +++ b/net/iucv/Kconfig @@ -5,3 +5,11 @@ config IUCV Select this option if you want to use inter-user communication under VM or VIF sockets. If you run on z/VM, say "Y" to enable a fast communication link between VM guests. + +config AFIUCV + tristate "AF_IUCV support (VM only)" + depends on IUCV + help + Select this option if you want to use inter-user communication under + VM or VIF sockets. If you run on z/VM, say "Y" to enable a fast + communication link between VM guests. diff --git a/net/iucv/Makefile b/net/iucv/Makefile index 875941720d6a..7bfdc8532675 100644 --- a/net/iucv/Makefile +++ b/net/iucv/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_IUCV) += iucv.o +obj-$(CONFIG_AFIUCV) += af_iucv.o diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c new file mode 100644 index 000000000000..acc94214bde6 --- /dev/null +++ b/net/iucv/af_iucv.c @@ -0,0 +1,1077 @@ +/* + * linux/net/iucv/af_iucv.c + * + * IUCV protocol stack for Linux on zSeries + * + * Copyright 2006 IBM Corporation + * + * Author(s): Jennifer Hunt + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define CONFIG_IUCV_SOCK_DEBUG 1 + +#define IPRMDATA 0x80 +#define VERSION "1.0" + +static char iucv_userid[80]; + +static struct proto_ops iucv_sock_ops; + +static struct proto iucv_proto = { + .name = "AF_IUCV", + .owner = THIS_MODULE, + .obj_size = sizeof(struct iucv_sock), +}; + +/* 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 *); +static void iucv_callback_connack(struct iucv_path *, u8 ipuser[16]); +static int iucv_callback_connreq(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]); +static void iucv_callback_connrej(struct iucv_path *, u8 ipuser[16]); + +static struct iucv_sock_list iucv_sk_list = { + .lock = RW_LOCK_UNLOCKED, + .autobind_name = ATOMIC_INIT(0) +}; + +static struct iucv_handler af_iucv_handler = { + .path_pending = iucv_callback_connreq, + .path_complete = iucv_callback_connack, + .path_severed = iucv_callback_connrej, + .message_pending = iucv_callback_rx, + .message_complete = iucv_callback_txdone +}; + +static inline void high_nmcpy(unsigned char *dst, char *src) +{ + memcpy(dst, src, 8); +} + +static inline void low_nmcpy(unsigned char *dst, char *src) +{ + memcpy(&dst[8], src, 8); +} + +/* Timers */ +static void iucv_sock_timeout(unsigned long arg) +{ + struct sock *sk = (struct sock *)arg; + + bh_lock_sock(sk); + sk->sk_err = ETIMEDOUT; + sk->sk_state_change(sk); + bh_unlock_sock(sk); + + iucv_sock_kill(sk); + sock_put(sk); +} + +static void iucv_sock_clear_timer(struct sock *sk) +{ + sk_stop_timer(sk, &sk->sk_timer); +} + +static void iucv_sock_init_timer(struct sock *sk) +{ + init_timer(&sk->sk_timer); + sk->sk_timer.function = iucv_sock_timeout; + sk->sk_timer.data = (unsigned long)sk; +} + +static struct sock *__iucv_get_sock_by_name(char *nm) +{ + struct sock *sk; + struct hlist_node *node; + + sk_for_each(sk, node, &iucv_sk_list.head) + if (!memcmp(&iucv_sk(sk)->src_name, nm, 8)) + return sk; + + return NULL; +} + +static void iucv_sock_destruct(struct sock *sk) +{ + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); +} + +/* Cleanup Listen */ +static void iucv_sock_cleanup_listen(struct sock *parent) +{ + struct sock *sk; + + /* Close non-accepted connections */ + while ((sk = iucv_accept_dequeue(parent, NULL))) { + iucv_sock_close(sk); + iucv_sock_kill(sk); + } + + parent->sk_state = IUCV_CLOSED; + sock_set_flag(parent, SOCK_ZAPPED); +} + +/* Kill socket */ +static void iucv_sock_kill(struct sock *sk) +{ + if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket) + return; + + iucv_sock_unlink(&iucv_sk_list, sk); + sock_set_flag(sk, SOCK_DEAD); + sock_put(sk); +} + +/* Close an IUCV socket */ +static void iucv_sock_close(struct sock *sk) +{ + unsigned char user_data[16]; + struct iucv_sock *iucv = iucv_sk(sk); + int err; + + iucv_sock_clear_timer(sk); + lock_sock(sk); + + switch(sk->sk_state) { + case IUCV_LISTEN: + iucv_sock_cleanup_listen(sk); + break; + + case IUCV_CONNECTED: + case IUCV_DISCONN: + err = 0; + if (iucv->path) { + low_nmcpy(user_data, iucv->src_name); + high_nmcpy(user_data, iucv->dst_name); + ASCEBC(user_data, sizeof(user_data)); + err = iucv_path_sever(iucv->path, user_data); + iucv_path_free(iucv->path); + iucv->path = NULL; + } + + sk->sk_state = IUCV_CLOSED; + sk->sk_state_change(sk); + sk->sk_err = ECONNRESET; + sk->sk_state_change(sk); + + skb_queue_purge(&iucv->send_skb_q); + + sock_set_flag(sk, SOCK_ZAPPED); + break; + + default: + sock_set_flag(sk, SOCK_ZAPPED); + break; + }; + + release_sock(sk); + iucv_sock_kill(sk); +} + +static void iucv_sock_init(struct sock *sk, struct sock *parent) +{ + if (parent) + sk->sk_type = parent->sk_type; +} + +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); + if (!sk) + return NULL; + + sock_init_data(sock, sk); + INIT_LIST_HEAD(&iucv_sk(sk)->accept_q); + skb_queue_head_init(&iucv_sk(sk)->send_skb_q); + iucv_sk(sk)->send_tag = 0; + + sk->sk_destruct = iucv_sock_destruct; + sk->sk_sndtimeo = IUCV_CONN_TIMEOUT; + sk->sk_allocation = GFP_DMA; + + sock_reset_flag(sk, SOCK_ZAPPED); + + sk->sk_protocol = proto; + sk->sk_state = IUCV_OPEN; + + iucv_sock_init_timer(sk); + + iucv_sock_link(&iucv_sk_list, sk); + return sk; +} + +/* Create an IUCV socket */ +static int iucv_sock_create(struct socket *sock, int protocol) +{ + struct sock *sk; + + if (sock->type != SOCK_STREAM) + return -ESOCKTNOSUPPORT; + + sock->state = SS_UNCONNECTED; + sock->ops = &iucv_sock_ops; + + sk = iucv_sock_alloc(sock, protocol, GFP_KERNEL); + if (!sk) + return -ENOMEM; + + iucv_sock_init(sk, NULL); + + return 0; +} + +void iucv_sock_link(struct iucv_sock_list *l, struct sock *sk) +{ + write_lock_bh(&l->lock); + sk_add_node(sk, &l->head); + write_unlock_bh(&l->lock); +} + +void iucv_sock_unlink(struct iucv_sock_list *l, struct sock *sk) +{ + write_lock_bh(&l->lock); + sk_del_node_init(sk); + write_unlock_bh(&l->lock); +} + +void iucv_accept_enqueue(struct sock *parent, struct sock *sk) +{ + sock_hold(sk); + list_add_tail(&iucv_sk(sk)->accept_q, &iucv_sk(parent)->accept_q); + iucv_sk(sk)->parent = parent; + parent->sk_ack_backlog++; +} + +void iucv_accept_unlink(struct sock *sk) +{ + list_del_init(&iucv_sk(sk)->accept_q); + iucv_sk(sk)->parent->sk_ack_backlog--; + iucv_sk(sk)->parent = NULL; + sock_put(sk); +} + +struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock) +{ + struct iucv_sock *isk, *n; + struct sock *sk; + + list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q){ + sk = (struct sock *) isk; + lock_sock(sk); + + if (sk->sk_state == IUCV_CLOSED) { + release_sock(sk); + iucv_accept_unlink(sk); + continue; + } + + if (sk->sk_state == IUCV_CONNECTED || + sk->sk_state == IUCV_SEVERED || + !newsock) { + iucv_accept_unlink(sk); + if (newsock) + sock_graft(sk, newsock); + + if (sk->sk_state == IUCV_SEVERED) + sk->sk_state = IUCV_DISCONN; + + release_sock(sk); + return sk; + } + + release_sock(sk); + } + return NULL; +} + +int iucv_sock_wait_state(struct sock *sk, int state, int state2, + unsigned long timeo) +{ + DECLARE_WAITQUEUE(wait, current); + int err = 0; + + add_wait_queue(sk->sk_sleep, &wait); + while (sk->sk_state != state && sk->sk_state != state2) { + set_current_state(TASK_INTERRUPTIBLE); + + if (!timeo) { + err = -EAGAIN; + break; + } + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + + err = sock_error(sk); + if (err) + break; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sk_sleep, &wait); + return err; +} + +/* Bind an unbound socket */ +static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr, + int addr_len) +{ + struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr; + struct sock *sk = sock->sk; + struct iucv_sock *iucv; + int err; + + /* Verify the input sockaddr */ + if (!addr || addr->sa_family != AF_IUCV) + return -EINVAL; + + lock_sock(sk); + if (sk->sk_state != IUCV_OPEN) { + err = -EBADFD; + goto done; + } + + write_lock_bh(&iucv_sk_list.lock); + + iucv = iucv_sk(sk); + if (__iucv_get_sock_by_name(sa->siucv_name)) { + err = -EADDRINUSE; + goto done_unlock; + } + if (iucv->path) { + err = 0; + goto done_unlock; + } + + /* Bind the socket */ + memcpy(iucv->src_name, sa->siucv_name, 8); + + /* Copy the user id */ + memcpy(iucv->src_user_id, iucv_userid, 8); + sk->sk_state = IUCV_BOUND; + err = 0; + +done_unlock: + /* Release the socket list lock */ + write_unlock_bh(&iucv_sk_list.lock); +done: + release_sock(sk); + return err; +} + +/* Automatically bind an unbound socket */ +static int iucv_sock_autobind(struct sock *sk) +{ + struct iucv_sock *iucv = iucv_sk(sk); + char query_buffer[80]; + char name[12]; + int err = 0; + + /* Set the userid and name */ + cpcmd("QUERY USERID", query_buffer, sizeof(query_buffer), &err); + if (unlikely(err)) + return -EPROTO; + + memcpy(iucv->src_user_id, query_buffer, 8); + + write_lock_bh(&iucv_sk_list.lock); + + sprintf(name, "%08x", atomic_inc_return(&iucv_sk_list.autobind_name)); + while (__iucv_get_sock_by_name(name)) { + sprintf(name, "%08x", + atomic_inc_return(&iucv_sk_list.autobind_name)); + } + + write_unlock_bh(&iucv_sk_list.lock); + + memcpy(&iucv->src_name, name, 8); + + return err; +} + +/* Connect an unconnected socket */ +static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, + int alen, int flags) +{ + struct sockaddr_iucv *sa = (struct sockaddr_iucv *) addr; + struct sock *sk = sock->sk; + struct iucv_sock *iucv; + unsigned char user_data[16]; + int err; + + if (addr->sa_family != AF_IUCV || alen < sizeof(struct sockaddr_iucv)) + return -EINVAL; + + if (sk->sk_state != IUCV_OPEN && sk->sk_state != IUCV_BOUND) + return -EBADFD; + + if (sk->sk_type != SOCK_STREAM) + return -EINVAL; + + iucv = iucv_sk(sk); + + if (sk->sk_state == IUCV_OPEN) { + err = iucv_sock_autobind(sk); + if (unlikely(err)) + return err; + } + + lock_sock(sk); + + /* Set the destination information */ + memcpy(iucv_sk(sk)->dst_user_id, sa->siucv_user_id, 8); + memcpy(iucv_sk(sk)->dst_name, sa->siucv_name, 8); + + high_nmcpy(user_data, sa->siucv_name); + low_nmcpy(user_data, iucv_sk(sk)->src_name); + ASCEBC(user_data, sizeof(user_data)); + + iucv = iucv_sk(sk); + /* Create path. */ + iucv->path = iucv_path_alloc(IUCV_QUEUELEN_DEFAULT, + IPRMDATA, GFP_KERNEL); + err = iucv_path_connect(iucv->path, &af_iucv_handler, + sa->siucv_user_id, NULL, user_data, sk); + if (err) { + iucv_path_free(iucv->path); + iucv->path = NULL; + err = -ECONNREFUSED; + goto done; + } + + if (sk->sk_state != IUCV_CONNECTED) { + err = iucv_sock_wait_state(sk, IUCV_CONNECTED, IUCV_DISCONN, + sock_sndtimeo(sk, flags & O_NONBLOCK)); + } + + if (sk->sk_state == IUCV_DISCONN) { + release_sock(sk); + return -ECONNREFUSED; + } +done: + release_sock(sk); + return err; +} + +/* Move a socket into listening state. */ +static int iucv_sock_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + int err; + + lock_sock(sk); + + err = -EINVAL; + if (sk->sk_state != IUCV_BOUND || sock->type != SOCK_STREAM) + goto done; + + sk->sk_max_ack_backlog = backlog; + sk->sk_ack_backlog = 0; + sk->sk_state = IUCV_LISTEN; + err = 0; + +done: + release_sock(sk); + return err; +} + +/* Accept a pending connection */ +static int iucv_sock_accept(struct socket *sock, struct socket *newsock, + int flags) +{ + DECLARE_WAITQUEUE(wait, current); + struct sock *sk = sock->sk, *nsk; + long timeo; + int err = 0; + + lock_sock(sk); + + if (sk->sk_state != IUCV_LISTEN) { + err = -EBADFD; + goto done; + } + + timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); + + /* Wait for an incoming connection */ + add_wait_queue_exclusive(sk->sk_sleep, &wait); + while (!(nsk = iucv_accept_dequeue(sk, newsock))){ + set_current_state(TASK_INTERRUPTIBLE); + if (!timeo) { + err = -EAGAIN; + break; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + + if (sk->sk_state != IUCV_LISTEN) { + err = -EBADFD; + break; + } + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sk_sleep, &wait); + + if (err) + goto done; + + newsock->state = SS_CONNECTED; + +done: + release_sock(sk); + return err; +} + +static int iucv_sock_getname(struct socket *sock, struct sockaddr *addr, + int *len, int peer) +{ + struct sockaddr_iucv *siucv = (struct sockaddr_iucv *) addr; + struct sock *sk = sock->sk; + + addr->sa_family = AF_IUCV; + *len = sizeof(struct sockaddr_iucv); + + if (peer) { + memcpy(siucv->siucv_user_id, iucv_sk(sk)->dst_user_id, 8); + memcpy(siucv->siucv_name, &iucv_sk(sk)->dst_name, 8); + } else { + memcpy(siucv->siucv_user_id, iucv_sk(sk)->src_user_id, 8); + memcpy(siucv->siucv_name, iucv_sk(sk)->src_name, 8); + } + memset(&siucv->siucv_port, 0, sizeof(siucv->siucv_port)); + memset(&siucv->siucv_addr, 0, sizeof(siucv->siucv_addr)); + memset(siucv->siucv_nodeid, 0, sizeof(siucv->siucv_nodeid)); + + return 0; +} + +static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len) +{ + struct sock *sk = sock->sk; + struct iucv_sock *iucv = iucv_sk(sk); + struct sk_buff *skb; + struct iucv_message txmsg; + int err; + + err = sock_error(sk); + if (err) + return err; + + if (msg->msg_flags & MSG_OOB) + return -EOPNOTSUPP; + + lock_sock(sk); + + if (sk->sk_shutdown & SEND_SHUTDOWN) { + err = -EPIPE; + goto out; + } + + if (sk->sk_state == IUCV_CONNECTED){ + if(!(skb = sock_alloc_send_skb(sk, len, + msg->msg_flags & MSG_DONTWAIT, + &err))) + return err; + + if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)){ + err = -EFAULT; + goto fail; + } + + txmsg.class = 0; + txmsg.tag = iucv->send_tag++; + memcpy(skb->cb, &txmsg.tag, 4); + skb_queue_tail(&iucv->send_skb_q, skb); + err = iucv_message_send(iucv->path, &txmsg, 0, 0, + (void *) skb->data, skb->len); + if (err) { + if (err == 3) + printk(KERN_ERR "AF_IUCV msg limit exceeded\n"); + skb_unlink(skb, &iucv->send_skb_q); + err = -EPIPE; + goto fail; + } + + } else { + err = -ENOTCONN; + goto out; + } + + release_sock(sk); + return len; + +fail: + kfree_skb(skb); +out: + release_sock(sk); + return err; +} + +static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t len, int flags) +{ + int noblock = flags & MSG_DONTWAIT; + struct sock *sk = sock->sk; + int target, copied = 0; + struct sk_buff *skb; + int err = 0; + + if (flags & (MSG_OOB)) + return -EOPNOTSUPP; + + target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); + + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) { + if (sk->sk_shutdown & RCV_SHUTDOWN) + return 0; + return err; + } + + copied = min_t(unsigned int, skb->len, len); + + if (memcpy_toiovec(msg->msg_iov, skb->data, copied)) { + skb_queue_head(&sk->sk_receive_queue, skb); + if (copied == 0) + return -EFAULT; + } + + len -= copied; + + /* Mark read part of skb as used */ + if (!(flags & MSG_PEEK)) { + skb_pull(skb, copied); + + if (skb->len) { + skb_queue_head(&sk->sk_receive_queue, skb); + goto done; + } + + kfree_skb(skb); + } else + skb_queue_head(&sk->sk_receive_queue, skb); + +done: + return err ? : copied; +} + +static inline unsigned int iucv_accept_poll(struct sock *parent) +{ + struct iucv_sock *isk, *n; + struct sock *sk; + + list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q){ + sk = (struct sock *) isk; + + if (sk->sk_state == IUCV_CONNECTED) + return POLLIN | POLLRDNORM; + } + + return 0; +} + +unsigned int iucv_sock_poll(struct file *file, struct socket *sock, + poll_table *wait) +{ + struct sock *sk = sock->sk; + unsigned int mask = 0; + + poll_wait(file, sk->sk_sleep, wait); + + if (sk->sk_state == IUCV_LISTEN) + return iucv_accept_poll(sk); + + if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) + mask |= POLLERR; + + if (sk->sk_shutdown & RCV_SHUTDOWN) + mask |= POLLRDHUP; + + if (sk->sk_shutdown == SHUTDOWN_MASK) + mask |= POLLHUP; + + if (!skb_queue_empty(&sk->sk_receive_queue) || + (sk->sk_shutdown & RCV_SHUTDOWN)) + mask |= POLLIN | POLLRDNORM; + + if (sk->sk_state == IUCV_CLOSED) + mask |= POLLHUP; + + if (sock_writeable(sk)) + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + else + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + + return mask; +} + +static int iucv_sock_shutdown(struct socket *sock, int how) +{ + struct sock *sk = sock->sk; + struct iucv_sock *iucv = iucv_sk(sk); + struct iucv_message txmsg; + int err = 0; + u8 prmmsg[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; + + how++; + + if ((how & ~SHUTDOWN_MASK) || !how) + return -EINVAL; + + lock_sock(sk); + switch(sk->sk_state) { + case IUCV_CLOSED: + err = -ENOTCONN; + goto fail; + + default: + sk->sk_shutdown |= how; + break; + } + + if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) { + txmsg.class = 0; + txmsg.tag = 0; + err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0, + (void *) prmmsg, 8); + if (err) { + switch(err) { + case 1: + err = -ENOTCONN; + break; + case 2: + err = -ECONNRESET; + break; + default: + err = -ENOTCONN; + break; + } + } + } + + if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) { + err = iucv_path_quiesce(iucv_sk(sk)->path, NULL); + if (err) + err = -ENOTCONN; + + skb_queue_purge(&sk->sk_receive_queue); + } + + /* Wake up anyone sleeping in poll */ + sk->sk_state_change(sk); + +fail: + release_sock(sk); + return err; +} + +static int iucv_sock_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + int err = 0; + + if (!sk) + return 0; + + iucv_sock_close(sk); + + /* Unregister with IUCV base support */ + if (iucv_sk(sk)->path) { + iucv_path_sever(iucv_sk(sk)->path, NULL); + iucv_path_free(iucv_sk(sk)->path); + iucv_sk(sk)->path = NULL; + } + + if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime){ + lock_sock(sk); + err = iucv_sock_wait_state(sk, IUCV_CLOSED, 0, + sk->sk_lingertime); + release_sock(sk); + } + + sock_orphan(sk); + iucv_sock_kill(sk); + return err; +} + +/* Callback wrappers - called from iucv base support */ +static int iucv_callback_connreq(struct iucv_path *path, + u8 ipvmid[8], u8 ipuser[16]) +{ + unsigned char user_data[16]; + unsigned char nuser_data[16]; + unsigned char src_name[8]; + struct hlist_node *node; + struct sock *sk, *nsk; + struct iucv_sock *iucv, *niucv; + int err; + + memcpy(src_name, ipuser, 8); + EBCASC(src_name, 8); + /* Find out if this path belongs to af_iucv. */ + read_lock(&iucv_sk_list.lock); + iucv = NULL; + sk_for_each(sk, node, &iucv_sk_list.head) + if (sk->sk_state == IUCV_LISTEN && + !memcmp(&iucv_sk(sk)->src_name, src_name, 8)) { + /* + * Found a listening socket with + * src_name == ipuser[0-7]. + */ + iucv = iucv_sk(sk); + break; + } + read_unlock(&iucv_sk_list.lock); + if (!iucv) + /* No socket found, not one of our paths. */ + return -EINVAL; + + bh_lock_sock(sk); + + /* Check if parent socket is listening */ + low_nmcpy(user_data, iucv->src_name); + high_nmcpy(user_data, iucv->dst_name); + ASCEBC(user_data, sizeof(user_data)); + if (sk->sk_state != IUCV_LISTEN) { + err = iucv_path_sever(path, user_data); + goto fail; + } + + /* Check for backlog size */ + if (sk_acceptq_is_full(sk)) { + err = iucv_path_sever(path, user_data); + goto fail; + } + + /* Create the new socket */ + nsk = iucv_sock_alloc(NULL, SOCK_STREAM, GFP_ATOMIC); + if (!nsk){ + err = iucv_path_sever(path, user_data); + goto fail; + } + + niucv = iucv_sk(nsk); + iucv_sock_init(nsk, sk); + + /* Set the new iucv_sock */ + memcpy(niucv->dst_name, ipuser + 8, 8); + EBCASC(niucv->dst_name, 8); + memcpy(niucv->dst_user_id, ipvmid, 8); + memcpy(niucv->src_name, iucv->src_name, 8); + memcpy(niucv->src_user_id, iucv->src_user_id, 8); + niucv->path = path; + + /* Call iucv_accept */ + high_nmcpy(nuser_data, ipuser + 8); + memcpy(nuser_data + 8, niucv->src_name, 8); + ASCEBC(nuser_data + 8, 8); + + path->msglim = IUCV_QUEUELEN_DEFAULT; + err = iucv_path_accept(path, &af_iucv_handler, nuser_data, nsk); + if (err){ + err = iucv_path_sever(path, user_data); + goto fail; + } + + iucv_accept_enqueue(sk, nsk); + + /* Wake up accept */ + nsk->sk_state = IUCV_CONNECTED; + sk->sk_data_ready(sk, 1); + err = 0; +fail: + bh_unlock_sock(sk); + return 0; +} + +static void iucv_callback_connack(struct iucv_path *path, u8 ipuser[16]) +{ + struct sock *sk = path->private; + + sk->sk_state = IUCV_CONNECTED; + sk->sk_state_change(sk); +} + +static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg) +{ + struct sock *sk = path->private; + struct sk_buff *skb; + int rc; + + if (sk->sk_shutdown & RCV_SHUTDOWN) + return; + + skb = alloc_skb(msg->length, GFP_ATOMIC | GFP_DMA); + if (!skb) { + iucv_message_reject(path, msg); + return; + } + + 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; + } + + skb->h.raw = skb->data; + skb->nh.raw = skb->data; + skb->len = msg->length; + } + + if (sock_queue_rcv_skb(sk, skb)) + kfree_skb(skb); +} + +static void iucv_callback_txdone(struct iucv_path *path, + struct iucv_message *msg) +{ + struct sock *sk = path->private; + struct sk_buff *this; + struct sk_buff_head *list = &iucv_sk(sk)->send_skb_q; + struct sk_buff *list_skb = list->next; + unsigned long flags; + + spin_lock_irqsave(&list->lock, flags); + + do { + this = list_skb; + list_skb = list_skb->next; + } while (memcmp(&msg->tag, this->cb, 4)); + + spin_unlock_irqrestore(&list->lock, flags); + + skb_unlink(this, &iucv_sk(sk)->send_skb_q); + kfree_skb(this); +} + +static void iucv_callback_connrej(struct iucv_path *path, u8 ipuser[16]) +{ + struct sock *sk = path->private; + + if (!list_empty(&iucv_sk(sk)->accept_q)) + sk->sk_state = IUCV_SEVERED; + else + sk->sk_state = IUCV_DISCONN; + + sk->sk_state_change(sk); +} + +static struct proto_ops iucv_sock_ops = { + .family = PF_IUCV, + .owner = THIS_MODULE, + .release = iucv_sock_release, + .bind = iucv_sock_bind, + .connect = iucv_sock_connect, + .listen = iucv_sock_listen, + .accept = iucv_sock_accept, + .getname = iucv_sock_getname, + .sendmsg = iucv_sock_sendmsg, + .recvmsg = iucv_sock_recvmsg, + .poll = iucv_sock_poll, + .ioctl = sock_no_ioctl, + .mmap = sock_no_mmap, + .socketpair = sock_no_socketpair, + .shutdown = iucv_sock_shutdown, + .setsockopt = sock_no_setsockopt, + .getsockopt = sock_no_getsockopt +}; + +static struct net_proto_family iucv_sock_family_ops = { + .family = AF_IUCV, + .owner = THIS_MODULE, + .create = iucv_sock_create, +}; + +static int afiucv_init(void) +{ + int err; + + if (!MACHINE_IS_VM) { + printk(KERN_ERR "AF_IUCV connection needs VM as base\n"); + err = -EPROTONOSUPPORT; + goto out; + } + cpcmd("QUERY USERID", iucv_userid, sizeof(iucv_userid), &err); + if (unlikely(err)) { + printk(KERN_ERR "AF_IUCV needs the VM userid\n"); + err = -EPROTONOSUPPORT; + goto out; + } + + err = iucv_register(&af_iucv_handler, 0); + if (err) + goto out; + err = proto_register(&iucv_proto, 0); + if (err) + goto out_iucv; + err = sock_register(&iucv_sock_family_ops); + if (err) + goto out_proto; + printk(KERN_INFO "AF_IUCV lowlevel driver initialized\n"); + return 0; + +out_proto: + proto_unregister(&iucv_proto); +out_iucv: + iucv_unregister(&af_iucv_handler, 0); +out: + return err; +} + +static void __exit afiucv_exit(void) +{ + sock_unregister(PF_IUCV); + proto_unregister(&iucv_proto); + iucv_unregister(&af_iucv_handler, 0); + + printk(KERN_INFO "AF_IUCV lowlevel driver unloaded\n"); +} + +module_init(afiucv_init); +module_exit(afiucv_exit); + +MODULE_AUTHOR("Jennifer Hunt "); +MODULE_DESCRIPTION("IUCV Sockets ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_IUCV); -- cgit v1.2.3 From 42c05f6e6e3d57495054a4cae35850b3f7d1c343 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 8 Feb 2007 16:01:09 -0800 Subject: [ATM]: atmarp.h needs to always include linux/types.h To provide the __be* types, even for userspace includes. Reported by Andrew Walrond. Signed-off-by: David S. Miller --- include/linux/atmarp.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/atmarp.h b/include/linux/atmarp.h index ee108f9e9cb7..231f4bdec730 100644 --- a/include/linux/atmarp.h +++ b/include/linux/atmarp.h @@ -6,9 +6,7 @@ #ifndef _LINUX_ATMARP_H #define _LINUX_ATMARP_H -#ifdef __KERNEL__ #include -#endif #include #include -- cgit v1.2.3 From 40e0aa64660b4e28a9348e57bfbda6c114617969 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Fri, 6 Oct 2006 18:36:07 +0200 Subject: [ALSA] ASoC codecs: WM8731 support This patch adds ASoC support for the WM8731 codec. Supported features:- o Capture/Playback/Sidetone/Bypass. o 16 & 24 bit audio. o 8k - 96k sample rates. o DAPM. Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- include/linux/i2c-id.h | 1 + sound/soc/codecs/wm8731.c | 789 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8731.h | 41 +++ 3 files changed, 831 insertions(+) create mode 100644 sound/soc/codecs/wm8731.c create mode 100644 sound/soc/codecs/wm8731.h (limited to 'include/linux') diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index d38778f2fbec..01e98c2a9618 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -115,6 +115,7 @@ #define I2C_DRIVERID_KS0127 86 /* Samsung ks0127 video decoder */ #define I2C_DRIVERID_TLV320AIC23B 87 /* TI TLV320AIC23B audio codec */ #define I2C_DRIVERID_ISL1208 88 /* Intersil ISL1208 RTC */ +#define I2C_DRIVERID_WM8731 89 /* Wolfson WM8731 audio codec */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c new file mode 100644 index 000000000000..cd0ece650f31 --- /dev/null +++ b/sound/soc/codecs/wm8731.c @@ -0,0 +1,789 @@ +/* + * wm8731.c -- WM8731 ALSA SoC Audio driver + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * Based on wm8753.c by Liam Girdwood + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8731.h" + +#define AUDIO_NAME "wm8731" +#define WM8731_VERSION "0.12" + +/* + * Debug + */ + +#define WM8731_DEBUG 0 + +#ifdef WM8731_DEBUG +#define dbg(format, arg...) \ + printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) \ + printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) + +struct snd_soc_codec_device soc_codec_dev_wm8731; + +/* + * wm8731 register cache + * We can't read the WM8731 register space when we are + * using 2 wire for device control, so we cache them instead. + * There is no point in caching the reset register + */ +static const u16 wm8731_reg[WM8731_CACHEREGNUM] = { + 0x0097, 0x0097, 0x0079, 0x0079, + 0x000a, 0x0008, 0x009f, 0x000a, + 0x0000, 0x0000 +}; + +#define WM8731_DAIFMT \ + (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_RIGHT_J | \ + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_IB_NF | \ + SND_SOC_DAIFMT_IB_IF) + +#define WM8731_DIR \ + (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) + +#define WM8731_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + +#define WM8731_HIFI_BITS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_mode wm8731_modes[] = { + /* codec frame and clock master modes */ + /* 8k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, 0, + 1536, SND_SOC_FSB(64)}, + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, 0, + 2304, SND_SOC_FSB(64)}, + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, 0, + 1408, SND_SOC_FSB(64)}, + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, 0, + 2112, SND_SOC_FSB(64)}, + + /* 32k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_32000, WM8731_DIR, 0, + 384, SND_SOC_FSB(64)}, + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_32000, WM8731_DIR, 0, + 576, SND_SOC_FSB(64)}, + + /* 44.1k & 48k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + WM8731_DIR, 0, 256, SND_SOC_FSB(64)}, + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + WM8731_DIR, 0, 384, SND_SOC_FSB(64)}, + + /* 88.2 & 96k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + WM8731_DIR, 0, 128, SND_SOC_FSB(64)}, + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + WM8731_DIR, 0, 192, SND_SOC_FSB(64)}, + + + /* USB codec frame and clock master modes */ + /* 8k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_8000, WM8731_DIR, + SND_SOC_DAI_BFS_DIV, 1500, SND_SOC_FSBD(1)}, + + /* 44.1k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_44100, WM8731_DIR, + SND_SOC_DAI_BFS_DIV, 272, SND_SOC_FSBD(1)}, + + /* 48k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_48000, WM8731_DIR, + SND_SOC_DAI_BFS_DIV, 250, SND_SOC_FSBD(1)}, + + /* 88.2k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_88200, WM8731_DIR, + SND_SOC_DAI_BFS_DIV, 136, SND_SOC_FSBD(1)}, + + /* 96k */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, SNDRV_PCM_RATE_96000, WM8731_DIR, + SND_SOC_DAI_BFS_DIV, 125, SND_SOC_FSBD(1)}, + + /* codec frame and clock slave modes */ + {WM8731_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + WM8731_HIFI_BITS, WM8731_RATES, WM8731_DIR, SND_SOC_DAI_BFS_DIV, + SND_SOC_FS_ALL, SND_SOC_FSBD_ALL}, +}; + +/* + * read wm8731 register cache + */ +static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg == WM8731_RESET) + return 0; + if (reg >= WM8731_CACHEREGNUM) + return -1; + return cache[reg]; +} + +/* + * write wm8731 register cache + */ +static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg >= WM8731_CACHEREGNUM) + return; + cache[reg] = value; +} + +/* + * write to the WM8731 register space + */ +static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8731 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8731_write_reg_cache (codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8731_reset(c) wm8731_write(c, WM8731_RESET, 0) + +static const char *wm8731_input_select[] = {"Line In", "Mic"}; +static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; + +static const struct soc_enum wm8731_enum[] = { + SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select), + SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph), +}; + +static const struct snd_kcontrol_new wm8731_snd_controls[] = { + +SOC_DOUBLE_R("Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V, 0, 127, 0), +SOC_DOUBLE_R("Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V, 7, 1, 0), + +SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0), +SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1), + +SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0), +SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1), + +SOC_SINGLE("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1), + +SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1), +SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0), + +SOC_ENUM("Playback De-emphasis", wm8731_enum[1]), +}; + +/* add non dapm controls */ +static int wm8731_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) { + if ((err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8731_snd_controls[i],codec, NULL))) < 0) + return err; + } + + return 0; +} + +/* Output Mixer */ +static const struct snd_kcontrol_new wm8731_output_mixer_controls[] = { +SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0), +SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0), +SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0), +}; + +/* Input mux */ +static const struct snd_kcontrol_new wm8731_input_mux_controls = +SOC_DAPM_ENUM("Input Select", wm8731_enum[0]); + +static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { +SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, + &wm8731_output_mixer_controls[0], + ARRAY_SIZE(wm8731_output_mixer_controls)), +SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM8731_PWR, 3, 1), +SND_SOC_DAPM_OUTPUT("LOUT"), +SND_SOC_DAPM_OUTPUT("LHPOUT"), +SND_SOC_DAPM_OUTPUT("ROUT"), +SND_SOC_DAPM_OUTPUT("RHPOUT"), +SND_SOC_DAPM_ADC("ADC", "HiFi Capture", WM8731_PWR, 2, 1), +SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &wm8731_input_mux_controls), +SND_SOC_DAPM_PGA("Line Input", WM8731_PWR, 0, 1, NULL, 0), +SND_SOC_DAPM_MICBIAS("Mic Bias", WM8731_PWR, 1, 1), +SND_SOC_DAPM_INPUT("MICIN"), +SND_SOC_DAPM_INPUT("RLINEIN"), +SND_SOC_DAPM_INPUT("LLINEIN"), +}; + +static const char *intercon[][3] = { + /* output mixer */ + {"Output Mixer", "Line Bypass Switch", "Line Input"}, + {"Output Mixer", "HiFi Playback Switch", "DAC"}, + {"Output Mixer", "Mic Sidetone Switch", "Mic Bias"}, + + /* outputs */ + {"RHPOUT", NULL, "Output Mixer"}, + {"ROUT", NULL, "Output Mixer"}, + {"LHPOUT", NULL, "Output Mixer"}, + {"LOUT", NULL, "Output Mixer"}, + + /* input mux */ + {"Input Mux", "Line In", "Line Input"}, + {"Input Mux", "Mic", "Mic Bias"}, + {"ADC", NULL, "Input Mux"}, + + /* inputs */ + {"Line Input", NULL, "LLINEIN"}, + {"Line Input", NULL, "RLINEIN"}, + {"Mic Bias", NULL, "MICIN"}, + + /* terminator */ + {NULL, NULL, NULL}, +}; + +static int wm8731_add_widgets(struct snd_soc_codec *codec) +{ + int i; + + for(i = 0; i < ARRAY_SIZE(wm8731_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &wm8731_dapm_widgets[i]); + } + + /* set up audio path interconnects */ + for(i = 0; intercon[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, intercon[i][0], + intercon[i][1], intercon[i][2]); + } + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +struct _coeff_div { + u32 mclk; + u32 rate; + u16 fs; + u8 sr:4; + u8 bosr:1; + u8 usb:1; +}; + +/* codec mclk clock divider coefficients */ +static const struct _coeff_div coeff_div[] = { + /* 48k */ + {12288000, 48000, 256, 0x0, 0x0, 0x0}, + {18432000, 48000, 384, 0x0, 0x1, 0x0}, + {12000000, 48000, 250, 0x0, 0x0, 0x1}, + + /* 32k */ + {12288000, 32000, 384, 0x6, 0x0, 0x0}, + {18432000, 32000, 576, 0x6, 0x1, 0x0}, + + /* 8k */ + {12288000, 8000, 1536, 0x3, 0x0, 0x0}, + {18432000, 8000, 2304, 0x3, 0x1, 0x0}, + {11289600, 8000, 1408, 0xb, 0x0, 0x0}, + {16934400, 8000, 2112, 0xb, 0x1, 0x0}, + {12000000, 8000, 1500, 0x3, 0x0, 0x1}, + + /* 96k */ + {12288000, 96000, 128, 0x7, 0x0, 0x0}, + {18432000, 96000, 192, 0x7, 0x1, 0x0}, + {12000000, 96000, 125, 0x7, 0x0, 0x1}, + + /* 44.1k */ + {11289600, 44100, 256, 0x8, 0x0, 0x0}, + {16934400, 44100, 384, 0x8, 0x1, 0x0}, + {12000000, 44100, 272, 0x8, 0x1, 0x1}, + + /* 88.2k */ + {11289600, 88200, 128, 0xf, 0x0, 0x0}, + {16934400, 88200, 192, 0xf, 0x1, 0x0}, + {12000000, 88200, 136, 0xf, 0x1, 0x1}, +}; + +static inline int get_coeff(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { + if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) + return i; + } + return 0; +} + +/* WM8731 supports numerous clocks per sample rate */ +static unsigned int wm8731_config_sysclk(struct snd_soc_codec_dai *dai, + struct snd_soc_clock_info *info, unsigned int clk) +{ + dai->mclk = 0; + + /* check that the calculated FS and rate actually match a clock from + * the machine driver */ + if (info->fs * info->rate == clk) + dai->mclk = clk; + + return dai->mclk; +} + +static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + u16 iface = 0, srate; + int i = get_coeff(rtd->codec_dai->mclk, + snd_soc_get_rate(rtd->codec_dai->dai_runtime.pcmrate)); + + /* set master/slave audio interface */ + switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + iface |= 0x0040; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + } + srate = (coeff_div[i].sr << 2) | + (coeff_div[i].bosr << 1) | coeff_div[i].usb; + wm8731_write(codec, WM8731_SRATE, srate); + + /* interface format */ + switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 0x0002; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x0001; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x0003; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x0013; + break; + } + + /* bit size */ + switch (rtd->codec_dai->dai_runtime.pcmfmt) { + case SNDRV_PCM_FMTBIT_S16_LE: + break; + case SNDRV_PCM_FMTBIT_S20_3LE: + iface |= 0x0004; + break; + case SNDRV_PCM_FMTBIT_S24_LE: + iface |= 0x0008; + break; + case SNDRV_PCM_FMTBIT_S32_LE: + iface |= 0x000c; + break; + } + + /* clock inversion */ + switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x0090; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x0080; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= 0x0010; + break; + } + + /* set iface */ + wm8731_write(codec, WM8731_IFACE, iface); + + /* set active */ + wm8731_write(codec, WM8731_ACTIVE, 0x0001); + return 0; +} + +static void wm8731_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + + /* deactivate */ + if (!codec->active) { + udelay(50); + wm8731_write(codec, WM8731_ACTIVE, 0x0); + } +} + +static int wm8731_mute(struct snd_soc_codec *codec, + struct snd_soc_codec_dai *dai, int mute) +{ + u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; + if (mute) + wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8); + else + wm8731_write(codec, WM8731_APDIGI, mute_reg); + return 0; +} + +static int wm8731_dapm_event(struct snd_soc_codec *codec, int event) +{ + u16 reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; + + switch (event) { + case SNDRV_CTL_POWER_D0: /* full On */ + /* vref/mid, osc on, dac unmute */ + wm8731_write(codec, WM8731_PWR, reg); + break; + case SNDRV_CTL_POWER_D1: /* partial On */ + case SNDRV_CTL_POWER_D2: /* partial On */ + break; + case SNDRV_CTL_POWER_D3hot: /* Off, with power */ + /* everything off except vref/vmid, */ + wm8731_write(codec, WM8731_PWR, reg | 0x0040); + break; + case SNDRV_CTL_POWER_D3cold: /* Off, without power */ + /* everything off, dac mute, inactive */ + wm8731_write(codec, WM8731_ACTIVE, 0x0); + wm8731_write(codec, WM8731_PWR, 0xffff); + break; + } + codec->dapm_state = event; + return 0; +} + +struct snd_soc_codec_dai wm8731_dai = { + .name = "WM8731", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + }, + .config_sysclk = wm8731_config_sysclk, + .digital_mute = wm8731_mute, + .ops = { + .prepare = wm8731_pcm_prepare, + .shutdown = wm8731_shutdown, + }, + .caps = { + .num_modes = ARRAY_SIZE(wm8731_modes), + .mode = wm8731_modes, + }, +}; +EXPORT_SYMBOL_GPL(wm8731_dai); + +static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + wm8731_write(codec, WM8731_ACTIVE, 0x0); + wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); + return 0; +} + +static int wm8731_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + int i; + u8 data[2]; + u16 *cache = codec->reg_cache; + + /* Sync reg_cache with the hardware */ + for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) { + data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); + data[1] = cache[i] & 0x00ff; + codec->hw_write(codec->control_data, data, 2); + } + wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); + wm8731_dapm_event(codec, codec->suspend_dapm_state); + return 0; +} + +/* + * initialise the WM8731 driver + * register the mixer and dsp interfaces with the kernel + */ +static int wm8731_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; + int reg, ret = 0; + + codec->name = "WM8731"; + codec->owner = THIS_MODULE; + codec->read = wm8731_read_reg_cache; + codec->write = wm8731_write; + codec->dapm_event = wm8731_dapm_event; + codec->dai = &wm8731_dai; + codec->num_dai = 1; + codec->reg_cache_size = ARRAY_SIZE(wm8731_reg); + + codec->reg_cache = + kzalloc(sizeof(u16) * ARRAY_SIZE(wm8731_reg), GFP_KERNEL); + if (codec->reg_cache == NULL) + return -ENOMEM; + memcpy(codec->reg_cache, + wm8731_reg, sizeof(u16) * ARRAY_SIZE(wm8731_reg)); + codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(wm8731_reg); + + wm8731_reset(codec); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + kfree(codec->reg_cache); + return ret; + } + + /* power on device */ + wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3hot); + + /* set the update bits */ + reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); + wm8731_write(codec, WM8731_LOUT1V, reg | 0x0100); + reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); + wm8731_write(codec, WM8731_ROUT1V, reg | 0x0100); + reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); + wm8731_write(codec, WM8731_LINVOL, reg | 0x0100); + reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); + wm8731_write(codec, WM8731_RINVOL, reg | 0x0100); + + wm8731_add_controls(codec); + wm8731_add_widgets(codec); + ret = snd_soc_register_card(socdev); + if (ret < 0) { + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + } + + return ret; +} + +static struct snd_soc_device *wm8731_socdev; + +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + +/* + * WM8731 2 wire address is determined by GPIO5 + * state during powerup. + * low = 0x1a + * high = 0x1b + */ +static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; + +/* Magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; + +static struct i2c_driver wm8731_i2c_driver; +static struct i2c_client client_template; + +/* If the i2c layer weren't so broken, we could pass this kind of data + around */ + +static int wm8731_codec_probe(struct i2c_adapter *adap, int addr, int kind) +{ + struct snd_soc_device *socdev = wm8731_socdev; + struct wm8731_setup_data *setup = socdev->codec_data; + struct snd_soc_codec *codec = socdev->codec; + struct i2c_client *i2c; + int ret; + + if (addr != setup->i2c_address) + return -ENODEV; + + client_template.adapter = adap; + client_template.addr = addr; + + i2c = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (i2c == NULL) { + kfree(codec); + return -ENOMEM; + } + memcpy(i2c, &client_template, sizeof(struct i2c_client)); + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + + ret = i2c_attach_client(i2c); + if (ret < 0) { + err("failed to attach codec at addr %x\n", addr); + goto err; + } + + ret = wm8731_init(socdev); + if (ret < 0) { + err("failed to initialise WM8731\n"); + goto err; + } + return ret; + +err: + kfree(codec); + kfree(i2c); + return ret; +} + +static int wm8731_i2c_detach(struct i2c_client *client) +{ + struct snd_soc_codec* codec = i2c_get_clientdata(client); + i2c_detach_client(client); + kfree(codec->reg_cache); + kfree(client); + return 0; +} + +static int wm8731_i2c_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, wm8731_codec_probe); +} + +/* corgi i2c codec control layer */ +static struct i2c_driver wm8731_i2c_driver = { + .driver = { + .name = "WM8731 I2C Codec", + .owner = THIS_MODULE, + }, + .id = I2C_DRIVERID_WM8731, + .attach_adapter = wm8731_i2c_attach, + .detach_client = wm8731_i2c_detach, + .command = NULL, +}; + +static struct i2c_client client_template = { + .name = "WM8731", + .driver = &wm8731_i2c_driver, +}; +#endif + +static int wm8731_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct wm8731_setup_data *setup; + struct snd_soc_codec *codec; + int ret = 0; + + info("WM8731 Audio Codec %s", WM8731_VERSION); + + setup = socdev->codec_data; + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + socdev->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + wm8731_socdev = socdev; +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + if (setup->i2c_address) { + normal_i2c[0] = setup->i2c_address; + codec->hw_write = (hw_write_t)i2c_master_send; + ret = i2c_add_driver(&wm8731_i2c_driver); + if (ret != 0) + printk(KERN_ERR "can't add i2c driver"); + } +#else + /* Add other interfaces here */ +#endif + return ret; +} + +/* power down chip */ +static int wm8731_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + if (codec->control_data) + wm8731_dapm_event(codec, SNDRV_CTL_POWER_D3cold); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + i2c_del_driver(&wm8731_i2c_driver); +#endif + kfree(codec); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8731 = { + .probe = wm8731_probe, + .remove = wm8731_remove, + .suspend = wm8731_suspend, + .resume = wm8731_resume, +}; + +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); + +MODULE_DESCRIPTION("ASoC WM8731 driver"); +MODULE_AUTHOR("Richard Purdie"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h new file mode 100644 index 000000000000..8fa0f53bef1c --- /dev/null +++ b/sound/soc/codecs/wm8731.h @@ -0,0 +1,41 @@ +/* + * wm8731.h -- WM8731 Soc Audio driver + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * Based on wm8753.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _WM8731_H +#define _WM8731_H + +/* WM8731 register space */ + +#define WM8731_LINVOL 0x00 +#define WM8731_RINVOL 0x01 +#define WM8731_LOUT1V 0x02 +#define WM8731_ROUT1V 0x03 +#define WM8731_APANA 0x04 +#define WM8731_APDIGI 0x05 +#define WM8731_PWR 0x06 +#define WM8731_IFACE 0x07 +#define WM8731_SRATE 0x08 +#define WM8731_ACTIVE 0x09 +#define WM8731_RESET 0x0f + +#define WM8731_CACHEREGNUM 10 + +struct wm8731_setup_data { + unsigned short i2c_address; +}; + +extern struct snd_soc_codec_dai wm8731_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8731; + +#endif -- cgit v1.2.3 From abadfc928a27e1cf27c834e8e29e6b1f64ca2d55 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Fri, 6 Oct 2006 18:36:39 +0200 Subject: [ALSA] ASoC codecs: WM8750 support This patch adds ASoC support for the WM8750 codec. Supported features:- o Capture/Playback/Sidetone/Bypass. o 16 & 24 bit audio. o 8k - 96k sample rates. o DAPM. Signed-off-by: Richard Purdie Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai Signed-off-by: Jaroslav Kysela --- include/linux/i2c-id.h | 1 + sound/soc/codecs/wm8750.c | 1131 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8750.h | 66 +++ 3 files changed, 1198 insertions(+) create mode 100644 sound/soc/codecs/wm8750.c create mode 100644 sound/soc/codecs/wm8750.h (limited to 'include/linux') diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 01e98c2a9618..6e7ec4c76178 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -116,6 +116,7 @@ #define I2C_DRIVERID_TLV320AIC23B 87 /* TI TLV320AIC23B audio codec */ #define I2C_DRIVERID_ISL1208 88 /* Intersil ISL1208 RTC */ #define I2C_DRIVERID_WM8731 89 /* Wolfson WM8731 audio codec */ +#define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c new file mode 100644 index 000000000000..6a8b2799b3b1 --- /dev/null +++ b/sound/soc/codecs/wm8750.c @@ -0,0 +1,1131 @@ +/* + * wm8750.c -- WM8750 ALSA SoC audio driver + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * Based on WM8753.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8750.h" + +#define AUDIO_NAME "WM8750" +#define WM8750_VERSION "0.11" + +/* + * Debug + */ + +#define WM8750_DEBUG 0 + +#ifdef WM8750_DEBUG +#define dbg(format, arg...) \ + printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) do {} while (0) +#endif +#define err(format, arg...) \ + printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) + +static struct workqueue_struct *wm8750_workq = NULL; +static struct work_struct wm8750_dapm_work; + +/* + * wm8750 register cache + * We can't read the WM8750 register space when we + * are using 2 wire for device control, so we cache them instead. + */ +static const u16 wm8750_reg[] = { + 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ + 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ + 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ + 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ + 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ + 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ + 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ + 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ + 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ + 0x0079, 0x0079, 0x0079, /* 40 */ +}; + +#define WM8750_HIFI_DAIFMT \ + (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_RIGHT_J | \ + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_IB_NF | \ + SND_SOC_DAIFMT_IB_IF) + +#define WM8750_DIR \ + (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) + +#define WM8750_HIFI_FSB \ + (SND_SOC_FSBD(1) | SND_SOC_FSBD(2) | SND_SOC_FSBD(4) | \ + SND_SOC_FSBD(8) | SND_SOC_FSBD(16)) + +#define WM8750_HIFI_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + +#define WM8750_HIFI_BITS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_mode wm8750_modes[] = { + /* common codec frame and clock master modes */ + /* 8k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1536, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1408, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 2304, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 2112, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_8000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1500, WM8750_HIFI_FSB}, + + /* 11.025k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_11025, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1024, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_11025, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1536, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_11025, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1088, WM8750_HIFI_FSB}, + + /* 16k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 768, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 1152, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 750, WM8750_HIFI_FSB}, + + /* 22.05k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_22050, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 512, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_22050, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 768, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_22050, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 544, WM8750_HIFI_FSB}, + + /* 32k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 384, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 576, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_16000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 375, WM8750_HIFI_FSB}, + + /* 44.1k & 48k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000, WM8750_DIR, SND_SOC_DAI_BFS_DIV, 256, + WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000, WM8750_DIR, SND_SOC_DAI_BFS_DIV, 384, + WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_44100, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 272, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_48000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 250, WM8750_HIFI_FSB}, + + /* 88.2k & 96k */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, WM8750_DIR, SND_SOC_DAI_BFS_DIV, 128, + WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, WM8750_DIR, SND_SOC_DAI_BFS_DIV, 192, + WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_88200, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 136, WM8750_HIFI_FSB}, + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAITDM_LRDW(0,0), WM8750_HIFI_BITS, SNDRV_PCM_RATE_96000, + WM8750_DIR, SND_SOC_DAI_BFS_DIV, 125, WM8750_HIFI_FSB}, + + /* codec frame and clock slave modes */ + {WM8750_HIFI_DAIFMT | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAITDM_LRDW(0,0), + WM8750_HIFI_BITS, WM8750_HIFI_RATES, WM8750_DIR, + SND_SOC_DAI_BFS_DIV, SND_SOC_FS_ALL, SND_SOC_FSBD_ALL}, +}; + +/* + * read wm8750 register cache + */ +static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg > WM8750_CACHE_REGNUM) + return -1; + return cache[reg]; +} + +/* + * write wm8750 register cache + */ +static inline void wm8750_write_reg_cache(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg > WM8750_CACHE_REGNUM) + return; + cache[reg] = value; +} + +static int wm8750_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8753 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8750_write_reg_cache (codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8750_reset(c) wm8750_write(c, WM8750_RESET, 0) + +/* + * WM8750 Controls + */ +static const char *wm8750_bass[] = {"Linear Control", "Adaptive Boost"}; +static const char *wm8750_bass_filter[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" }; +static const char *wm8750_treble[] = {"8kHz", "4kHz"}; +static const char *wm8750_3d_lc[] = {"200Hz", "500Hz"}; +static const char *wm8750_3d_uc[] = {"2.2kHz", "1.5kHz"}; +static const char *wm8750_3d_func[] = {"Capture", "Playback"}; +static const char *wm8750_alc_func[] = {"Off", "Right", "Left", "Stereo"}; +static const char *wm8750_ng_type[] = {"Constant PGA Gain", + "Mute ADC Output"}; +static const char *wm8750_line_mux[] = {"Line 1", "Line 2", "Line 3", "PGA", + "Differential"}; +static const char *wm8750_pga_sel[] = {"Line 1", "Line 2", "Line 3", + "Differential"}; +static const char *wm8750_out3[] = {"VREF", "ROUT1 + Vol", "MonoOut", + "ROUT1"}; +static const char *wm8750_diff_sel[] = {"Line 1", "Line 2"}; +static const char *wm8750_adcpol[] = {"Normal", "L Invert", "R Invert", + "L + R Invert"}; +static const char *wm8750_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; +static const char *wm8750_mono_mux[] = {"Stereo", "Mono (Left)", + "Mono (Right)", "Digital Mono"}; + +static const struct soc_enum wm8750_enum[] = { +SOC_ENUM_SINGLE(WM8750_BASS, 7, 2, wm8750_bass), +SOC_ENUM_SINGLE(WM8750_BASS, 6, 2, wm8750_bass_filter), +SOC_ENUM_SINGLE(WM8750_TREBLE, 6, 2, wm8750_treble), +SOC_ENUM_SINGLE(WM8750_3D, 5, 2, wm8750_3d_lc), +SOC_ENUM_SINGLE(WM8750_3D, 6, 2, wm8750_3d_uc), +SOC_ENUM_SINGLE(WM8750_3D, 7, 2, wm8750_3d_func), +SOC_ENUM_SINGLE(WM8750_ALC1, 7, 4, wm8750_alc_func), +SOC_ENUM_SINGLE(WM8750_NGATE, 1, 2, wm8750_ng_type), +SOC_ENUM_SINGLE(WM8750_LOUTM1, 0, 5, wm8750_line_mux), +SOC_ENUM_SINGLE(WM8750_ROUTM1, 0, 5, wm8750_line_mux), +SOC_ENUM_SINGLE(WM8750_LADCIN, 6, 4, wm8750_pga_sel), /* 10 */ +SOC_ENUM_SINGLE(WM8750_RADCIN, 6, 4, wm8750_pga_sel), +SOC_ENUM_SINGLE(WM8750_ADCTL2, 7, 4, wm8750_out3), +SOC_ENUM_SINGLE(WM8750_ADCIN, 8, 2, wm8750_diff_sel), +SOC_ENUM_SINGLE(WM8750_ADCDAC, 5, 4, wm8750_adcpol), +SOC_ENUM_SINGLE(WM8750_ADCDAC, 1, 4, wm8750_deemph), +SOC_ENUM_SINGLE(WM8750_ADCIN, 6, 4, wm8750_mono_mux), /* 16 */ + +}; + +static const struct snd_kcontrol_new wm8750_snd_controls[] = { + +SOC_DOUBLE_R("Capture Volume", WM8750_LINVOL, WM8750_RINVOL, 0, 63, 0), +SOC_DOUBLE_R("Capture ZC Switch", WM8750_LINVOL, WM8750_RINVOL, 6, 1, 0), +SOC_DOUBLE_R("Capture Switch", WM8750_LINVOL, WM8750_RINVOL, 7, 1, 1), + +SOC_DOUBLE_R("Out1 Playback ZC Switch", WM8750_LOUT1V, + WM8750_ROUT1V, 7, 1, 0), +SOC_DOUBLE_R("Out2 Playback ZC Switch", WM8750_LOUT2V, + WM8750_ROUT2V, 7, 1, 0), + +SOC_ENUM("Playback De-emphasis", wm8750_enum[15]), + +SOC_ENUM("Capture Polarity", wm8750_enum[14]), +SOC_SINGLE("Playback 6dB Attenuate", WM8750_ADCDAC, 7, 1, 0), +SOC_SINGLE("Capture 6dB Attenuate", WM8750_ADCDAC, 8, 1, 0), + +SOC_DOUBLE_R("PCM Volume", WM8750_LDAC, WM8750_RDAC, 0, 255, 0), + +SOC_ENUM("Bass Boost", wm8750_enum[0]), +SOC_ENUM("Bass Filter", wm8750_enum[1]), +SOC_SINGLE("Bass Volume", WM8750_BASS, 0, 15, 1), + +SOC_SINGLE("Treble Volume", WM8750_TREBLE, 0, 15, 0), +SOC_ENUM("Treble Cut-off", wm8750_enum[2]), + +SOC_SINGLE("3D Switch", WM8750_3D, 0, 1, 0), +SOC_SINGLE("3D Volume", WM8750_3D, 1, 15, 0), +SOC_ENUM("3D Lower Cut-off", wm8750_enum[3]), +SOC_ENUM("3D Upper Cut-off", wm8750_enum[4]), +SOC_ENUM("3D Mode", wm8750_enum[5]), + +SOC_SINGLE("ALC Capture Target Volume", WM8750_ALC1, 0, 7, 0), +SOC_SINGLE("ALC Capture Max Volume", WM8750_ALC1, 4, 7, 0), +SOC_ENUM("ALC Capture Function", wm8750_enum[6]), +SOC_SINGLE("ALC Capture ZC Switch", WM8750_ALC2, 7, 1, 0), +SOC_SINGLE("ALC Capture Hold Time", WM8750_ALC2, 0, 15, 0), +SOC_SINGLE("ALC Capture Decay Time", WM8750_ALC3, 4, 15, 0), +SOC_SINGLE("ALC Capture Attack Time", WM8750_ALC3, 0, 15, 0), +SOC_SINGLE("ALC Capture NG Threshold", WM8750_NGATE, 3, 31, 0), +SOC_ENUM("ALC Capture NG Type", wm8750_enum[4]), +SOC_SINGLE("ALC Capture NG Switch", WM8750_NGATE, 0, 1, 0), + +SOC_SINGLE("Left ADC Capture Volume", WM8750_LADC, 0, 255, 0), +SOC_SINGLE("Right ADC Capture Volume", WM8750_RADC, 0, 255, 0), + +SOC_SINGLE("ZC Timeout Switch", WM8750_ADCTL1, 0, 1, 0), +SOC_SINGLE("Playback Invert Switch", WM8750_ADCTL1, 1, 1, 0), + +SOC_SINGLE("Right Out2 Playback Invert Switch", WM8750_ADCTL2, 4, 1, 0), + +/* Unimplemented */ +/* ADCDAC Bit 0 - ADCHPD */ +/* ADCDAC Bit 4 - HPOR */ +/* ADCTL1 Bit 2,3 - DATSEL */ +/* ADCTL1 Bit 4,5 - DMONOMIX */ +/* ADCTL1 Bit 6,7 - VSEL */ +/* ADCTL2 Bit 2 - LRCM */ +/* ADCTL2 Bit 3 - TRI */ +/* ADCTL3 Bit 5 - HPFLREN */ +/* ADCTL3 Bit 6 - VROI */ +/* ADCTL3 Bit 7,8 - ADCLRM */ +/* ADCIN Bit 4 - LDCM */ +/* ADCIN Bit 5 - RDCM */ + +SOC_DOUBLE_R("Mic Boost", WM8750_LADCIN, WM8750_RADCIN, 4, 3, 0), + +SOC_DOUBLE_R("Bypass Left Playback Volume", WM8750_LOUTM1, + WM8750_LOUTM2, 4, 7, 1), +SOC_DOUBLE_R("Bypass Right Playback Volume", WM8750_ROUTM1, + WM8750_ROUTM2, 4, 7, 1), +SOC_DOUBLE_R("Bypass Mono Playback Volume", WM8750_MOUTM1, + WM8750_MOUTM2, 4, 7, 1), + +SOC_SINGLE("Mono Playback ZC Switch", WM8750_MOUTV, 7, 1, 0), + +SOC_DOUBLE_R("Out1 Playback Volume", WM8750_LOUT1V, WM8750_ROUT1V, 0, 127, 0), +SOC_DOUBLE_R("Out2 Playback Volume", WM8750_LOUT2V, WM8750_ROUT2V, 0, 127, 0), + +SOC_SINGLE("Mono Playback Volume", WM8750_MOUTV, 0, 127, 0), + +}; + +/* add non dapm controls */ +static int wm8750_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(wm8750_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8750_snd_controls[i],codec, NULL)); + if (err < 0) + return err; + } + return 0; +} + +/* + * DAPM Controls + */ + +/* Left Mixer */ +static const struct snd_kcontrol_new wm8750_left_mixer_controls[] = { +SOC_DAPM_SINGLE("Playback Switch", WM8750_LOUTM1, 8, 1, 0), +SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_LOUTM1, 7, 1, 0), +SOC_DAPM_SINGLE("Right Playback Switch", WM8750_LOUTM2, 8, 1, 0), +SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_LOUTM2, 7, 1, 0), +}; + +/* Right Mixer */ +static const struct snd_kcontrol_new wm8750_right_mixer_controls[] = { +SOC_DAPM_SINGLE("Left Playback Switch", WM8750_ROUTM1, 8, 1, 0), +SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_ROUTM1, 7, 1, 0), +SOC_DAPM_SINGLE("Playback Switch", WM8750_ROUTM2, 8, 1, 0), +SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_ROUTM2, 7, 1, 0), +}; + +/* Mono Mixer */ +static const struct snd_kcontrol_new wm8750_mono_mixer_controls[] = { +SOC_DAPM_SINGLE("Left Playback Switch", WM8750_MOUTM1, 8, 1, 0), +SOC_DAPM_SINGLE("Left Bypass Switch", WM8750_MOUTM1, 7, 1, 0), +SOC_DAPM_SINGLE("Right Playback Switch", WM8750_MOUTM2, 8, 1, 0), +SOC_DAPM_SINGLE("Right Bypass Switch", WM8750_MOUTM2, 7, 1, 0), +}; + +/* Left Line Mux */ +static const struct snd_kcontrol_new wm8750_left_line_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[8]); + +/* Right Line Mux */ +static const struct snd_kcontrol_new wm8750_right_line_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[9]); + +/* Left PGA Mux */ +static const struct snd_kcontrol_new wm8750_left_pga_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[10]); + +/* Right PGA Mux */ +static const struct snd_kcontrol_new wm8750_right_pga_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[11]); + +/* Out 3 Mux */ +static const struct snd_kcontrol_new wm8750_out3_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[12]); + +/* Differential Mux */ +static const struct snd_kcontrol_new wm8750_diffmux_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[13]); + +/* Mono ADC Mux */ +static const struct snd_kcontrol_new wm8750_monomux_controls = +SOC_DAPM_ENUM("Route", wm8750_enum[16]); + +static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { + SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, + &wm8750_left_mixer_controls[0], + ARRAY_SIZE(wm8750_left_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, + &wm8750_right_mixer_controls[0], + ARRAY_SIZE(wm8750_right_mixer_controls)), + SND_SOC_DAPM_MIXER("Mono Mixer", WM8750_PWR2, 2, 0, + &wm8750_mono_mixer_controls[0], + ARRAY_SIZE(wm8750_mono_mixer_controls)), + + SND_SOC_DAPM_PGA("Right Out 2", WM8750_PWR2, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 2", WM8750_PWR2, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 1", WM8750_PWR2, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 1", WM8750_PWR2, 6, 0, NULL, 0), + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8750_PWR2, 7, 0), + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8750_PWR2, 8, 0), + + SND_SOC_DAPM_MICBIAS("Mic Bias", WM8750_PWR1, 1, 0), + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8750_PWR1, 2, 0), + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8750_PWR1, 3, 0), + + SND_SOC_DAPM_MUX("Left PGA Mux", WM8750_PWR1, 5, 0, + &wm8750_left_pga_controls), + SND_SOC_DAPM_MUX("Right PGA Mux", WM8750_PWR1, 4, 0, + &wm8750_right_pga_controls), + SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, + &wm8750_left_line_controls), + SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, + &wm8750_right_line_controls), + + SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8750_out3_controls), + SND_SOC_DAPM_PGA("Out 3", WM8750_PWR2, 1, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mono Out 1", WM8750_PWR2, 2, 0, NULL, 0), + + SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, + &wm8750_diffmux_controls), + SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, + &wm8750_monomux_controls), + SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, + &wm8750_monomux_controls), + + SND_SOC_DAPM_OUTPUT("LOUT1"), + SND_SOC_DAPM_OUTPUT("ROUT1"), + SND_SOC_DAPM_OUTPUT("LOUT2"), + SND_SOC_DAPM_OUTPUT("ROUT2"), + SND_SOC_DAPM_OUTPUT("MONO"), + SND_SOC_DAPM_OUTPUT("OUT3"), + + SND_SOC_DAPM_INPUT("LINPUT1"), + SND_SOC_DAPM_INPUT("LINPUT2"), + SND_SOC_DAPM_INPUT("LINPUT3"), + SND_SOC_DAPM_INPUT("RINPUT1"), + SND_SOC_DAPM_INPUT("RINPUT2"), + SND_SOC_DAPM_INPUT("RINPUT3"), +}; + +static const char *audio_map[][3] = { + /* left mixer */ + {"Left Mixer", "Playback Switch", "Left DAC"}, + {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, + {"Left Mixer", "Right Playback Switch", "Right DAC"}, + {"Left Mixer", "Right Bypass Switch", "Right Line Mux"}, + + /* right mixer */ + {"Right Mixer", "Left Playback Switch", "Left DAC"}, + {"Right Mixer", "Left Bypass Switch", "Left Line Mux"}, + {"Right Mixer", "Playback Switch", "Right DAC"}, + {"Right Mixer", "Right Bypass Switch", "Right Line Mux"}, + + /* left out 1 */ + {"Left Out 1", NULL, "Left Mixer"}, + {"LOUT1", NULL, "Left Out 1"}, + + /* left out 2 */ + {"Left Out 2", NULL, "Left Mixer"}, + {"LOUT2", NULL, "Left Out 2"}, + + /* right out 1 */ + {"Right Out 1", NULL, "Right Mixer"}, + {"ROUT1", NULL, "Right Out 1"}, + + /* right out 2 */ + {"Right Out 2", NULL, "Right Mixer"}, + {"ROUT2", NULL, "Right Out 2"}, + + /* mono mixer */ + {"Mono Mixer", "Left Playback Switch", "Left DAC"}, + {"Mono Mixer", "Left Bypass Switch", "Left Line Mux"}, + {"Mono Mixer", "Right Playback Switch", "Right DAC"}, + {"Mono Mixer", "Right Bypass Switch", "Right Line Mux"}, + + /* mono out */ + {"Mono Out 1", NULL, "Mono Mixer"}, + {"MONO1", NULL, "Mono Out 1"}, + + /* out 3 */ + {"Out3 Mux", "VREF", "VREF"}, + {"Out3 Mux", "ROUT1 + Vol", "ROUT1"}, + {"Out3 Mux", "ROUT1", "Right Mixer"}, + {"Out3 Mux", "MonoOut", "MONO1"}, + {"Out 3", NULL, "Out3 Mux"}, + {"OUT3", NULL, "Out 3"}, + + /* Left Line Mux */ + {"Left Line Mux", "Line 1", "LINPUT1"}, + {"Left Line Mux", "Line 2", "LINPUT2"}, + {"Left Line Mux", "Line 3", "LINPUT3"}, + {"Left Line Mux", "PGA", "Left PGA Mux"}, + {"Left Line Mux", "Differential", "Differential Mux"}, + + /* Right Line Mux */ + {"Right Line Mux", "Line 1", "RINPUT1"}, + {"Right Line Mux", "Line 2", "RINPUT2"}, + {"Right Line Mux", "Line 3", "RINPUT3"}, + {"Right Line Mux", "PGA", "Right PGA Mux"}, + {"Right Line Mux", "Differential", "Differential Mux"}, + + /* Left PGA Mux */ + {"Left PGA Mux", "Line 1", "LINPUT1"}, + {"Left PGA Mux", "Line 2", "LINPUT2"}, + {"Left PGA Mux", "Line 3", "LINPUT3"}, + {"Left PGA Mux", "Differential", "Differential Mux"}, + + /* Right PGA Mux */ + {"Right PGA Mux", "Line 1", "RINPUT1"}, + {"Right PGA Mux", "Line 2", "RINPUT2"}, + {"Right PGA Mux", "Line 3", "RINPUT3"}, + {"Right PGA Mux", "Differential", "Differential Mux"}, + + /* Differential Mux */ + {"Differential Mux", "Line 1", "LINPUT1"}, + {"Differential Mux", "Line 1", "RINPUT1"}, + {"Differential Mux", "Line 2", "LINPUT2"}, + {"Differential Mux", "Line 2", "RINPUT2"}, + + /* Left ADC Mux */ + {"Left ADC Mux", "Stereo", "Left PGA Mux"}, + {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"}, + {"Left ADC Mux", "Digital Mono", "Left PGA Mux"}, + + /* Right ADC Mux */ + {"Right ADC Mux", "Stereo", "Right PGA Mux"}, + {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, + {"Right ADC Mux", "Digital Mono", "Right PGA Mux"}, + + /* ADC */ + {"Left ADC", NULL, "Left ADC Mux"}, + {"Right ADC", NULL, "Right ADC Mux"}, + + /* terminator */ + {NULL, NULL, NULL}, +}; + +static int wm8750_add_widgets(struct snd_soc_codec *codec) +{ + int i; + + for(i = 0; i < ARRAY_SIZE(wm8750_dapm_widgets); i++) { + snd_soc_dapm_new_control(codec, &wm8750_dapm_widgets[i]); + } + + /* set up audio path audio_mapnects */ + for(i = 0; audio_map[i][0] != NULL; i++) { + snd_soc_dapm_connect_input(codec, audio_map[i][0], + audio_map[i][1], audio_map[i][2]); + } + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +struct _coeff_div { + u32 mclk; + u32 rate; + u16 fs; + u8 sr:5; + u8 usb:1; +}; + +/* codec hifi mclk clock divider coefficients */ +static const struct _coeff_div coeff_div[] = { + /* 8k */ + {12288000, 8000, 1536, 0x6, 0x0}, + {11289600, 8000, 1408, 0x16, 0x0}, + {18432000, 8000, 2304, 0x7, 0x0}, + {16934400, 8000, 2112, 0x17, 0x0}, + {12000000, 8000, 1500, 0x6, 0x1}, + + /* 11.025k */ + {11289600, 11025, 1024, 0x18, 0x0}, + {16934400, 11025, 1536, 0x19, 0x0}, + {12000000, 11025, 1088, 0x19, 0x1}, + + /* 16k */ + {12288000, 16000, 768, 0xa, 0x0}, + {18432000, 16000, 1152, 0xb, 0x0}, + {12000000, 16000, 750, 0xa, 0x1}, + + /* 22.05k */ + {11289600, 22050, 512, 0x1a, 0x0}, + {16934400, 22050, 768, 0x1b, 0x0}, + {12000000, 22050, 544, 0x1b, 0x1}, + + /* 32k */ + {12288000, 32000, 384, 0xc, 0x0}, + {18432000, 32000, 576, 0xd, 0x0}, + {12000000, 32000, 375, 0xa, 0x1}, + + /* 44.1k */ + {11289600, 44100, 256, 0x10, 0x0}, + {16934400, 44100, 384, 0x11, 0x0}, + {12000000, 44100, 272, 0x11, 0x1}, + + /* 48k */ + {12288000, 48000, 256, 0x0, 0x0}, + {18432000, 48000, 384, 0x1, 0x0}, + {12000000, 48000, 250, 0x0, 0x1}, + + /* 88.2k */ + {11289600, 88200, 128, 0x1e, 0x0}, + {16934400, 88200, 192, 0x1f, 0x0}, + {12000000, 88200, 136, 0x1f, 0x1}, + + /* 96k */ + {12288000, 96000, 128, 0xe, 0x0}, + {18432000, 96000, 192, 0xf, 0x0}, + {12000000, 96000, 125, 0xe, 0x1}, +}; + +static inline int get_coeff(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { + if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) + return i; + } + return -EINVAL; +} + +/* WM8750 supports numerous input clocks per sample rate */ +static unsigned int wm8750_config_sysclk(struct snd_soc_codec_dai *dai, + struct snd_soc_clock_info *info, unsigned int clk) +{ + dai->mclk = 0; + + /* check that the calculated FS and rate actually match a clock from + * the machine driver */ + if (info->fs * info->rate == clk) + dai->mclk = clk; + + return dai->mclk; +} + +static int wm8750_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + u16 iface = 0, bfs, srate = 0; + int i = get_coeff(rtd->codec_dai->mclk, + snd_soc_get_rate(rtd->codec_dai->dai_runtime.pcmrate)); + + /* is coefficient valid ? */ + if (i < 0) + return i; + + bfs = SND_SOC_FSB_REAL(rtd->codec_dai->dai_runtime.bfs); + + /* set master/slave audio interface */ + switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CLOCK_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + iface = 0x0040; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + } + + /* interface format */ + switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 0x0002; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x0001; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x0003; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x0013; + break; + } + + /* bit size */ + switch (rtd->codec_dai->dai_runtime.pcmfmt) { + case SNDRV_PCM_FMTBIT_S16_LE: + break; + case SNDRV_PCM_FMTBIT_S20_3LE: + iface |= 0x0004; + break; + case SNDRV_PCM_FMTBIT_S24_LE: + iface |= 0x0008; + break; + case SNDRV_PCM_FMTBIT_S32_LE: + iface |= 0x000c; + break; + } + + /* clock inversion */ + switch (rtd->codec_dai->dai_runtime.fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x0090; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x0080; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= 0x0010; + break; + } + + /* set bclk divisor rate */ + switch (bfs) { + case 1: + break; + case 4: + srate |= (0x1 << 7); + break; + case 8: + srate |= (0x2 << 7); + break; + case 16: + srate |= (0x3 << 7); + break; + } + + /* set iface & srate */ + wm8750_write(codec, WM8750_IFACE, iface); + wm8750_write(codec, WM8750_SRATE, srate | + (coeff_div[i].sr << 1) | coeff_div[i].usb); + + return 0; +} + +static int wm8750_mute(struct snd_soc_codec *codec, + struct snd_soc_codec_dai *dai, int mute) +{ + u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; + if (mute) + wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8); + else + wm8750_write(codec, WM8750_ADCDAC, mute_reg); + return 0; +} + +static int wm8750_dapm_event(struct snd_soc_codec *codec, int event) +{ + u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; + + switch (event) { + case SNDRV_CTL_POWER_D0: /* full On */ + /* set vmid to 50k and unmute dac */ + wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); + break; + case SNDRV_CTL_POWER_D1: /* partial On */ + case SNDRV_CTL_POWER_D2: /* partial On */ + /* set vmid to 5k for quick power up */ + wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); + break; + case SNDRV_CTL_POWER_D3hot: /* Off, with power */ + /* mute dac and set vmid to 500k, enable VREF */ + wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); + break; + case SNDRV_CTL_POWER_D3cold: /* Off, without power */ + wm8750_write(codec, WM8750_PWR1, 0x0001); + break; + } + codec->dapm_state = event; + return 0; +} + +struct snd_soc_codec_dai wm8750_dai = { + .name = "WM8750", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + }, + .config_sysclk = wm8750_config_sysclk, + .digital_mute = wm8750_mute, + .ops = { + .prepare = wm8750_pcm_prepare, + }, + .caps = { + .num_modes = ARRAY_SIZE(wm8750_modes), + .mode = wm8750_modes, + }, +}; +EXPORT_SYMBOL_GPL(wm8750_dai); + +static void wm8750_work(void *data) +{ + struct snd_soc_codec *codec = (struct snd_soc_codec *)data; + wm8750_dapm_event(codec, codec->dapm_state); +} + +static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); + return 0; +} + +static int wm8750_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + int i; + u8 data[2]; + u16 *cache = codec->reg_cache; + + /* Sync reg_cache with the hardware */ + for (i = 0; i < ARRAY_SIZE(wm8750_reg); i++) { + if (i == WM8750_RESET) + continue; + data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); + data[1] = cache[i] & 0x00ff; + codec->hw_write(codec->control_data, data, 2); + } + + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3hot); + + /* charge wm8750 caps */ + if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) { + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); + codec->dapm_state = SNDRV_CTL_POWER_D0; + queue_delayed_work(wm8750_workq, &wm8750_dapm_work, + msecs_to_jiffies(1000)); + } + + return 0; +} + +/* + * initialise the WM8750 driver + * register the mixer and dsp interfaces with the kernel + */ +static int wm8750_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; + int reg, ret = 0; + + codec->name = "WM8750"; + codec->owner = THIS_MODULE; + codec->read = wm8750_read_reg_cache; + codec->write = wm8750_write; + codec->dapm_event = wm8750_dapm_event; + codec->dai = &wm8750_dai; + codec->num_dai = 1; + codec->reg_cache_size = ARRAY_SIZE(wm8750_reg); + + codec->reg_cache = + kzalloc(sizeof(u16) * ARRAY_SIZE(wm8750_reg), GFP_KERNEL); + if (codec->reg_cache == NULL) + return -ENOMEM; + memcpy(codec->reg_cache, wm8750_reg, + sizeof(u16) * ARRAY_SIZE(wm8750_reg)); + codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(wm8750_reg); + + wm8750_reset(codec); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + kfree(codec->reg_cache); + return ret; + } + + /* charge output caps */ + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D2); + codec->dapm_state = SNDRV_CTL_POWER_D3hot; + queue_delayed_work(wm8750_workq, &wm8750_dapm_work, + msecs_to_jiffies(1000)); + + /* set the update bits */ + reg = wm8750_read_reg_cache(codec, WM8750_LDAC); + wm8750_write(codec, WM8750_LDAC, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_RDAC); + wm8750_write(codec, WM8750_RDAC, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_LOUT1V); + wm8750_write(codec, WM8750_LOUT1V, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_ROUT1V); + wm8750_write(codec, WM8750_ROUT1V, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_LOUT2V); + wm8750_write(codec, WM8750_LOUT2V, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_ROUT2V); + wm8750_write(codec, WM8750_ROUT2V, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_LINVOL); + wm8750_write(codec, WM8750_LINVOL, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_RINVOL); + wm8750_write(codec, WM8750_RINVOL, reg | 0x0100); + + wm8750_add_controls(codec); + wm8750_add_widgets(codec); + ret = snd_soc_register_card(socdev); + if (ret < 0) { + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + } + + return ret; +} + +/* If the i2c layer weren't so broken, we could pass this kind of data + around */ +static struct snd_soc_device *wm8750_socdev; + +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + +/* + * WM8731 2 wire address is determined by GPIO5 + * state during powerup. + * low = 0x1a + * high = 0x1b + */ +static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; + +/* Magic definition of all other variables and things */ +I2C_CLIENT_INSMOD; + +static struct i2c_driver wm8750_i2c_driver; +static struct i2c_client client_template; + +static int wm8750_codec_probe(struct i2c_adapter *adap, int addr, int kind) +{ + struct snd_soc_device *socdev = wm8750_socdev; + struct wm8750_setup_data *setup = socdev->codec_data; + struct snd_soc_codec *codec = socdev->codec; + struct i2c_client *i2c; + int ret; + + if (addr != setup->i2c_address) + return -ENODEV; + + client_template.adapter = adap; + client_template.addr = addr; + + i2c = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (i2c == NULL) { + kfree(codec); + return -ENOMEM; + } + memcpy(i2c, &client_template, sizeof(struct i2c_client)); + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + + ret = i2c_attach_client(i2c); + if (ret < 0) { + err("failed to attach codec at addr %x\n", addr); + goto err; + } + + ret = wm8750_init(socdev); + if (ret < 0) { + err("failed to initialise WM8750\n"); + goto err; + } + return ret; + +err: + kfree(codec); + kfree(i2c); + return ret; +} + +static int wm8750_i2c_detach(struct i2c_client *client) +{ + struct snd_soc_codec *codec = i2c_get_clientdata(client); + i2c_detach_client(client); + kfree(codec->reg_cache); + kfree(client); + return 0; +} + +static int wm8750_i2c_attach(struct i2c_adapter *adap) +{ + return i2c_probe(adap, &addr_data, wm8750_codec_probe); +} + +/* corgi i2c codec control layer */ +static struct i2c_driver wm8750_i2c_driver = { + .driver = { + .name = "WM8750 I2C Codec", + .owner = THIS_MODULE, + }, + .id = I2C_DRIVERID_WM8750, + .attach_adapter = wm8750_i2c_attach, + .detach_client = wm8750_i2c_detach, + .command = NULL, +}; + +static struct i2c_client client_template = { + .name = "WM8750", + .driver = &wm8750_i2c_driver, +}; +#endif + +static int wm8750_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct wm8750_setup_data *setup = socdev->codec_data; + struct snd_soc_codec *codec; + int ret = 0; + + info("WM8750 Audio Codec %s", WM8750_VERSION); + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + socdev->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + wm8750_socdev = socdev; + INIT_WORK(&wm8750_dapm_work, wm8750_work, codec); + wm8750_workq = create_workqueue("wm8750"); + if (wm8750_workq == NULL) { + kfree(codec); + return -ENOMEM; + } +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + if (setup->i2c_address) { + normal_i2c[0] = setup->i2c_address; + codec->hw_write = (hw_write_t)i2c_master_send; + ret = i2c_add_driver(&wm8750_i2c_driver); + if (ret != 0) + printk(KERN_ERR "can't add i2c driver"); + } +#else + /* Add other interfaces here */ +#endif + + return ret; +} + +/* power down chip */ +static int wm8750_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + if (codec->control_data) + wm8750_dapm_event(codec, SNDRV_CTL_POWER_D3cold); + if (wm8750_workq) + destroy_workqueue(wm8750_workq); + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) + i2c_del_driver(&wm8750_i2c_driver); +#endif + kfree(codec); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8750 = { + .probe = wm8750_probe, + .remove = wm8750_remove, + .suspend = wm8750_suspend, + .resume = wm8750_resume, +}; + +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); + +MODULE_DESCRIPTION("ASoC WM8750 driver"); +MODULE_AUTHOR("Liam Girdwood"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8750.h b/sound/soc/codecs/wm8750.h new file mode 100644 index 000000000000..ee5eea4a2d34 --- /dev/null +++ b/sound/soc/codecs/wm8750.h @@ -0,0 +1,66 @@ +/* + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * Based on WM8753.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _WM8750_H +#define _WM8750_H + +/* WM8750 register space */ + +#define WM8750_LINVOL 0x00 +#define WM8750_RINVOL 0x01 +#define WM8750_LOUT1V 0x02 +#define WM8750_ROUT1V 0x03 +#define WM8750_ADCDAC 0x05 +#define WM8750_IFACE 0x07 +#define WM8750_SRATE 0x08 +#define WM8750_LDAC 0x0a +#define WM8750_RDAC 0x0b +#define WM8750_BASS 0x0c +#define WM8750_TREBLE 0x0d +#define WM8750_RESET 0x0f +#define WM8750_3D 0x10 +#define WM8750_ALC1 0x11 +#define WM8750_ALC2 0x12 +#define WM8750_ALC3 0x13 +#define WM8750_NGATE 0x14 +#define WM8750_LADC 0x15 +#define WM8750_RADC 0x16 +#define WM8750_ADCTL1 0x17 +#define WM8750_ADCTL2 0x18 +#define WM8750_PWR1 0x19 +#define WM8750_PWR2 0x1a +#define WM8750_ADCTL3 0x1b +#define WM8750_ADCIN 0x1f +#define WM8750_LADCIN 0x20 +#define WM8750_RADCIN 0x21 +#define WM8750_LOUTM1 0x22 +#define WM8750_LOUTM2 0x23 +#define WM8750_ROUTM1 0x24 +#define WM8750_ROUTM2 0x25 +#define WM8750_MOUTM1 0x26 +#define WM8750_MOUTM2 0x27 +#define WM8750_LOUT2V 0x28 +#define WM8750_ROUT2V 0x29 +#define WM8750_MOUTV 0x2a + +#define WM8750_CACHE_REGNUM 0x2a + +struct wm8750_setup_data { + unsigned short i2c_address; + unsigned int mclk; +}; + +extern struct snd_soc_codec_dai wm8750_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8750; + +#endif -- cgit v1.2.3 From 62045305c20a194127ae87ccf963cfe6ffde7c4e Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Fri, 9 Feb 2007 05:28:19 +0100 Subject: [PATCH] mm: remove find_trylock_page Remove find_trylock_page as per the removal schedule. Signed-off-by: Nick Piggin [ Let's see if anybody screams ] Signed-off-by: Linus Torvalds --- Documentation/feature-removal-schedule.txt | 12 ------------ include/linux/pagemap.h | 2 -- mm/filemap.c | 20 -------------------- 3 files changed, 34 deletions(-) (limited to 'include/linux') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 2dc5e5da8f88..4a1d8979ed92 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -186,18 +186,6 @@ Who: Greg Kroah-Hartman --------------------------- -What: find_trylock_page -When: January 2007 -Why: The interface no longer has any callers left in the kernel. It - is an odd interface (compared with other find_*_page functions), in - that it does not take a refcount to the page, only the page lock. - It should be replaced with find_get_page or find_lock_page if possible. - This feature removal can be reevaluated if users of the interface - cannot cleanly use something else. -Who: Nick Piggin - ---------------------------- - What: Interrupt only SA_* flags When: Januar 2007 Why: The interrupt related SA_* flags are replaced by IRQF_* to move them diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index c3e255bf8594..7a8dcb82a699 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -76,8 +76,6 @@ extern struct page * find_get_page(struct address_space *mapping, unsigned long index); extern struct page * find_lock_page(struct address_space *mapping, unsigned long index); -extern __deprecated_for_modules struct page * find_trylock_page( - struct address_space *mapping, unsigned long index); extern struct page * find_or_create_page(struct address_space *mapping, unsigned long index, gfp_t gfp_mask); unsigned find_get_pages(struct address_space *mapping, pgoff_t start, diff --git a/mm/filemap.c b/mm/filemap.c index 8332c77b1bd1..f30ef28405d3 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -605,26 +605,6 @@ struct page * find_get_page(struct address_space *mapping, unsigned long offset) } EXPORT_SYMBOL(find_get_page); -/** - * find_trylock_page - find and lock a page - * @mapping: the address_space to search - * @offset: the page index - * - * Same as find_get_page(), but trylock it instead of incrementing the count. - */ -struct page *find_trylock_page(struct address_space *mapping, unsigned long offset) -{ - struct page *page; - - read_lock_irq(&mapping->tree_lock); - page = radix_tree_lookup(&mapping->page_tree, offset); - if (page && TestSetPageLocked(page)) - page = NULL; - read_unlock_irq(&mapping->tree_lock); - return page; -} -EXPORT_SYMBOL(find_trylock_page); - /** * find_lock_page - locate, pin and lock a pagecache page * @mapping: the address_space to search -- cgit v1.2.3 From b454cc6636d254fbf6049b73e9560aee76fb04a3 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 5 Feb 2007 16:28:25 -0800 Subject: [TC] MIPS: TURBOchannel update to the driver model This is a set of changes to convert support for the TURBOchannel bus to the driver model. It implements the usual set of calls similar to what other bus drivers have: tc_register_driver(), tc_unregister_driver(), etc. All the platform-specific bits have been removed and headers from asm-mips/dec/ have been merged into linux/tc.h, which should be included by drivers. Signed-off-by: Maciej W. Rozycki Signed-off-by: Andrew Morton Signed-off-by: Ralf Baechle --- MAINTAINERS | 5 + drivers/tc/Makefile | 2 +- drivers/tc/tc-driver.c | 110 +++++++++++++ drivers/tc/tc.c | 339 ++++++++++++++++------------------------ include/asm-mips/dec/tc.h | 41 ----- include/asm-mips/dec/tcinfo.h | 47 ------ include/asm-mips/dec/tcmodule.h | 39 ----- include/linux/tc.h | 141 +++++++++++++++++ 8 files changed, 396 insertions(+), 328 deletions(-) create mode 100644 drivers/tc/tc-driver.c delete mode 100644 include/asm-mips/dec/tc.h delete mode 100644 include/asm-mips/dec/tcinfo.h delete mode 100644 include/asm-mips/dec/tcmodule.h create mode 100644 include/linux/tc.h (limited to 'include/linux') diff --git a/MAINTAINERS b/MAINTAINERS index fe35f3ac4cd3..3780623cc70c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3287,6 +3287,11 @@ L: vtun@office.satix.net W: http://vtun.sourceforge.net/tun S: Maintained +TURBOCHANNEL SUBSYSTEM +P: Maciej W. Rozycki +M: macro@linux-mips.org +S: Maintained + U14-34F SCSI DRIVER P: Dario Ballabio M: ballabio_dario@emc.com diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile index 83b5bd75ce26..967342692211 100644 --- a/drivers/tc/Makefile +++ b/drivers/tc/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-$(CONFIG_TC) += tc.o +obj-$(CONFIG_TC) += tc.o tc-driver.o obj-$(CONFIG_ZS) += zs.o obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o diff --git a/drivers/tc/tc-driver.c b/drivers/tc/tc-driver.c new file mode 100644 index 000000000000..16b5bae63c74 --- /dev/null +++ b/drivers/tc/tc-driver.c @@ -0,0 +1,110 @@ +/* + * TURBOchannel driver services. + * + * Copyright (c) 2005 James Simmons + * Copyright (c) 2006 Maciej W. Rozycki + * + * Loosely based on drivers/dio/dio-driver.c and + * drivers/pci/pci-driver.c. + * + * 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 + +/** + * tc_register_driver - register a new TC driver + * @drv: the driver structure to register + * + * Adds the driver structure to the list of registered drivers + * Returns a negative value on error, otherwise 0. + * If no error occurred, the driver remains registered even if + * no device was claimed during registration. + */ +int tc_register_driver(struct tc_driver *tdrv) +{ + return driver_register(&tdrv->driver); +} +EXPORT_SYMBOL(tc_register_driver); + +/** + * tc_unregister_driver - unregister a TC driver + * @drv: the driver structure to unregister + * + * Deletes the driver structure from the list of registered TC drivers, + * gives it a chance to clean up by calling its remove() function for + * each device it was responsible for, and marks those devices as + * driverless. + */ +void tc_unregister_driver(struct tc_driver *tdrv) +{ + driver_unregister(&tdrv->driver); +} +EXPORT_SYMBOL(tc_unregister_driver); + +/** + * tc_match_device - tell if a TC device structure has a matching + * TC device ID structure + * @tdrv: the TC driver to earch for matching TC device ID strings + * @tdev: the TC device structure to match against + * + * Used by a driver to check whether a TC device present in the + * system is in its list of supported devices. Returns the matching + * tc_device_id structure or %NULL if there is no match. + */ +const struct tc_device_id *tc_match_device(struct tc_driver *tdrv, + struct tc_dev *tdev) +{ + const struct tc_device_id *id = tdrv->id_table; + + if (id) { + while (id->name[0] || id->vendor[0]) { + if (strcmp(tdev->name, id->name) == 0 && + strcmp(tdev->vendor, id->vendor) == 0) + return id; + id++; + } + } + return NULL; +} +EXPORT_SYMBOL(tc_match_device); + +/** + * tc_bus_match - Tell if a device structure has a matching + * TC device ID structure + * @dev: the device structure to match against + * @drv: the device driver to search for matching TC device ID strings + * + * Used by a driver to check whether a TC device present in the + * system is in its list of supported devices. Returns 1 if there + * is a match or 0 otherwise. + */ +static int tc_bus_match(struct device *dev, struct device_driver *drv) +{ + struct tc_dev *tdev = to_tc_dev(dev); + struct tc_driver *tdrv = to_tc_driver(drv); + const struct tc_device_id *id; + + id = tc_match_device(tdrv, tdev); + if (id) + return 1; + + return 0; +} + +struct bus_type tc_bus_type = { + .name = "tc", + .match = tc_bus_match, +}; +EXPORT_SYMBOL(tc_bus_type); + +static int __init tc_driver_init(void) +{ + return bus_register(&tc_bus_type); +} + +postcore_initcall(tc_driver_init); diff --git a/drivers/tc/tc.c b/drivers/tc/tc.c index 4a51e56f85b6..5514e5283616 100644 --- a/drivers/tc/tc.c +++ b/drivers/tc/tc.c @@ -1,254 +1,193 @@ /* - * tc-init: We assume the TURBOchannel to be up and running so - * just probe for Modules and fill in the global data structure - * tc_bus. + * TURBOchannel bus services. * - * 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) Harald Koerfgen, 1998 + * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki + * Copyright (c) 2005 James Simmons * - * Copyright (c) Harald Koerfgen, 1998 - * Copyright (c) 2001, 2003, 2005 Maciej W. Rozycki + * This file is subject to the terms and conditions of the GNU + * General Public License. See the file "COPYING" in the main + * directory of this archive for more details. */ +#include +#include #include +#include #include +#include #include #include +#include #include -#include -#include #include -#include -#include -#include -#include -#include -#include - -MODULE_LICENSE("GPL"); -slot_info tc_bus[MAX_SLOT]; -static int num_tcslots; -static tcinfo *info; +static struct tc_bus tc_bus = { + .name = "TURBOchannel", +}; /* - * Interface to the world. Read comment in include/asm-mips/tc.h. + * Probing for TURBOchannel modules. */ - -int search_tc_card(const char *name) -{ - int slot; - slot_info *sip; - - for (slot = 0; slot < num_tcslots; slot++) { - sip = &tc_bus[slot]; - if ((sip->flags & FREE) && - (strncmp(sip->name, name, strlen(name)) == 0)) { - return slot; - } - } - - return -ENODEV; -} - -void claim_tc_card(int slot) -{ - if (tc_bus[slot].flags & IN_USE) { - printk("claim_tc_card: attempting to claim a card already in use\n"); - return; - } - tc_bus[slot].flags &= ~FREE; - tc_bus[slot].flags |= IN_USE; -} - -void release_tc_card(int slot) +static void __init tc_bus_add_devices(struct tc_bus *tbus) { - if (tc_bus[slot].flags & FREE) { - printk("release_tc_card: " - "attempting to release a card already free\n"); - return; - } - tc_bus[slot].flags &= ~IN_USE; - tc_bus[slot].flags |= FREE; -} - -unsigned long get_tc_base_addr(int slot) -{ - return tc_bus[slot].base_addr; -} - -unsigned long get_tc_irq_nr(int slot) -{ - return tc_bus[slot].interrupt; -} - -unsigned long get_tc_speed(void) -{ - return 100000 * (10000 / (unsigned long)info->clk_period); -} - -/* - * Probing for TURBOchannel modules - */ -static void __init tc_probe(unsigned long startaddr, unsigned long size, - int slots) -{ - unsigned long slotaddr; + resource_size_t slotsize = tbus->info.slot_size << 20; + resource_size_t extslotsize = tbus->ext_slot_size; + resource_size_t slotaddr; + resource_size_t extslotaddr; + resource_size_t devsize; + void __iomem *module; + struct tc_dev *tdev; int i, slot, err; - long offset; u8 pattern[4]; - volatile u8 *module; + long offset; - for (slot = 0; slot < slots; slot++) { - slotaddr = startaddr + slot * size; - module = ioremap_nocache(slotaddr, size); + for (slot = 0; slot < tbus->num_tcslots; slot++) { + slotaddr = tbus->slot_base + slot * slotsize; + extslotaddr = tbus->ext_slot_base + slot * extslotsize; + module = ioremap_nocache(slotaddr, slotsize); BUG_ON(!module); - offset = OLDCARD; + offset = TC_OLDCARD; err = 0; - err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0); - err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1); - err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2); - err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3); - if (err) { - iounmap(module); - continue; - } + err |= tc_preadb(pattern + 0, module + offset + TC_PATTERN0); + err |= tc_preadb(pattern + 1, module + offset + TC_PATTERN1); + err |= tc_preadb(pattern + 2, module + offset + TC_PATTERN2); + err |= tc_preadb(pattern + 3, module + offset + TC_PATTERN3); + if (err) + goto out_err; if (pattern[0] != 0x55 || pattern[1] != 0x00 || pattern[2] != 0xaa || pattern[3] != 0xff) { - offset = NEWCARD; + offset = TC_NEWCARD; err = 0; - err |= get_dbe(pattern[0], module + TC_PATTERN0); - err |= get_dbe(pattern[1], module + TC_PATTERN1); - err |= get_dbe(pattern[2], module + TC_PATTERN2); - err |= get_dbe(pattern[3], module + TC_PATTERN3); - if (err) { - iounmap(module); - continue; - } + err |= tc_preadb(pattern + 0, + module + offset + TC_PATTERN0); + err |= tc_preadb(pattern + 1, + module + offset + TC_PATTERN1); + err |= tc_preadb(pattern + 2, + module + offset + TC_PATTERN2); + err |= tc_preadb(pattern + 3, + module + offset + TC_PATTERN3); + if (err) + goto out_err; } if (pattern[0] != 0x55 || pattern[1] != 0x00 || - pattern[2] != 0xaa || pattern[3] != 0xff) { - iounmap(module); - continue; + pattern[2] != 0xaa || pattern[3] != 0xff) + goto out_err; + + /* Found a board, allocate it an entry in the list */ + tdev = kzalloc(sizeof(*tdev), GFP_KERNEL); + if (!tdev) { + printk(KERN_ERR "tc%x: unable to allocate tc_dev\n", + slot); + goto out_err; } + sprintf(tdev->dev.bus_id, "tc%x", slot); + tdev->bus = tbus; + tdev->dev.parent = &tbus->dev; + tdev->dev.bus = &tc_bus_type; + tdev->slot = slot; - tc_bus[slot].base_addr = slotaddr; for (i = 0; i < 8; i++) { - tc_bus[slot].firmware[i] = - module[TC_FIRM_VER + offset + 4 * i]; - tc_bus[slot].vendor[i] = - module[TC_VENDOR + offset + 4 * i]; - tc_bus[slot].name[i] = - module[TC_MODULE + offset + 4 * i]; + tdev->firmware[i] = + readb(module + offset + TC_FIRM_VER + 4 * i); + tdev->vendor[i] = + readb(module + offset + TC_VENDOR + 4 * i); + tdev->name[i] = + readb(module + offset + TC_MODULE + 4 * i); } - tc_bus[slot].firmware[8] = 0; - tc_bus[slot].vendor[8] = 0; - tc_bus[slot].name[8] = 0; - /* - * Looks unneccesary, but we may change - * TC? in the future - */ - switch (slot) { - case 0: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0]; - break; - case 1: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1]; - break; - case 2: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2]; - break; - /* - * Yuck! DS5000/200 onboard devices - */ - case 5: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5]; - break; - case 6: - tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6]; - break; - default: - tc_bus[slot].interrupt = -1; - break; + tdev->firmware[8] = 0; + tdev->vendor[8] = 0; + tdev->name[8] = 0; + + pr_info("%s: %s %s %s\n", tdev->dev.bus_id, tdev->vendor, + tdev->name, tdev->firmware); + + devsize = readb(module + offset + TC_SLOT_SIZE); + devsize <<= 22; + if (devsize <= slotsize) { + tdev->resource.start = slotaddr; + tdev->resource.end = slotaddr + devsize - 1; + } else if (devsize <= extslotsize) { + tdev->resource.start = extslotaddr; + tdev->resource.end = extslotaddr + devsize - 1; + } else { + printk(KERN_ERR "%s: Cannot provide slot space " + "(%dMiB required, up to %dMiB supported)\n", + tdev->dev.bus_id, devsize >> 20, + max(slotsize, extslotsize) >> 20); + kfree(tdev); + goto out_err; } + tdev->resource.name = tdev->name; + tdev->resource.flags = IORESOURCE_MEM; + + tc_device_get_irq(tdev); + device_register(&tdev->dev); + list_add_tail(&tdev->node, &tbus->devices); + +out_err: iounmap(module); } } /* - * the main entry + * The main entry. */ static int __init tc_init(void) { - int tc_clock; - int i; - unsigned long slot0addr; - unsigned long slot_size; - - if (!TURBOCHANNEL) + /* Initialize the TURBOchannel bus */ + if (tc_bus_get_info(&tc_bus)) return 0; - for (i = 0; i < MAX_SLOT; i++) { - tc_bus[i].base_addr = 0; - tc_bus[i].name[0] = 0; - tc_bus[i].vendor[0] = 0; - tc_bus[i].firmware[0] = 0; - tc_bus[i].interrupt = -1; - tc_bus[i].flags = FREE; - } - - info = rex_gettcinfo(); - slot0addr = CPHYSADDR((long)rex_slot_address(0)); - - switch (mips_machtype) { - case MACH_DS5000_200: - num_tcslots = 7; - break; - case MACH_DS5000_1XX: - case MACH_DS5000_2X0: - case MACH_DS5900: - num_tcslots = 3; - break; - case MACH_DS5000_XX: - default: - num_tcslots = 2; - break; - } - - tc_clock = 10000 / info->clk_period; - - if (info->slot_size && slot0addr) { - pr_info("TURBOchannel rev. %d at %d.%d MHz (with%s parity)\n", - info->revision, tc_clock / 10, tc_clock % 10, - info->parity ? "" : "out"); - - slot_size = info->slot_size << 20; - - tc_probe(slot0addr, slot_size, num_tcslots); - - for (i = 0; i < num_tcslots; i++) { - if (!tc_bus[i].base_addr) - continue; - pr_info(" slot %d: %s %s %s\n", i, tc_bus[i].vendor, - tc_bus[i].name, tc_bus[i].firmware); + INIT_LIST_HEAD(&tc_bus.devices); + strcpy(tc_bus.dev.bus_id, "tc"); + device_register(&tc_bus.dev); + + if (tc_bus.info.slot_size) { + unsigned int tc_clock = tc_get_speed(&tc_bus) / 100000; + + pr_info("tc: TURBOchannel rev. %d at %d.%d MHz " + "(with%s parity)\n", tc_bus.info.revision, + tc_clock / 10, tc_clock % 10, + tc_bus.info.parity ? "" : "out"); + + tc_bus.resource[0].start = tc_bus.slot_base; + tc_bus.resource[0].end = tc_bus.slot_base + + (tc_bus.info.slot_size << 20) * + tc_bus.num_tcslots; + tc_bus.resource[0].name = tc_bus.name; + tc_bus.resource[0].flags = IORESOURCE_MEM; + if (request_resource(&iomem_resource, + &tc_bus.resource[0]) < 0) { + printk(KERN_ERR "tc: Cannot reserve resource\n"); + return 0; + } + if (tc_bus.ext_slot_size) { + tc_bus.resource[1].start = tc_bus.ext_slot_base; + tc_bus.resource[1].end = tc_bus.ext_slot_base + + tc_bus.ext_slot_size * + tc_bus.num_tcslots; + tc_bus.resource[1].name = tc_bus.name; + tc_bus.resource[1].flags = IORESOURCE_MEM; + if (request_resource(&iomem_resource, + &tc_bus.resource[1]) < 0) { + printk(KERN_ERR + "tc: Cannot reserve resource\n"); + release_resource(&tc_bus.resource[0]); + return 0; + } } + + tc_bus_add_devices(&tc_bus); } return 0; } subsys_initcall(tc_init); - -EXPORT_SYMBOL(search_tc_card); -EXPORT_SYMBOL(claim_tc_card); -EXPORT_SYMBOL(release_tc_card); -EXPORT_SYMBOL(get_tc_base_addr); -EXPORT_SYMBOL(get_tc_irq_nr); -EXPORT_SYMBOL(get_tc_speed); diff --git a/include/asm-mips/dec/tc.h b/include/asm-mips/dec/tc.h deleted file mode 100644 index 9cb51f24d42c..000000000000 --- a/include/asm-mips/dec/tc.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Interface to the TURBOchannel related routines - * - * 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) 1998 Harald Koerfgen - */ -#ifndef __ASM_DEC_TC_H -#define __ASM_DEC_TC_H - -/* - * Search for a TURBOchannel Option Module - * with a certain name. Returns slot number - * of the first card not in use or -ENODEV - * if none found. - */ -extern int search_tc_card(const char *); -/* - * Marks the card in slot as used - */ -extern void claim_tc_card(int); -/* - * Marks the card in slot as free - */ -extern void release_tc_card(int); -/* - * Return base address of card in slot - */ -extern unsigned long get_tc_base_addr(int); -/* - * Return interrupt number of slot - */ -extern unsigned long get_tc_irq_nr(int); -/* - * Return TURBOchannel clock frequency in Hz - */ -extern unsigned long get_tc_speed(void); - -#endif /* __ASM_DEC_TC_H */ diff --git a/include/asm-mips/dec/tcinfo.h b/include/asm-mips/dec/tcinfo.h deleted file mode 100644 index cc23509ee77a..000000000000 --- a/include/asm-mips/dec/tcinfo.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Various TURBOchannel related stuff - * - * 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. - * - * Information obtained through the get_tcinfo prom call - * created from: - * - * TURBOchannel Firmware Specification - * - * EK-TCAAD-FS-004 - * from Digital Equipment Corporation - * - * Copyright (c) 1998 Harald Koerfgen - */ - -typedef struct { - int revision; - int clk_period; - int slot_size; - int io_timeout; - int dma_range; - int max_dma_burst; - int parity; - int reserved[4]; -} tcinfo; - -#define MAX_SLOT 7 - -typedef struct { - unsigned long base_addr; - unsigned char name[9]; - unsigned char vendor[9]; - unsigned char firmware[9]; - int interrupt; - int flags; -} slot_info; - -/* - * Values for flags - */ -#define FREE 1<<0 -#define IN_USE 1<<1 - - diff --git a/include/asm-mips/dec/tcmodule.h b/include/asm-mips/dec/tcmodule.h deleted file mode 100644 index 6268e8915d87..000000000000 --- a/include/asm-mips/dec/tcmodule.h +++ /dev/null @@ -1,39 +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. - * - * Offsets for the ROM header locations for - * TURBOchannel cards - * - * created from: - * - * TURBOchannel Firmware Specification - * - * EK-TCAAD-FS-004 - * from Digital Equipment Corporation - * - * Jan.1998 Harald Koerfgen - */ -#ifndef __ASM_DEC_TCMODULE_H -#define __ASM_DEC_TCMODULE_H - -#define OLDCARD 0x3c0000 -#define NEWCARD 0x000000 - -#define TC_ROM_WIDTH 0x3e0 -#define TC_ROM_STRIDE 0x3e4 -#define TC_ROM_SIZE 0x3e8 -#define TC_SLOT_SIZE 0x3ec -#define TC_PATTERN0 0x3f0 -#define TC_PATTERN1 0x3f4 -#define TC_PATTERN2 0x3f8 -#define TC_PATTERN3 0x3fc -#define TC_FIRM_VER 0x400 -#define TC_VENDOR 0x420 -#define TC_MODULE 0x440 -#define TC_FIRM_TYPE 0x460 -#define TC_FLAGS 0x470 -#define TC_ROM_OBJECTS 0x480 - -#endif /* __ASM_DEC_TCMODULE_H */ diff --git a/include/linux/tc.h b/include/linux/tc.h new file mode 100644 index 000000000000..f92511e57cdb --- /dev/null +++ b/include/linux/tc.h @@ -0,0 +1,141 @@ +/* + * Interface to the TURBOchannel related routines. + * + * Copyright (c) 1998 Harald Koerfgen + * Copyright (c) 2005 James Simmons + * Copyright (c) 2006 Maciej W. Rozycki + * + * Based on: + * + * "TURBOchannel Firmware Specification", EK-TCAAD-FS-004 + * + * from Digital Equipment Corporation. + * + * 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 _LINUX_TC_H +#define _LINUX_TC_H + +#include +#include +#include +#include + +/* + * Offsets for the ROM header locations for TURBOchannel cards. + */ +#define TC_OLDCARD 0x3c0000 +#define TC_NEWCARD 0x000000 + +#define TC_ROM_WIDTH 0x3e0 +#define TC_ROM_STRIDE 0x3e4 +#define TC_ROM_SIZE 0x3e8 +#define TC_SLOT_SIZE 0x3ec +#define TC_PATTERN0 0x3f0 +#define TC_PATTERN1 0x3f4 +#define TC_PATTERN2 0x3f8 +#define TC_PATTERN3 0x3fc +#define TC_FIRM_VER 0x400 +#define TC_VENDOR 0x420 +#define TC_MODULE 0x440 +#define TC_FIRM_TYPE 0x460 +#define TC_FLAGS 0x470 +#define TC_ROM_OBJECTS 0x480 + +/* + * Information obtained through the get_tcinfo() PROM call. + */ +struct tcinfo { + s32 revision; /* Hardware revision level. */ + s32 clk_period; /* Clock period in nanoseconds. */ + s32 slot_size; /* Slot size in megabytes. */ + s32 io_timeout; /* I/O timeout in cycles. */ + s32 dma_range; /* DMA address range in megabytes. */ + s32 max_dma_burst; /* Maximum DMA burst length. */ + s32 parity; /* System module supports TC parity. */ + s32 reserved[4]; +}; + +/* + * TURBOchannel bus. + */ +struct tc_bus { + struct list_head devices; /* List of devices on this bus. */ + struct resource resource[2]; /* Address space routed to this bus. */ + + struct device dev; + char name[13]; + resource_size_t slot_base; + resource_size_t ext_slot_base; + resource_size_t ext_slot_size; + int num_tcslots; + struct tcinfo info; +}; + +/* + * TURBOchannel device. + */ +struct tc_dev { + struct list_head node; /* Node in list of all TC devices. */ + struct tc_bus *bus; /* Bus this device is on. */ + struct tc_driver *driver; /* Which driver has allocated this + device. */ + struct device dev; /* Generic device interface. */ + struct resource resource; /* Address space of this device. */ + char vendor[9]; + char name[9]; + char firmware[9]; + int interrupt; + int slot; +}; + +#define to_tc_dev(n) container_of(n, struct tc_dev, dev) + +struct tc_device_id { + char vendor[9]; + char name[9]; +}; + +/* + * TURBOchannel driver. + */ +struct tc_driver { + struct list_head node; + const struct tc_device_id *id_table; + struct device_driver driver; +}; + +#define to_tc_driver(drv) container_of(drv, struct tc_driver, driver) + +/* + * Return TURBOchannel clock frequency in Hz. + */ +static inline unsigned long tc_get_speed(struct tc_bus *tbus) +{ + return 100000 * (10000 / (unsigned long)tbus->info.clk_period); +} + +#ifdef CONFIG_TC + +extern struct bus_type tc_bus_type; + +extern int tc_register_driver(struct tc_driver *tdrv); +extern void tc_unregister_driver(struct tc_driver *tdrv); + +#else /* !CONFIG_TC */ + +static inline int tc_register_driver(struct tc_driver *tdrv) { return 0; } +static inline void tc_unregister_driver(struct tc_driver *tdrv) { } + +#endif /* CONFIG_TC */ + +/* + * These have to be provided by the architecture. + */ +extern int tc_preadb(u8 *valp, void __iomem *addr); +extern int tc_bus_get_info(struct tc_bus *tbus); +extern void tc_device_get_irq(struct tc_dev *tdev); + +#endif /* _LINUX_TC_H */ -- cgit v1.2.3 From f85da084151c9454891124c999006857a354622a Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 5 Feb 2007 16:28:26 -0800 Subject: [EISA] EISA registration with !CONFIG_EISA This is a change for the EISA bus support to permit drivers to call un/registration functions even if EISA support has not been enabled. This is similar to what PCI (and now TC) does and reduces the need for #ifdef clutter. Signed-off-by: Maciej W. Rozycki Signed-off-by: Andrew Morton Signed-off-by: Ralf Baechle --- include/linux/eisa.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include/linux') diff --git a/include/linux/eisa.h b/include/linux/eisa.h index 1ff7c1392525..fe806b6f030d 100644 --- a/include/linux/eisa.h +++ b/include/linux/eisa.h @@ -61,10 +61,20 @@ struct eisa_driver { #define to_eisa_driver(drv) container_of(drv,struct eisa_driver, driver) +/* These external functions are only available when EISA support is enabled. */ +#ifdef CONFIG_EISA + extern struct bus_type eisa_bus_type; int eisa_driver_register (struct eisa_driver *edrv); void eisa_driver_unregister (struct eisa_driver *edrv); +#else /* !CONFIG_EISA */ + +static inline int eisa_driver_register (struct eisa_driver *edrv) { return 0; } +static inline void eisa_driver_unregister (struct eisa_driver *edrv) { } + +#endif /* !CONFIG_EISA */ + /* Mimics pci.h... */ static inline void *eisa_get_drvdata (struct eisa_device *edev) { -- cgit v1.2.3 From 7726942fb15edd46e4fe8ab37f9a99795191e585 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 9 Feb 2007 17:08:57 +0000 Subject: [APM] Add shared version of APM emulation Currently ARM and MIPS both have nearly identical copies of the APM emulation code in their arch code. Add yet another copy of it to drivers char and make it selectable through SYS_SUPPORTS_APM_EMULATION. Signed-off-by: Ralf Baechle --- drivers/char/Makefile | 2 + drivers/char/apm-emulation.c | 672 ++++++++++++++++++++++++++++++++++++++++++ include/linux/apm-emulation.h | 62 ++++ kernel/power/Kconfig | 26 ++ 4 files changed, 762 insertions(+) create mode 100644 drivers/char/apm-emulation.c create mode 100644 include/linux/apm-emulation.h (limited to 'include/linux') diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 0326ca1a848a..ae8567cc529c 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -60,6 +60,8 @@ obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o obj-$(CONFIG_PRINTER) += lp.o obj-$(CONFIG_TIPAR) += tipar.o +obj-$(CONFIG_APM_EMULATION) += apm-emulation.o + obj-$(CONFIG_DTLK) += dtlk.o obj-$(CONFIG_R3964) += n_r3964.o obj-$(CONFIG_APPLICOM) += applicom.o diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c new file mode 100644 index 000000000000..179c7a3b6e75 --- /dev/null +++ b/drivers/char/apm-emulation.c @@ -0,0 +1,672 @@ +/* + * bios-less APM driver for ARM Linux + * Jamey Hicks + * adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com) + * + * APM 1.2 Reference: + * Intel Corporation, Microsoft Corporation. Advanced Power Management + * (APM) BIOS Interface Specification, Revision 1.2, February 1996. + * + * [This document is available from Microsoft at: + * http://www.microsoft.com/hwdev/busbios/amp_12.htm] + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * The apm_bios device is one of the misc char devices. + * This is its minor number. + */ +#define APM_MINOR_DEV 134 + +/* + * See Documentation/Config.help for the configuration options. + * + * Various options can be changed at boot time as follows: + * (We allow underscores for compatibility with the modules code) + * apm=on/off enable/disable APM + */ + +/* + * Maximum number of events stored + */ +#define APM_MAX_EVENTS 16 + +struct apm_queue { + unsigned int event_head; + unsigned int event_tail; + apm_event_t events[APM_MAX_EVENTS]; +}; + +/* + * The per-file APM data + */ +struct apm_user { + struct list_head list; + + unsigned int suser: 1; + unsigned int writer: 1; + unsigned int reader: 1; + + int suspend_result; + unsigned int suspend_state; +#define SUSPEND_NONE 0 /* no suspend pending */ +#define SUSPEND_PENDING 1 /* suspend pending read */ +#define SUSPEND_READ 2 /* suspend read, pending ack */ +#define SUSPEND_ACKED 3 /* suspend acked */ +#define SUSPEND_WAIT 4 /* waiting for suspend */ +#define SUSPEND_DONE 5 /* suspend completed */ + + struct apm_queue queue; +}; + +/* + * Local variables + */ +static int suspends_pending; +static int apm_disabled; +static struct task_struct *kapmd_tsk; + +static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); +static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); + +/* + * This is a list of everyone who has opened /dev/apm_bios + */ +static DECLARE_RWSEM(user_list_lock); +static LIST_HEAD(apm_user_list); + +/* + * kapmd info. kapmd provides us a process context to handle + * "APM" events within - specifically necessary if we're going + * to be suspending the system. + */ +static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait); +static DEFINE_SPINLOCK(kapmd_queue_lock); +static struct apm_queue kapmd_queue; + +static DEFINE_MUTEX(state_lock); + +static const char driver_version[] = "1.13"; /* no spaces */ + + + +/* + * Compatibility cruft until the IPAQ people move over to the new + * interface. + */ +static void __apm_get_power_status(struct apm_power_info *info) +{ +} + +/* + * This allows machines to provide their own "apm get power status" function. + */ +void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status; +EXPORT_SYMBOL(apm_get_power_status); + + +/* + * APM event queue management. + */ +static inline int queue_empty(struct apm_queue *q) +{ + return q->event_head == q->event_tail; +} + +static inline apm_event_t queue_get_event(struct apm_queue *q) +{ + q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; + return q->events[q->event_tail]; +} + +static void queue_add_event(struct apm_queue *q, apm_event_t event) +{ + q->event_head = (q->event_head + 1) % APM_MAX_EVENTS; + if (q->event_head == q->event_tail) { + static int notified; + + if (notified++ == 0) + printk(KERN_ERR "apm: an event queue overflowed\n"); + q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; + } + q->events[q->event_head] = event; +} + +static void queue_event(apm_event_t event) +{ + struct apm_user *as; + + down_read(&user_list_lock); + list_for_each_entry(as, &apm_user_list, list) { + if (as->reader) + queue_add_event(&as->queue, event); + } + up_read(&user_list_lock); + wake_up_interruptible(&apm_waitqueue); +} + +/* + * queue_suspend_event - queue an APM suspend event. + * + * Check that we're in a state where we can suspend. If not, + * return -EBUSY. Otherwise, queue an event to all "writer" + * users. If there are no "writer" users, return '1' to + * indicate that we can immediately suspend. + */ +static int queue_suspend_event(apm_event_t event, struct apm_user *sender) +{ + struct apm_user *as; + int ret = 1; + + mutex_lock(&state_lock); + down_read(&user_list_lock); + + /* + * If a thread is still processing, we can't suspend, so reject + * the request. + */ + list_for_each_entry(as, &apm_user_list, list) { + if (as != sender && as->reader && as->writer && as->suser && + as->suspend_state != SUSPEND_NONE) { + ret = -EBUSY; + goto out; + } + } + + list_for_each_entry(as, &apm_user_list, list) { + if (as != sender && as->reader && as->writer && as->suser) { + as->suspend_state = SUSPEND_PENDING; + suspends_pending++; + queue_add_event(&as->queue, event); + ret = 0; + } + } + out: + up_read(&user_list_lock); + mutex_unlock(&state_lock); + wake_up_interruptible(&apm_waitqueue); + return ret; +} + +static void apm_suspend(void) +{ + struct apm_user *as; + int err = pm_suspend(PM_SUSPEND_MEM); + + /* + * Anyone on the APM queues will think we're still suspended. + * Send a message so everyone knows we're now awake again. + */ + queue_event(APM_NORMAL_RESUME); + + /* + * Finally, wake up anyone who is sleeping on the suspend. + */ + mutex_lock(&state_lock); + down_read(&user_list_lock); + list_for_each_entry(as, &apm_user_list, list) { + if (as->suspend_state == SUSPEND_WAIT || + as->suspend_state == SUSPEND_ACKED) { + as->suspend_result = err; + as->suspend_state = SUSPEND_DONE; + } + } + up_read(&user_list_lock); + mutex_unlock(&state_lock); + + wake_up(&apm_suspend_waitqueue); +} + +static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos) +{ + struct apm_user *as = fp->private_data; + apm_event_t event; + int i = count, ret = 0; + + if (count < sizeof(apm_event_t)) + return -EINVAL; + + if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK) + return -EAGAIN; + + wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue)); + + while ((i >= sizeof(event)) && !queue_empty(&as->queue)) { + event = queue_get_event(&as->queue); + + ret = -EFAULT; + if (copy_to_user(buf, &event, sizeof(event))) + break; + + mutex_lock(&state_lock); + if (as->suspend_state == SUSPEND_PENDING && + (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND)) + as->suspend_state = SUSPEND_READ; + mutex_unlock(&state_lock); + + buf += sizeof(event); + i -= sizeof(event); + } + + if (i < count) + ret = count - i; + + return ret; +} + +static unsigned int apm_poll(struct file *fp, poll_table * wait) +{ + struct apm_user *as = fp->private_data; + + poll_wait(fp, &apm_waitqueue, wait); + return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM; +} + +/* + * apm_ioctl - handle APM ioctl + * + * APM_IOC_SUSPEND + * This IOCTL is overloaded, and performs two functions. It is used to: + * - initiate a suspend + * - acknowledge a suspend read from /dev/apm_bios. + * Only when everyone who has opened /dev/apm_bios with write permission + * has acknowledge does the actual suspend happen. + */ +static int +apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) +{ + struct apm_user *as = filp->private_data; + unsigned long flags; + int err = -EINVAL; + + if (!as->suser || !as->writer) + return -EPERM; + + switch (cmd) { + case APM_IOC_SUSPEND: + mutex_lock(&state_lock); + + as->suspend_result = -EINTR; + + if (as->suspend_state == SUSPEND_READ) { + int pending; + + /* + * If we read a suspend command from /dev/apm_bios, + * then the corresponding APM_IOC_SUSPEND ioctl is + * interpreted as an acknowledge. + */ + as->suspend_state = SUSPEND_ACKED; + suspends_pending--; + pending = suspends_pending == 0; + mutex_unlock(&state_lock); + + /* + * If there are no further acknowledges required, + * suspend the system. + */ + if (pending) + apm_suspend(); + + /* + * Wait for the suspend/resume to complete. If there + * are pending acknowledges, we wait here for them. + * + * Note: we need to ensure that the PM subsystem does + * not kick us out of the wait when it suspends the + * threads. + */ + flags = current->flags; + current->flags |= PF_NOFREEZE; + + wait_event(apm_suspend_waitqueue, + as->suspend_state == SUSPEND_DONE); + } else { + as->suspend_state = SUSPEND_WAIT; + mutex_unlock(&state_lock); + + /* + * Otherwise it is a request to suspend the system. + * Queue an event for all readers, and expect an + * acknowledge from all writers who haven't already + * acknowledged. + */ + err = queue_suspend_event(APM_USER_SUSPEND, as); + if (err < 0) { + /* + * Avoid taking the lock here - this + * should be fine. + */ + as->suspend_state = SUSPEND_NONE; + break; + } + + if (err > 0) + apm_suspend(); + + /* + * Wait for the suspend/resume to complete. If there + * are pending acknowledges, we wait here for them. + * + * Note: we need to ensure that the PM subsystem does + * not kick us out of the wait when it suspends the + * threads. + */ + flags = current->flags; + current->flags |= PF_NOFREEZE; + + wait_event_interruptible(apm_suspend_waitqueue, + as->suspend_state == SUSPEND_DONE); + } + + current->flags = flags; + + mutex_lock(&state_lock); + err = as->suspend_result; + as->suspend_state = SUSPEND_NONE; + mutex_unlock(&state_lock); + break; + } + + return err; +} + +static int apm_release(struct inode * inode, struct file * filp) +{ + struct apm_user *as = filp->private_data; + int pending = 0; + + filp->private_data = NULL; + + down_write(&user_list_lock); + list_del(&as->list); + up_write(&user_list_lock); + + /* + * We are now unhooked from the chain. As far as new + * events are concerned, we no longer exist. However, we + * need to balance suspends_pending, which means the + * possibility of sleeping. + */ + mutex_lock(&state_lock); + if (as->suspend_state != SUSPEND_NONE) { + suspends_pending -= 1; + pending = suspends_pending == 0; + } + mutex_unlock(&state_lock); + if (pending) + apm_suspend(); + + kfree(as); + return 0; +} + +static int apm_open(struct inode * inode, struct file * filp) +{ + struct apm_user *as; + + as = kzalloc(sizeof(*as), GFP_KERNEL); + if (as) { + /* + * XXX - this is a tiny bit broken, when we consider BSD + * process accounting. If the device is opened by root, we + * instantly flag that we used superuser privs. Who knows, + * we might close the device immediately without doing a + * privileged operation -- cevans + */ + as->suser = capable(CAP_SYS_ADMIN); + as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE; + as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ; + + down_write(&user_list_lock); + list_add(&as->list, &apm_user_list); + up_write(&user_list_lock); + + filp->private_data = as; + } + + return as ? 0 : -ENOMEM; +} + +static struct file_operations apm_bios_fops = { + .owner = THIS_MODULE, + .read = apm_read, + .poll = apm_poll, + .ioctl = apm_ioctl, + .open = apm_open, + .release = apm_release, +}; + +static struct miscdevice apm_device = { + .minor = APM_MINOR_DEV, + .name = "apm_bios", + .fops = &apm_bios_fops +}; + + +#ifdef CONFIG_PROC_FS +/* + * Arguments, with symbols from linux/apm_bios.h. + * + * 0) Linux driver version (this will change if format changes) + * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. + * 2) APM flags from APM Installation Check (0x00): + * bit 0: APM_16_BIT_SUPPORT + * bit 1: APM_32_BIT_SUPPORT + * bit 2: APM_IDLE_SLOWS_CLOCK + * bit 3: APM_BIOS_DISABLED + * bit 4: APM_BIOS_DISENGAGED + * 3) AC line status + * 0x00: Off-line + * 0x01: On-line + * 0x02: On backup power (BIOS >= 1.1 only) + * 0xff: Unknown + * 4) Battery status + * 0x00: High + * 0x01: Low + * 0x02: Critical + * 0x03: Charging + * 0x04: Selected battery not present (BIOS >= 1.2 only) + * 0xff: Unknown + * 5) Battery flag + * bit 0: High + * bit 1: Low + * bit 2: Critical + * bit 3: Charging + * bit 7: No system battery + * 0xff: Unknown + * 6) Remaining battery life (percentage of charge): + * 0-100: valid + * -1: Unknown + * 7) Remaining battery life (time units): + * Number of remaining minutes or seconds + * -1: Unknown + * 8) min = minutes; sec = seconds + */ +static int apm_get_info(char *buf, char **start, off_t fpos, int length) +{ + struct apm_power_info info; + char *units; + int ret; + + info.ac_line_status = 0xff; + info.battery_status = 0xff; + info.battery_flag = 0xff; + info.battery_life = -1; + info.time = -1; + info.units = -1; + + if (apm_get_power_status) + apm_get_power_status(&info); + + switch (info.units) { + default: units = "?"; break; + case 0: units = "min"; break; + case 1: units = "sec"; break; + } + + ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", + driver_version, APM_32_BIT_SUPPORT, + info.ac_line_status, info.battery_status, + info.battery_flag, info.battery_life, + info.time, units); + + return ret; +} +#endif + +static int kapmd(void *arg) +{ + do { + apm_event_t event; + int ret; + + wait_event_interruptible(kapmd_wait, + !queue_empty(&kapmd_queue) || kthread_should_stop()); + + if (kthread_should_stop()) + break; + + spin_lock_irq(&kapmd_queue_lock); + event = 0; + if (!queue_empty(&kapmd_queue)) + event = queue_get_event(&kapmd_queue); + spin_unlock_irq(&kapmd_queue_lock); + + switch (event) { + case 0: + break; + + case APM_LOW_BATTERY: + case APM_POWER_STATUS_CHANGE: + queue_event(event); + break; + + case APM_USER_SUSPEND: + case APM_SYS_SUSPEND: + ret = queue_suspend_event(event, NULL); + if (ret < 0) { + /* + * We were busy. Try again in 50ms. + */ + queue_add_event(&kapmd_queue, event); + msleep(50); + } + if (ret > 0) + apm_suspend(); + break; + + case APM_CRITICAL_SUSPEND: + apm_suspend(); + break; + } + } while (1); + + return 0; +} + +static int __init apm_init(void) +{ + int ret; + + if (apm_disabled) { + printk(KERN_NOTICE "apm: disabled on user request.\n"); + return -ENODEV; + } + + kapmd_tsk = kthread_create(kapmd, NULL, "kapmd"); + if (IS_ERR(kapmd_tsk)) { + ret = PTR_ERR(kapmd_tsk); + kapmd_tsk = NULL; + return ret; + } + kapmd_tsk->flags |= PF_NOFREEZE; + wake_up_process(kapmd_tsk); + +#ifdef CONFIG_PROC_FS + create_proc_info_entry("apm", 0, NULL, apm_get_info); +#endif + + ret = misc_register(&apm_device); + if (ret != 0) { + remove_proc_entry("apm", NULL); + kthread_stop(kapmd_tsk); + } + + return ret; +} + +static void __exit apm_exit(void) +{ + misc_deregister(&apm_device); + remove_proc_entry("apm", NULL); + + kthread_stop(kapmd_tsk); +} + +module_init(apm_init); +module_exit(apm_exit); + +MODULE_AUTHOR("Stephen Rothwell"); +MODULE_DESCRIPTION("Advanced Power Management"); +MODULE_LICENSE("GPL"); + +#ifndef MODULE +static int __init apm_setup(char *str) +{ + while ((str != NULL) && (*str != '\0')) { + if (strncmp(str, "off", 3) == 0) + apm_disabled = 1; + if (strncmp(str, "on", 2) == 0) + apm_disabled = 0; + str = strchr(str, ','); + if (str != NULL) + str += strspn(str, ", \t"); + } + return 1; +} + +__setup("apm=", apm_setup); +#endif + +/** + * apm_queue_event - queue an APM event for kapmd + * @event: APM event + * + * Queue an APM event for kapmd to process and ultimately take the + * appropriate action. Only a subset of events are handled: + * %APM_LOW_BATTERY + * %APM_POWER_STATUS_CHANGE + * %APM_USER_SUSPEND + * %APM_SYS_SUSPEND + * %APM_CRITICAL_SUSPEND + */ +void apm_queue_event(apm_event_t event) +{ + unsigned long flags; + + spin_lock_irqsave(&kapmd_queue_lock, flags); + queue_add_event(&kapmd_queue, event); + spin_unlock_irqrestore(&kapmd_queue_lock, flags); + + wake_up_interruptible(&kapmd_wait); +} +EXPORT_SYMBOL(apm_queue_event); diff --git a/include/linux/apm-emulation.h b/include/linux/apm-emulation.h new file mode 100644 index 000000000000..e6d800358dd6 --- /dev/null +++ b/include/linux/apm-emulation.h @@ -0,0 +1,62 @@ +/* -*- linux-c -*- + * + * (C) 2003 zecke@handhelds.org + * + * GPL version 2 + * + * based on arch/arm/kernel/apm.c + * factor out the information needed by architectures to provide + * apm status + */ +#ifndef __LINUX_APM_EMULATION_H +#define __LINUX_APM_EMULATION_H + +#include + +/* + * This structure gets filled in by the machine specific 'get_power_status' + * implementation. Any fields which are not set default to a safe value. + */ +struct apm_power_info { + unsigned char ac_line_status; +#define APM_AC_OFFLINE 0 +#define APM_AC_ONLINE 1 +#define APM_AC_BACKUP 2 +#define APM_AC_UNKNOWN 0xff + + unsigned char battery_status; +#define APM_BATTERY_STATUS_HIGH 0 +#define APM_BATTERY_STATUS_LOW 1 +#define APM_BATTERY_STATUS_CRITICAL 2 +#define APM_BATTERY_STATUS_CHARGING 3 +#define APM_BATTERY_STATUS_NOT_PRESENT 4 +#define APM_BATTERY_STATUS_UNKNOWN 0xff + + unsigned char battery_flag; +#define APM_BATTERY_FLAG_HIGH (1 << 0) +#define APM_BATTERY_FLAG_LOW (1 << 1) +#define APM_BATTERY_FLAG_CRITICAL (1 << 2) +#define APM_BATTERY_FLAG_CHARGING (1 << 3) +#define APM_BATTERY_FLAG_NOT_PRESENT (1 << 7) +#define APM_BATTERY_FLAG_UNKNOWN 0xff + + int battery_life; + int time; + int units; +#define APM_UNITS_MINS 0 +#define APM_UNITS_SECS 1 +#define APM_UNITS_UNKNOWN -1 + +}; + +/* + * This allows machines to provide their own "apm get power status" function. + */ +extern void (*apm_get_power_status)(struct apm_power_info *); + +/* + * Queue an event (APM_SYS_SUSPEND or APM_CRITICAL_SUSPEND) + */ +void apm_queue_event(apm_event_t event); + +#endif /* __LINUX_APM_EMULATION_H */ diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index ed296225dcd4..95f6657fff73 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -131,3 +131,29 @@ config SUSPEND_SMP bool depends on HOTPLUG_CPU && X86 && PM default y + +config APM_EMULATION + tristate "Advanced Power Management Emulation" + depends on PM && SYS_SUPPORTS_APM_EMULATION + help + APM is a BIOS specification for saving power using several different + techniques. This is mostly useful for battery powered laptops with + APM compliant BIOSes. If you say Y here, the system time will be + reset after a RESUME operation, the /proc/apm device will provide + battery status information, and user-space programs will receive + notification of APM "events" (e.g. battery status change). + + In order to use APM, you will need supporting software. For location + and more information, read and the + Battery Powered Linux mini-HOWTO, available from + . + + This driver does not spin down disk drives (see the hdparm(8) + manpage ("man 8 hdparm") for that), and it doesn't turn off + VESA-compliant "green" monitors. + + Generally, if you don't have a battery in your machine, there isn't + much point in using this driver and you should say N. If you get + random kernel OOPSes or reboots that don't seem to be related to + anything, try disabling/enabling this option (or disabling/enabling + APM in your BIOS). -- cgit v1.2.3 From f2e97df669d32f74152336f46e4e0e328b993c57 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 9 Feb 2007 16:38:55 +0000 Subject: [PATCH] in non-NUMA case mark GFP_THISNODE gfp_t ... operations with it are OK as is, but flags & ~0 will have no idea that this ~0 is meant to be ~gfp_t. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- include/linux/gfp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 00c314aedab7..063799ea6be0 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -70,7 +70,7 @@ struct vm_area_struct; #ifdef CONFIG_NUMA #define GFP_THISNODE (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY) #else -#define GFP_THISNODE 0 +#define GFP_THISNODE ((__force gfp_t)0) #endif -- cgit v1.2.3 From f336953bfdee8d5e7f69cb8e080704546541f04b Mon Sep 17 00:00:00 2001 From: Evgeniy Dushistov Date: Thu, 8 Feb 2007 14:20:25 -0800 Subject: [PATCH] ufs: restore back support of openstep This is a fix of regression, which triggered by ~2.6.16. Patch with name ufs-directory-and-page-cache-from-blocks-to-pages.patch: in additional to conversation from block to page cache mechanism added new checks of directory integrity, one of them that directory entry do not across directory chunks. But some kinds of UFS: OpenStep UFS and Apple UFS (looks like these are the same filesystems) have different directory chunk size, then common UFSes(BSD and Solaris UFS). So this patch adds ability to works with variable size of directory chunks, and set it for ufstype=openstep to right size. Tested on darwin ufs. Signed-off-by: Evgeniy Dushistov Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ufs/dir.c | 21 ++++++++++++--------- fs/ufs/super.c | 5 ++++- include/linux/ufs_fs.h | 1 + 3 files changed, 17 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index 433b6f68403a..a6c0ca9f48bf 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c @@ -106,12 +106,13 @@ static void ufs_check_page(struct page *page) char *kaddr = page_address(page); unsigned offs, rec_len; unsigned limit = PAGE_CACHE_SIZE; + const unsigned chunk_mask = UFS_SB(sb)->s_uspi->s_dirblksize - 1; struct ufs_dir_entry *p; char *error; if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) { limit = dir->i_size & ~PAGE_CACHE_MASK; - if (limit & (UFS_SECTOR_SIZE - 1)) + if (limit & chunk_mask) goto Ebadsize; if (!limit) goto out; @@ -126,7 +127,7 @@ static void ufs_check_page(struct page *page) goto Ealign; if (rec_len < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, p))) goto Enamelen; - if (((offs + rec_len - 1) ^ offs) & ~(UFS_SECTOR_SIZE-1)) + if (((offs + rec_len - 1) ^ offs) & ~chunk_mask) goto Espan; if (fs32_to_cpu(sb, p->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg * UFS_SB(sb)->s_uspi->s_ncg)) @@ -310,6 +311,7 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode) int namelen = dentry->d_name.len; struct super_block *sb = dir->i_sb; unsigned reclen = UFS_DIR_REC_LEN(namelen); + const unsigned int chunk_size = UFS_SB(sb)->s_uspi->s_dirblksize; unsigned short rec_len, name_len; struct page *page = NULL; struct ufs_dir_entry *de; @@ -342,8 +344,8 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode) if ((char *)de == dir_end) { /* We hit i_size */ name_len = 0; - rec_len = UFS_SECTOR_SIZE; - de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE); + rec_len = chunk_size; + de->d_reclen = cpu_to_fs16(sb, chunk_size); de->d_ino = 0; goto got_it; } @@ -431,7 +433,7 @@ ufs_readdir(struct file *filp, void *dirent, filldir_t filldir) unsigned int offset = pos & ~PAGE_CACHE_MASK; unsigned long n = pos >> PAGE_CACHE_SHIFT; unsigned long npages = ufs_dir_pages(inode); - unsigned chunk_mask = ~(UFS_SECTOR_SIZE - 1); + unsigned chunk_mask = ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1); int need_revalidate = filp->f_version != inode->i_version; unsigned flags = UFS_SB(sb)->s_flags; @@ -511,7 +513,7 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir, struct super_block *sb = inode->i_sb; struct address_space *mapping = page->mapping; char *kaddr = page_address(page); - unsigned from = ((char*)dir - kaddr) & ~(UFS_SECTOR_SIZE - 1); + unsigned from = ((char*)dir - kaddr) & ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1); unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen); struct ufs_dir_entry *pde = NULL; struct ufs_dir_entry *de = (struct ufs_dir_entry *) (kaddr + from); @@ -556,6 +558,7 @@ int ufs_make_empty(struct inode * inode, struct inode *dir) struct super_block * sb = dir->i_sb; struct address_space *mapping = inode->i_mapping; struct page *page = grab_cache_page(mapping, 0); + const unsigned int chunk_size = UFS_SB(sb)->s_uspi->s_dirblksize; struct ufs_dir_entry * de; char *base; int err; @@ -563,7 +566,7 @@ int ufs_make_empty(struct inode * inode, struct inode *dir) if (!page) return -ENOMEM; kmap(page); - err = mapping->a_ops->prepare_write(NULL, page, 0, UFS_SECTOR_SIZE); + err = mapping->a_ops->prepare_write(NULL, page, 0, chunk_size); if (err) { unlock_page(page); goto fail; @@ -584,11 +587,11 @@ int ufs_make_empty(struct inode * inode, struct inode *dir) ((char *)de + fs16_to_cpu(sb, de->d_reclen)); de->d_ino = cpu_to_fs32(sb, dir->i_ino); ufs_set_de_type(sb, de, dir->i_mode); - de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE - UFS_DIR_REC_LEN(1)); + de->d_reclen = cpu_to_fs16(sb, chunk_size - UFS_DIR_REC_LEN(1)); ufs_set_de_namlen(sb, de, 2); strcpy (de->d_name, ".."); - err = ufs_commit_chunk(page, 0, UFS_SECTOR_SIZE); + err = ufs_commit_chunk(page, 0, chunk_size); fail: kunmap(page); page_cache_release(page); diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 8a8e9382ec09..209be95e9d18 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -649,7 +649,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL); if (!uspi) goto failed; - + uspi->s_dirblksize = UFS_SECTOR_SIZE; super_block_offset=UFS_SBLOCK; /* Keep 2Gig file limit. Some UFS variants need to override @@ -718,6 +718,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_NEXTSTEP: + /*TODO: check may be we need set special dir block size?*/ UFSD("ufstype=nextstep\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); @@ -733,6 +734,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD: + /*TODO: check may be we need set special dir block size?*/ UFSD("ufstype=nextstep-cd\n"); uspi->s_fsize = block_size = 2048; uspi->s_fmask = ~(2048 - 1); @@ -754,6 +756,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; + uspi->s_dirblksize = 1024; flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; if (!(sb->s_flags & MS_RDONLY)) { if (!silent) diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h index 28967eda9d7b..d3a4f994a5dc 100644 --- a/include/linux/ufs_fs.h +++ b/include/linux/ufs_fs.h @@ -789,6 +789,7 @@ struct ufs_sb_private_info { __u32 s_maxsymlinklen;/* upper limit on fast symlinks' size */ __s32 fs_magic; /* filesystem magic */ + unsigned int s_dirblksize; }; /* -- cgit v1.2.3 From aaf68cfbf2241d24d46583423f6bff5c47e088b3 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 8 Feb 2007 14:20:30 -0800 Subject: [PATCH] knfsd: fix a race in closing NFSd connections If you lose this race, it can iput a socket inode twice and you get a BUG in fs/inode.c When I added the option for user-space to close a socket, I added some cruft to svc_delete_socket so that I could call that function when closing a socket per user-space request. This was the wrong thing to do. I should have just set SK_CLOSE and let normal mechanisms do the work. Not only wrong, but buggy. The locking is all wrong and it openned up a race where-by a socket could be closed twice. So this patch: Introduces svc_close_socket which sets SK_CLOSE then either leave the close up to a thread, or calls svc_delete_socket if it can get SK_BUSY. Adds a bias to sk_busy which is removed when SK_DEAD is set, This avoid races around shutting down the socket. Changes several 'spin_lock' to 'spin_lock_bh' where the _bh was missing. Bugzilla-url: http://bugzilla.kernel.org/show_bug.cgi?id=7916 Signed-off-by: Neil Brown Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sunrpc/svcsock.h | 2 +- net/sunrpc/svc.c | 4 ++-- net/sunrpc/svcsock.c | 52 ++++++++++++++++++++++++++++++------------ 3 files changed, 41 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 98b21ad370fd..db312a1e2eeb 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -63,7 +63,7 @@ struct svc_sock { * Function prototypes. */ int svc_makesock(struct svc_serv *, int, unsigned short); -void svc_delete_socket(struct svc_sock *); +void svc_close_socket(struct svc_sock *); int svc_recv(struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 4c1611211119..c1f878131ac6 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -386,7 +386,7 @@ svc_destroy(struct svc_serv *serv) svsk = list_entry(serv->sv_tempsocks.next, struct svc_sock, sk_list); - svc_delete_socket(svsk); + svc_close_socket(svsk); } if (serv->sv_shutdown) serv->sv_shutdown(serv); @@ -395,7 +395,7 @@ svc_destroy(struct svc_serv *serv) svsk = list_entry(serv->sv_permsocks.next, struct svc_sock, sk_list); - svc_delete_socket(svsk); + svc_close_socket(svsk); } cache_clean_deferred(serv); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index ff1f8bf680aa..cf93cd1d857b 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -62,6 +62,12 @@ * after a clear, the socket must be read/accepted * if this succeeds, it must be set again. * SK_CLOSE can set at any time. It is never cleared. + * sk_inuse contains a bias of '1' until SK_DEAD is set. + * so when sk_inuse hits zero, we know the socket is dead + * and no-one is using it. + * SK_DEAD can only be set while SK_BUSY is held which ensures + * no other thread will be using the socket or will try to + * set SK_DEAD. * */ @@ -70,6 +76,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *, int *errp, int pmap_reg); +static void svc_delete_socket(struct svc_sock *svsk); static void svc_udp_data_ready(struct sock *, int); static int svc_udp_recvfrom(struct svc_rqst *); static int svc_udp_sendto(struct svc_rqst *); @@ -329,8 +336,9 @@ void svc_reserve(struct svc_rqst *rqstp, int space) static inline void svc_sock_put(struct svc_sock *svsk) { - if (atomic_dec_and_test(&svsk->sk_inuse) && - test_bit(SK_DEAD, &svsk->sk_flags)) { + if (atomic_dec_and_test(&svsk->sk_inuse)) { + BUG_ON(! test_bit(SK_DEAD, &svsk->sk_flags)); + dprintk("svc: releasing dead socket\n"); if (svsk->sk_sock->file) sockfd_put(svsk->sk_sock); @@ -520,7 +528,7 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose) if (!serv) return 0; - spin_lock(&serv->sv_lock); + spin_lock_bh(&serv->sv_lock); list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) { int onelen = one_sock_name(buf+len, svsk); if (toclose && strcmp(toclose, buf+len) == 0) @@ -528,12 +536,12 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose) else len += onelen; } - spin_unlock(&serv->sv_lock); + spin_unlock_bh(&serv->sv_lock); if (closesk) /* Should unregister with portmap, but you cannot * unregister just one protocol... */ - svc_delete_socket(closesk); + svc_close_socket(closesk); else if (toclose) return -ENOENT; return len; @@ -683,6 +691,11 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) return svc_deferred_recv(rqstp); } + if (test_bit(SK_CLOSE, &svsk->sk_flags)) { + svc_delete_socket(svsk); + return 0; + } + clear_bit(SK_DATA, &svsk->sk_flags); while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) { if (err == -EAGAIN) { @@ -1176,7 +1189,8 @@ svc_tcp_sendto(struct svc_rqst *rqstp) rqstp->rq_sock->sk_server->sv_name, (sent<0)?"got error":"sent only", sent, xbufp->len); - svc_delete_socket(rqstp->rq_sock); + set_bit(SK_CLOSE, &rqstp->rq_sock->sk_flags); + svc_sock_enqueue(rqstp->rq_sock); sent = -EAGAIN; } return sent; @@ -1495,7 +1509,7 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock, svsk->sk_odata = inet->sk_data_ready; svsk->sk_owspace = inet->sk_write_space; svsk->sk_server = serv; - atomic_set(&svsk->sk_inuse, 0); + atomic_set(&svsk->sk_inuse, 1); svsk->sk_lastrecv = get_seconds(); spin_lock_init(&svsk->sk_defer_lock); INIT_LIST_HEAD(&svsk->sk_deferred); @@ -1618,7 +1632,7 @@ bummer: /* * Remove a dead socket */ -void +static void svc_delete_socket(struct svc_sock *svsk) { struct svc_serv *serv; @@ -1644,16 +1658,26 @@ svc_delete_socket(struct svc_sock *svsk) * while still attached to a queue, the queue itself * is about to be destroyed (in svc_destroy). */ - if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags)) + if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags)) { + BUG_ON(atomic_read(&svsk->sk_inuse)<2); + atomic_dec(&svsk->sk_inuse); if (test_bit(SK_TEMP, &svsk->sk_flags)) serv->sv_tmpcnt--; + } - /* This atomic_inc should be needed - svc_delete_socket - * should have the semantic of dropping a reference. - * But it doesn't yet.... - */ - atomic_inc(&svsk->sk_inuse); spin_unlock_bh(&serv->sv_lock); +} + +void svc_close_socket(struct svc_sock *svsk) +{ + set_bit(SK_CLOSE, &svsk->sk_flags); + if (test_and_set_bit(SK_BUSY, &svsk->sk_flags)) + /* someone else will have to effect the close */ + return; + + atomic_inc(&svsk->sk_inuse); + svc_delete_socket(svsk); + clear_bit(SK_BUSY, &svsk->sk_flags); svc_sock_put(svsk); } -- cgit v1.2.3 From da6e1a32fb8d7539a27f699c8671f64d7fefd0cc Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 8 Feb 2007 14:20:37 -0800 Subject: [PATCH] md: avoid possible BUG_ON in md bitmap handling md/bitmap tracks how many active write requests are pending on blocks associated with each bit in the bitmap, so that it knows when it can clear the bit (when count hits zero). The counter has 14 bits of space, so if there are ever more than 16383, we cannot cope. Currently the code just calles BUG_ON as "all" drivers have request queue limits much smaller than this. However is seems that some don't. Apparently some multipath configurations can allow more than 16383 concurrent write requests. So, in this unlikely situation, instead of calling BUG_ON we now wait for the count to drop down a bit. This requires a new wait_queue_head, some waiting code, and a wakeup call. Tested by limiting the counter to 20 instead of 16383 (writes go a lot slower in that case...). Signed-off-by: Neil Brown Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/bitmap.c | 22 +++++++++++++++++++++- include/linux/raid/bitmap.h | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 11108165e264..059704fbb753 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1160,6 +1160,22 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect return 0; } + if (unlikely((*bmc & COUNTER_MAX) == COUNTER_MAX)) { + DEFINE_WAIT(__wait); + /* note that it is safe to do the prepare_to_wait + * after the test as long as we do it before dropping + * the spinlock. + */ + prepare_to_wait(&bitmap->overflow_wait, &__wait, + TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&bitmap->lock); + bitmap->mddev->queue + ->unplug_fn(bitmap->mddev->queue); + schedule(); + finish_wait(&bitmap->overflow_wait, &__wait); + continue; + } + switch(*bmc) { case 0: bitmap_file_set_bit(bitmap, offset); @@ -1169,7 +1185,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect case 1: *bmc = 2; } - BUG_ON((*bmc & COUNTER_MAX) == COUNTER_MAX); + (*bmc)++; spin_unlock_irq(&bitmap->lock); @@ -1207,6 +1223,9 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto if (!success && ! (*bmc & NEEDED_MASK)) *bmc |= NEEDED_MASK; + if ((*bmc & COUNTER_MAX) == COUNTER_MAX) + wake_up(&bitmap->overflow_wait); + (*bmc)--; if (*bmc <= 2) { set_page_attr(bitmap, @@ -1431,6 +1450,7 @@ int bitmap_create(mddev_t *mddev) spin_lock_init(&bitmap->lock); atomic_set(&bitmap->pending_writes, 0); init_waitqueue_head(&bitmap->write_wait); + init_waitqueue_head(&bitmap->overflow_wait); bitmap->mddev = mddev; diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h index ebd42a3710b4..6db9a4c15355 100644 --- a/include/linux/raid/bitmap.h +++ b/include/linux/raid/bitmap.h @@ -247,6 +247,7 @@ struct bitmap { atomic_t pending_writes; /* pending writes to the bitmap file */ wait_queue_head_t write_wait; + wait_queue_head_t overflow_wait; }; -- cgit v1.2.3 From fa5dc22f8586cc3742413dd05f5cd9e039dfab9e Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 8 Feb 2007 14:20:41 -0800 Subject: [PATCH] Add install_special_mapping This patch adds a utility function install_special_mapping, for creating a special vma using a fixed set of preallocated pages as backing, such as for a vDSO. This consolidates some nearly identical code used for vDSO mapping reimplemented for different architectures. Signed-off-by: Roland McGrath Cc: Ingo Molnar Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 3 +++ mm/mmap.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index 2d2c08d5f473..bb793a4c8e9e 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1030,6 +1030,9 @@ extern struct vm_area_struct *copy_vma(struct vm_area_struct **, unsigned long addr, unsigned long len, pgoff_t pgoff); extern void exit_mmap(struct mm_struct *); extern int may_expand_vm(struct mm_struct *mm, unsigned long npages); +extern int install_special_mapping(struct mm_struct *mm, + unsigned long addr, unsigned long len, + unsigned long flags, struct page **pages); extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); diff --git a/mm/mmap.c b/mm/mmap.c index cc3a20819457..eb509ae76553 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2101,3 +2101,75 @@ int may_expand_vm(struct mm_struct *mm, unsigned long npages) return 0; return 1; } + + +static struct page *special_mapping_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + struct page **pages; + + BUG_ON(address < vma->vm_start || address >= vma->vm_end); + + address -= vma->vm_start; + for (pages = vma->vm_private_data; address > 0 && *pages; ++pages) + address -= PAGE_SIZE; + + if (*pages) { + struct page *page = *pages; + get_page(page); + return page; + } + + return NOPAGE_SIGBUS; +} + +/* + * Having a close hook prevents vma merging regardless of flags. + */ +static void special_mapping_close(struct vm_area_struct *vma) +{ +} + +static struct vm_operations_struct special_mapping_vmops = { + .close = special_mapping_close, + .nopage = special_mapping_nopage, +}; + +/* + * Called with mm->mmap_sem held for writing. + * Insert a new vma covering the given region, with the given flags. + * Its pages are supplied by the given array of struct page *. + * The array can be shorter than len >> PAGE_SHIFT if it's null-terminated. + * The region past the last page supplied will always produce SIGBUS. + * The array pointer and the pages it points to are assumed to stay alive + * for as long as this mapping might exist. + */ +int install_special_mapping(struct mm_struct *mm, + unsigned long addr, unsigned long len, + unsigned long vm_flags, struct page **pages) +{ + struct vm_area_struct *vma; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + if (unlikely(vma == NULL)) + return -ENOMEM; + + vma->vm_mm = mm; + vma->vm_start = addr; + vma->vm_end = addr + len; + + vma->vm_flags = vm_flags | mm->def_flags; + vma->vm_page_prot = protection_map[vma->vm_flags & 7]; + + vma->vm_ops = &special_mapping_vmops; + vma->vm_private_data = pages; + + if (unlikely(insert_vm_struct(mm, vma))) { + kmem_cache_free(vm_area_cachep, vma); + return -ENOMEM; + } + + mm->total_vm += len >> PAGE_SHIFT; + + return 0; +} -- cgit v1.2.3 From 9b13b682a68d5bcf09c75da73d4e61d92eba4c84 Mon Sep 17 00:00:00 2001 From: Alan Date: Thu, 7 Dec 2006 08:59:14 -0800 Subject: [PATCH] pata_it8213: Add new driver for the IT8213 card Add a driver for the IT8213 which is a single channel ICH-ish PATA controller. As it is very different to the IT8211/2 it gets its own driver. There is a legacy drivers/ide driver also available and I'll post that once I get time to test it all out (probably early January). If anyone else needs the drivers/ide driver and wants to do the merge for drivers/ide (Bart ??) then I'll forward it. [akpm@osdl.org: add PCI ID, constify needed_pio[]] Signed-off-by: Alan Cox Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 11 +- drivers/ata/Makefile | 1 + drivers/ata/pata_it8213.c | 354 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pci_ids.h | 1 + 4 files changed, 366 insertions(+), 1 deletion(-) create mode 100644 drivers/ata/pata_it8213.c (limited to 'include/linux') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 1c94b43d2c9b..afbd61575da6 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -296,7 +296,7 @@ config PATA_ISAPNP If unsure, say N. config PATA_IT821X - tristate "IT821x PATA support (Experimental)" + tristate "IT8211/2 PATA support (Experimental)" depends on PCI && EXPERIMENTAL help This option enables support for the ITE 8211 and 8212 @@ -305,6 +305,15 @@ config PATA_IT821X If unsure, say N. +config PATA_IT8213 + tristate "IT8213 PATA support (Experimental)" + depends on PCI && EXPERIMENTAL + help + This option enables support for the ITE 821 PATA + controllers via the new ATA layer. + + If unsure, say N. + config PATA_JMICRON tristate "JMicron PATA support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index bc3d81ae757e..50497ecc9b34 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o obj-$(CONFIG_PATA_HPT3X3) += pata_hpt3x3.o obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o obj-$(CONFIG_PATA_IT821X) += pata_it821x.o +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 diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c new file mode 100644 index 000000000000..7e9a41630e59 --- /dev/null +++ b/drivers/ata/pata_it8213.c @@ -0,0 +1,354 @@ +/* + * pata_it8213.c - iTE Tech. Inc. IT8213 PATA driver + * + * The IT8213 is a very Intel ICH like device for timing purposes, having + * a similar register layout and the same split clock arrangement. Cable + * detection is different, and it does not have slave channels or all the + * clutter of later ICH/SATA setups. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_it8213" +#define DRV_VERSION "0.0.2" + +/** + * it8213_pre_reset - check for 40/80 pin + * @ap: Port + * + * Perform cable detection for the 8213 ATA interface. This is + * different to the PIIX arrangement + */ + +static int it8213_pre_reset(struct ata_port *ap) +{ + static const struct pci_bits it8213_enable_bits[] = { + { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */ + }; + + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u8 tmp; + + if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no])) + return -ENOENT; + + pci_read_config_byte(pdev, 0x42, &tmp); + if (tmp & 2) /* The initial docs are incorrect */ + ap->cbl = ATA_CBL_PATA40; + else + ap->cbl = ATA_CBL_PATA80; + return ata_std_prereset(ap); +} + +/** + * it8213_probe_reset - Probe specified port on PATA host controller + * @ap: Port to probe + * + * LOCKING: + * None (inherited from caller). + */ + +static void it8213_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, it8213_pre_reset, ata_std_softreset, NULL, ata_std_postreset); +} + +/** + * it8213_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: um + * + * Set PIO mode for device, in host controller PCI config space. + * + * LOCKING: + * None (inherited from caller). + */ + +static void it8213_set_piomode (struct ata_port *ap, struct ata_device *adev) +{ + unsigned int pio = adev->pio_mode - XFER_PIO_0; + struct pci_dev *dev = to_pci_dev(ap->host->dev); + unsigned int idetm_port= ap->port_no ? 0x42 : 0x40; + u16 idetm_data; + int control = 0; + + /* + * See Intel Document 298600-004 for the timing programing rules + * for PIIX/ICH. The 8213 is a clone so very similar + */ + + static const /* ISP RTC */ + u8 timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + if (pio > 2) + control |= 1; /* TIME1 enable */ + if (ata_pio_need_iordy(adev)) /* PIO 3/4 require IORDY */ + control |= 2; /* IORDY enable */ + /* Bit 2 is set for ATAPI on the IT8213 - reverse of ICH/PIIX */ + if (adev->class != ATA_DEV_ATA) + control |= 4; + + pci_read_config_word(dev, idetm_port, &idetm_data); + + /* Enable PPE, IE and TIME as appropriate */ + + if (adev->devno == 0) { + idetm_data &= 0xCCF0; + idetm_data |= control; + idetm_data |= (timings[pio][0] << 12) | + (timings[pio][1] << 8); + } else { + u8 slave_data; + + idetm_data &= 0xCC0F; + idetm_data |= (control << 4); + + /* Slave timing in seperate register */ + pci_read_config_byte(dev, 0x44, &slave_data); + slave_data &= 0xF0; + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << 4; + pci_write_config_byte(dev, 0x44, slave_data); + } + + idetm_data |= 0x4000; /* Ensure SITRE is enabled */ + pci_write_config_word(dev, idetm_port, idetm_data); +} + +/** + * it8213_set_dmamode - Initialize host controller PATA DMA timings + * @ap: Port whose timings we are configuring + * @adev: Device to program + * + * Set UDMA/MWDMA mode for device, in host controller PCI config space. + * This device is basically an ICH alike. + * + * LOCKING: + * None (inherited from caller). + */ + +static void it8213_set_dmamode (struct ata_port *ap, struct ata_device *adev) +{ + struct pci_dev *dev = to_pci_dev(ap->host->dev); + u16 master_data; + u8 speed = adev->dma_mode; + int devid = adev->devno; + u8 udma_enable; + + static const /* ISP RTC */ + u8 timings[][2] = { { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + pci_read_config_word(dev, 0x40, &master_data); + pci_read_config_byte(dev, 0x48, &udma_enable); + + if (speed >= XFER_UDMA_0) { + unsigned int udma = adev->dma_mode - XFER_UDMA_0; + u16 udma_timing; + u16 ideconf; + int u_clock, u_speed; + + /* Clocks follow the PIIX style */ + u_speed = min(2 - (udma & 1), udma); + if (udma == 5) + u_clock = 0x1000; /* 100Mhz */ + else if (udma > 2) + u_clock = 1; /* 66Mhz */ + else + u_clock = 0; /* 33Mhz */ + + udma_enable |= (1 << devid); + + /* Load the UDMA mode number */ + pci_read_config_word(dev, 0x4A, &udma_timing); + udma_timing &= ~(3 << (4 * devid)); + udma_timing |= (udma & 3) << (4 * devid); + pci_write_config_word(dev, 0x4A, udma_timing); + + /* Load the clock selection */ + pci_read_config_word(dev, 0x54, &ideconf); + ideconf &= ~(0x1001 << devid); + ideconf |= u_clock << devid; + pci_write_config_word(dev, 0x54, ideconf); + } else { + /* + * MWDMA is driven by the PIO timings. We must also enable + * IORDY unconditionally along with TIME1. PPE has already + * been set when the PIO timing was set. + */ + unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0; + unsigned int control; + u8 slave_data; + static const unsigned int needed_pio[3] = { + XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 + }; + int pio = needed_pio[mwdma] - XFER_PIO_0; + + control = 3; /* IORDY|TIME1 */ + + /* If the drive MWDMA is faster than it can do PIO then + we must force PIO into PIO0 */ + + if (adev->pio_mode < needed_pio[mwdma]) + /* Enable DMA timing only */ + control |= 8; /* PIO cycles in PIO0 */ + + if (devid) { /* Slave */ + master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */ + master_data |= control << 4; + pci_read_config_byte(dev, 0x44, &slave_data); + slave_data &= (0x0F + 0xE1 * ap->port_no); + /* Load the matching timing */ + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0); + pci_write_config_byte(dev, 0x44, slave_data); + } else { /* Master */ + master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY + and master timing bits */ + master_data |= control; + master_data |= + (timings[pio][0] << 12) | + (timings[pio][1] << 8); + } + udma_enable &= ~(1 << devid); + pci_write_config_word(dev, 0x40, master_data); + } + pci_write_config_byte(dev, 0x48, udma_enable); +} + +static struct scsi_host_template it8213_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, + .max_sectors = ATA_MAX_SECTORS, + .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, + .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, +}; + +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, + + .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 = it8213_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .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 = ata_qc_issue_prot, + .data_xfer = ata_pio_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = ata_host_stop, +}; + + +/** + * it8213_init_one - Register 8213 ATA PCI device with kernel services + * @pdev: PCI device to register + * @ent: Entry in it8213_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 it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + static struct ata_port_info info = { + .sht = &it8213_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x1f, /* UDMA 100 */ + .port_ops = &it8213_ops, + }; + static struct ata_port_info *port_info[2] = { &info, &info }; + + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); + + /* Current IT8213 stuff is single port */ + return ata_pci_init_one(pdev, port_info, 1); +} + +static const struct pci_device_id it8213_pci_tbl[] = { + { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8213), }, + + { } /* terminate list */ +}; + +static struct pci_driver it8213_pci_driver = { + .name = DRV_NAME, + .id_table = it8213_pci_tbl, + .probe = it8213_init_one, + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +}; + +static int __init it8213_init(void) +{ + return pci_register_driver(&it8213_pci_driver); +} + +static void __exit it8213_exit(void) +{ + pci_unregister_driver(&it8213_pci_driver); +} + +module_init(it8213_init); +module_exit(it8213_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("SCSI low-level driver for the ITE 8213"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, it8213_pci_tbl); +MODULE_VERSION(DRV_VERSION); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6252cb9092dd..4c8966a082af 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1633,6 +1633,7 @@ #define PCI_VENDOR_ID_ITE 0x1283 #define PCI_DEVICE_ID_ITE_8211 0x8211 #define PCI_DEVICE_ID_ITE_8212 0x8212 +#define PCI_DEVICE_ID_ITE_8213 0x8213 #define PCI_DEVICE_ID_ITE_8872 0x8872 #define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886 -- cgit v1.2.3 From f20b16ff7c19d1c369ee07470952aca093551ed0 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Mon, 11 Dec 2006 11:14:06 -0500 Subject: [libata] trim trailing whitespace Most of these contributed by that mysterious figger known as A.C. Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 2 +- drivers/ata/libata-core.c | 2 +- drivers/ata/pata_ali.c | 4 ++-- drivers/ata/pata_cs5520.c | 2 +- drivers/ata/pata_cs5530.c | 8 ++++---- drivers/ata/pata_hpt366.c | 2 +- drivers/ata/pata_hpt37x.c | 4 ++-- drivers/ata/pata_hpt3x3.c | 2 +- drivers/ata/pata_jmicron.c | 2 +- drivers/ata/pata_marvell.c | 4 ++-- drivers/ata/pata_serverworks.c | 2 +- drivers/ata/pata_sil680.c | 2 +- drivers/ata/pata_sis.c | 2 +- drivers/ata/pata_via.c | 10 +++++----- drivers/ata/pata_winbond.c | 16 ++++++++-------- drivers/ata/sata_nv.c | 18 +++++++++--------- drivers/ata/sata_sis.c | 2 +- drivers/ata/sata_via.c | 2 +- include/linux/libata.h | 2 +- 19 files changed, 44 insertions(+), 44 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 47701b286f8b..7959e4c9f13b 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -632,7 +632,7 @@ static int piix_pata_prereset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) return -ENOENT; - + ap->cbl = ATA_CBL_PATA40; return ata_std_prereset(ap); } diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 667acd283364..e267319bb2b1 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5770,7 +5770,7 @@ int ata_device_add(const struct ata_probe_ent *ent) int rc; DPRINTK("ENTER\n"); - + if (ent->irq == 0) { dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n"); return 0; diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index c5d61d1911a5..2035417fc1ab 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -504,7 +504,7 @@ static struct ata_port_operations ali_c5_port_ops = { * Perform the setup on the device that must be done both at boot * and at resume time. */ - + static void ali_init_chipset(struct pci_dev *pdev) { u8 rev, tmp; @@ -655,7 +655,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) port_info[0] = port_info[1] = &info_c5; ali_init_chipset(pdev); - + isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); if (isa_bridge && rev >= 0x20 && rev < 0xC2) { /* Are we paired with a UDMA capable chip */ diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 9f165a8e032d..476b87963f5d 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -305,7 +305,7 @@ static void __devexit cs5520_remove_one(struct pci_dev *pdev) * Do any reconfiguration work needed by a resume from RAM. We need * to restore DMA mode support on BIOSen which disabled it */ - + static int cs5520_reinit_one(struct pci_dev *pdev) { u8 pcicfg; diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index b1ca207e3545..611d90f0d3bc 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -247,7 +247,7 @@ static int cs5530_is_palmax(void) * Perform the chip initialisation work that is shared between both * setup and resume paths */ - + static int cs5530_init_chip(void) { struct pci_dev *master_0 = NULL, *cs5530_0 = NULL, *dev = NULL; @@ -357,11 +357,11 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &cs5530_port_ops }; static struct ata_port_info *port_info[2] = { &info, &info }; - + /* Chip initialisation */ if (cs5530_init_chip()) return -ENODEV; - + if (cs5530_is_palmax()) port_info[1] = &info_palmax_secondary; @@ -376,7 +376,7 @@ static int cs5530_reinit_one(struct pci_dev *pdev) BUG(); return ata_pci_device_resume(pdev); } - + static const struct pci_device_id cs5530[] = { { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), }, diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 2663599a7c02..8cf167e59dee 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -232,7 +232,7 @@ static int hpt36x_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &hpt36x_enable_bits[ap->port_no])) return -ENOENT; - + pci_read_config_byte(pdev, 0x5A, &ata66); if (ata66 & (1 << ap->port_no)) ap->cbl = ATA_CBL_PATA40; diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index dfb306057cf4..3ad0e51cb2ab 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -459,7 +459,7 @@ static int hpt37x_pre_reset(struct ata_port *ap) }; if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no])) return -ENOENT; - + pci_read_config_byte(pdev, 0x5B, &scr2); pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01); /* Cable register now active */ @@ -504,7 +504,7 @@ static int hpt374_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no])) return -ENOENT; - + /* Do the extra channel work */ pci_read_config_word(pdev, 0x52, &mcr3); pci_read_config_word(pdev, 0x56, &mcr6); diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index 5f1d385eb592..5caf167e26de 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -164,7 +164,7 @@ static struct ata_port_operations hpt3x3_port_ops = { * * Perform the setup required at boot and on resume. */ - + static void hpt3x3_init_chipset(struct pci_dev *dev) { u16 cmd; diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index d50264af2848..aaf6787f5342 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -221,7 +221,7 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i static int jmicron_reinit_one(struct pci_dev *pdev) { u32 reg; - + switch(pdev->device) { case PCI_DEVICE_ID_JMICRON_JMB368: break; diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 1c810ea00253..af93533551ac 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -45,10 +45,10 @@ static int marvell_pre_reset(struct ata_port *ap) for(i = 0; i <= 0x0F; i++) printk("%02X:%02X ", i, readb(barp + i)); printk("\n"); - + devices = readl(barp + 0x0C); pci_iounmap(pdev, barp); - + if ((pdev->device == 0x6145) && (ap->port_no == 0) && (!(devices & 0x10))) /* PATA enable ? */ return -ENOENT; diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index f02b6a3b0f10..80191978d481 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -559,7 +559,7 @@ static int serverworks_reinit_one(struct pci_dev *pdev) { /* Force master latency timer to 64 PCI clocks */ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); - + switch (pdev->device) { case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE: diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index e8dfd8fc3ff7..11da1f5271d5 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -270,7 +270,7 @@ static struct ata_port_operations sil680_port_ops = { * is powered up on boot and when we resume in case we resumed from RAM. * Returns the final clock settings. */ - + static u8 sil680_init_chip(struct pci_dev *pdev) { u32 class_rev = 0; diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 916cedb3d755..c434c4ef4e4b 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -847,7 +847,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) struct sis_chipset *chipset = NULL; static struct sis_chipset sis_chipsets[] = { - + { 0x0968, &sis_info133 }, { 0x0966, &sis_info133 }, { 0x0965, &sis_info133 }, diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index f0b6c3b71429..2addce11000a 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -391,11 +391,11 @@ static struct ata_port_operations via_port_ops_noirq = { static void via_config_fifo(struct pci_dev *pdev, unsigned int flags) { u8 enable; - + /* 0x40 low bits indicate enabled channels */ pci_read_config_byte(pdev, 0x40 , &enable); enable &= 3; - + if (flags & VIA_SET_FIFO) { static const u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20}; u8 fifo; @@ -516,7 +516,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) /* Initialise the FIFO for the enabled channels. */ via_config_fifo(pdev, config->flags); - + /* Clock set up */ switch(config->flags & VIA_UDMA) { case VIA_UDMA_NONE: @@ -575,7 +575,7 @@ static int via_reinit_one(struct pci_dev *pdev) u32 timing; struct ata_host *host = dev_get_drvdata(&pdev->dev); const struct via_isa_bridge *config = host->private_data; - + via_config_fifo(pdev, config->flags); if ((config->flags & VIA_UDMA) == VIA_UDMA_66) { @@ -590,7 +590,7 @@ static int via_reinit_one(struct pci_dev *pdev) timing &= ~0x80008; pci_write_config_dword(pdev, 0x50, timing); } - return ata_pci_device_resume(pdev); + return ata_pci_device_resume(pdev); } static const struct pci_device_id via[] = { diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 5d1f518e1cc7..022da95a3389 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -5,7 +5,7 @@ * Support for the Winbond 83759A when operating in advanced mode. * Multichip mode is not currently supported. */ - + #include #include #include @@ -69,7 +69,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2); reg = winbond_readcfg(winbond->config, 0x81); - + /* Get the timing data in cycles */ if (reg & 0x40) /* Fast VLB bus, assume 50MHz */ ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); @@ -80,9 +80,9 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F; timing = (active << 4) | recovery; winbond_writecfg(winbond->config, timing, reg); - + /* Load the setup timing */ - + reg = 0x35; if (adev->class != ATA_DEV_ATA) reg |= 0x08; /* FIFO off */ @@ -194,13 +194,13 @@ static __init int winbond_init_one(unsigned long port) winbond_writecfg(port, 0x85, reg); reg = winbond_readcfg(port, 0x81); - + if (!(reg & 0x03)) /* Disabled */ return 0; for (i = 0; i < 2 ; i ++) { - if (reg & (1 << i)) { + if (reg & (1 << i)) { /* * Fill in a probe structure first of all */ @@ -217,7 +217,7 @@ static __init int winbond_init_one(unsigned long port) ae.pio_mask = 0x1F; ae.sht = &winbond_sht; - + ae.n_ports = 1; ae.irq = 14 + i; ae.irq_flags = 0; @@ -257,7 +257,7 @@ static __init int winbond_init(void) int ct = 0; int i; - + if (probe_winbond == 0) return -ENODEV; diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index f7a963eb1f02..cbca983165de 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -528,7 +528,7 @@ static void nv_adma_mode(struct ata_port *ap) if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) return; - + WARN_ON(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE); tmp = readw(mmio + NV_ADMA_CTL); @@ -568,7 +568,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev) /* Subtract 1 since an extra entry may be needed for padding, see libata-scsi.c */ sg_tablesize = LIBATA_MAX_PRD - 1; - + /* Since the legacy DMA engine is in use, we need to disable ADMA on the port. */ adma_enable = 0; @@ -580,7 +580,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev) sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN; adma_enable = 1; } - + pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, ¤t_reg); if(ap->port_no == 1) @@ -589,7 +589,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev) else config_mask = NV_MCP_SATA_CFG_20_PORT0_EN | NV_MCP_SATA_CFG_20_PORT0_PWB_EN; - + if(adma_enable) { new_reg = current_reg | config_mask; pp->flags &= ~NV_ADMA_ATAPI_SETUP_COMPLETE; @@ -598,10 +598,10 @@ static int nv_adma_slave_config(struct scsi_device *sdev) new_reg = current_reg & ~config_mask; pp->flags |= NV_ADMA_ATAPI_SETUP_COMPLETE; } - + if(current_reg != new_reg) pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, new_reg); - + blk_queue_bounce_limit(sdev->request_queue, bounce_limit); blk_queue_segment_boundary(sdev->request_queue, segment_boundary); blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize); @@ -812,13 +812,13 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) handled++; /* irq handled if we got here */ } } - + if(notifier_clears[0] || notifier_clears[1]) { /* Note: Both notifier clear registers must be written if either is set, even if one is zero, according to NVIDIA. */ - writel(notifier_clears[0], + writel(notifier_clears[0], nv_adma_notifier_clear_block(host->ports[0])); - writel(notifier_clears[1], + writel(notifier_clears[1], nv_adma_notifier_clear_block(host->ports[1])); } diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index c1e32194b09f..c90fb1319dfe 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -311,7 +311,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) pi.flags |= ATA_FLAG_SLAVE_POSS; } break; - + case 0x0182: case 0x0183: pci_read_config_dword ( pdev, 0x6C, &val); diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index d3d5c0d57032..038d49d0f2ab 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -330,7 +330,7 @@ static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev) { struct ata_probe_ent *probe_ent; struct ata_port_info *ppi[2]; - + ppi[0] = ppi[1] = &vt6420_port_info; probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) diff --git a/include/linux/libata.h b/include/linux/libata.h index 91bb8ceef0b5..84f12e8cae71 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -308,7 +308,7 @@ enum { * most devices. */ ATA_SPINUP_WAIT = 8000, - + /* Horkage types. May be set by libata or controller on drives (some horkage may be drive/controller pair dependant */ -- cgit v1.2.3 From d4013f07bd5380178bf28ef1cd76649779367288 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 15 Dec 2006 13:08:50 -0800 Subject: [PATCH] pci: Move PCI_VDEVICE from libata to core Updated diff which doesn't move the comment as per Jeff's request and corrects the docs as per report on l/k Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- include/linux/libata.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/libata.h b/include/linux/libata.h index 84f12e8cae71..dab4dc505ce7 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -109,10 +109,6 @@ static inline u32 ata_msg_init(int dval, int default_msg_enable_bits) #define ATA_TAG_POISON 0xfafbfcfdU /* move to PCI layer? */ -#define PCI_VDEVICE(vendor, device) \ - PCI_VENDOR_ID_##vendor, (device), \ - PCI_ANY_ID, PCI_ANY_ID, 0, 0 - static inline struct device *pci_dev_to_dev(struct pci_dev *pdev) { return &pdev->dev; -- cgit v1.2.3 From c9f89475a5b184e9a6077b995ce340e6804c1b1a Mon Sep 17 00:00:00 2001 From: Conke Hu Date: Tue, 9 Jan 2007 05:32:51 -0500 Subject: Add pci class code for SATA & AHCI, and replace some magic numbers. Signed-off-by: Conke Hu Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 8 ++++---- drivers/pci/quirks.c | 2 +- include/linux/pci_ids.h | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index e2796fb40eb7..32cfaa89dc7c 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -431,7 +431,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { /* Generic, PCI class code for AHCI */ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, - 0x010601, 0xffffff, board_ahci }, + PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, { } /* terminate list */ }; @@ -1619,11 +1619,11 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent) speed_s = "?"; pci_read_config_word(pdev, 0x0a, &cc); - if (cc == 0x0101) + if (cc == PCI_CLASS_STORAGE_IDE) scc_s = "IDE"; - else if (cc == 0x0106) + else if (cc == PCI_CLASS_STORAGE_SATA) scc_s = "SATA"; - else if (cc == 0x0104) + else if (cc == PCI_CLASS_STORAGE_RAID) scc_s = "RAID"; else scc_s = "unknown"; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 11217bda4b9e..1e6eda25c0d8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -871,7 +871,7 @@ static void __devinit quirk_sb600_sata(struct pci_dev *pdev) pci_write_config_byte(pdev, 0xa, 6); pci_write_config_byte(pdev, 0x40, tmp); - pdev->class = 0x010601; + pdev->class = PCI_CLASS_STORAGE_SATA_AHCI; } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_sb600_sata); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 4c8966a082af..e67b68ca235a 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -15,6 +15,8 @@ #define PCI_CLASS_STORAGE_FLOPPY 0x0102 #define PCI_CLASS_STORAGE_IPI 0x0103 #define PCI_CLASS_STORAGE_RAID 0x0104 +#define PCI_CLASS_STORAGE_SATA 0x0106 +#define PCI_CLASS_STORAGE_SATA_AHCI 0x010601 #define PCI_CLASS_STORAGE_SAS 0x0107 #define PCI_CLASS_STORAGE_OTHER 0x0180 -- cgit v1.2.3 From a0cf733b333eeeafb7324e2897448006c693c26c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 2 Jan 2007 20:18:49 +0900 Subject: libata: straighten out ATA_ID_* constants * Kill _OFS suffixes in ATA_ID_{SERNO|FW_REV|PROD}_OFS for consistency with other ATA_ID_* constants. * Kill ATA_SERNO_LEN * Add and use ATA_ID_SERNO_LEN, ATA_ID_FW_REV_LEN and ATA_ID_PROD_LEN. This change also makes ata_device_blacklisted() use proper length for fwrev. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 21 ++++++++++----------- drivers/ata/libata-scsi.c | 33 ++++++++++++++++----------------- drivers/ata/pata_ali.c | 4 ++-- drivers/ata/pata_hpt366.c | 4 ++-- drivers/ata/pata_hpt37x.c | 5 ++--- drivers/ata/pata_it821x.c | 5 ++--- drivers/ata/pata_serverworks.c | 4 ++-- drivers/ata/sata_sil.c | 4 ++-- include/linux/ata.h | 11 +++++++---- 9 files changed, 45 insertions(+), 46 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 2869469790b0..7d4b002568e7 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3187,7 +3187,8 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, const u16 *new_id) { const u16 *old_id = dev->id; - unsigned char model[2][41], serial[2][21]; + unsigned char model[2][ATA_ID_PROD_LEN + 1]; + unsigned char serial[2][ATA_ID_SERNO_LEN + 1]; u64 new_n_sectors; if (dev->class != new_class) { @@ -3196,10 +3197,10 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class, return 0; } - ata_id_c_string(old_id, model[0], ATA_ID_PROD_OFS, sizeof(model[0])); - ata_id_c_string(new_id, model[1], ATA_ID_PROD_OFS, sizeof(model[1])); - ata_id_c_string(old_id, serial[0], ATA_ID_SERNO_OFS, sizeof(serial[0])); - ata_id_c_string(new_id, serial[1], ATA_ID_SERNO_OFS, sizeof(serial[1])); + ata_id_c_string(old_id, model[0], ATA_ID_PROD, sizeof(model[0])); + ata_id_c_string(new_id, model[1], ATA_ID_PROD, sizeof(model[1])); + ata_id_c_string(old_id, serial[0], ATA_ID_SERNO, sizeof(serial[0])); + ata_id_c_string(new_id, serial[1], ATA_ID_SERNO, sizeof(serial[1])); new_n_sectors = ata_id_n_sectors(new_id); if (strcmp(model[0], model[1])) { @@ -3338,15 +3339,13 @@ static int ata_strim(char *s, size_t len) unsigned long ata_device_blacklisted(const struct ata_device *dev) { - unsigned char model_num[40]; - unsigned char model_rev[16]; + unsigned char model_num[ATA_ID_PROD_LEN]; + unsigned char model_rev[ATA_ID_FW_REV_LEN]; unsigned int nlen, rlen; const struct ata_blacklist_entry *ad = ata_device_blacklist; - ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, - sizeof(model_num)); - ata_id_string(dev->id, model_rev, ATA_ID_FW_REV_OFS, - sizeof(model_rev)); + ata_id_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); + ata_id_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); nlen = ata_strim(model_num, sizeof(model_num)); rlen = ata_strim(model_rev, sizeof(model_rev)); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 57111f842d66..6a99c0824751 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1698,8 +1698,8 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, if (buflen > 35) { memcpy(&rbuf[8], "ATA ", 8); - ata_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16); - ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4); + ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); + ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); if (rbuf[32] == 0 || rbuf[32] == ' ') memcpy(&rbuf[32], "n/a ", 4); } @@ -1768,13 +1768,13 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, 0, 0x80, /* this page code */ 0, - ATA_SERNO_LEN, /* page len */ + ATA_ID_SERNO_LEN, /* page len */ }; memcpy(rbuf, hdr, sizeof(hdr)); - if (buflen > (ATA_SERNO_LEN + 4 - 1)) + if (buflen > (ATA_ID_SERNO_LEN + 4 - 1)) ata_id_string(args->id, (unsigned char *) &rbuf[4], - ATA_ID_SERNO_OFS, ATA_SERNO_LEN); + ATA_ID_SERNO, ATA_ID_SERNO_LEN); return 0; } @@ -1799,19 +1799,18 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, { int num; const int sat_model_serial_desc_len = 68; - const int ata_model_byte_len = 40; rbuf[1] = 0x83; /* this page code */ num = 4; - if (buflen > (ATA_SERNO_LEN + num + 3)) { + if (buflen > (ATA_ID_SERNO_LEN + num + 3)) { /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */ rbuf[num + 0] = 2; - rbuf[num + 3] = ATA_SERNO_LEN; + rbuf[num + 3] = ATA_ID_SERNO_LEN; num += 4; ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_SERNO_OFS, ATA_SERNO_LEN); - num += ATA_SERNO_LEN; + ATA_ID_SERNO, ATA_ID_SERNO_LEN); + num += ATA_ID_SERNO_LEN; } if (buflen > (sat_model_serial_desc_len + num + 3)) { /* SAT defined lu model and serial numbers descriptor */ @@ -1823,11 +1822,11 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, memcpy(rbuf + num, "ATA ", 8); num += 8; ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_PROD_OFS, ata_model_byte_len); - num += ata_model_byte_len; + ATA_ID_PROD, ATA_ID_PROD_LEN); + num += ATA_ID_PROD_LEN; ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_SERNO_OFS, ATA_SERNO_LEN); - num += ATA_SERNO_LEN; + ATA_ID_SERNO, ATA_ID_SERNO_LEN); + num += ATA_ID_SERNO_LEN; } rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */ return 0; @@ -1955,15 +1954,15 @@ static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) */ static int ata_dev_supports_fua(u16 *id) { - unsigned char model[41], fw[9]; + unsigned char model[ATA_ID_PROD_LEN + 1], fw[ATA_ID_FW_REV_LEN + 1]; if (!libata_fua) return 0; if (!ata_id_has_fua(id)) return 0; - ata_id_c_string(id, model, ATA_ID_PROD_OFS, sizeof(model)); - ata_id_c_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw)); + ata_id_c_string(id, model, ATA_ID_PROD, sizeof(model)); + ata_id_c_string(id, fw, ATA_ID_FW_REV, sizeof(fw)); if (strcmp(model, "Maxtor")) return 1; diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 2035417fc1ab..76e386043dcd 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -153,11 +153,11 @@ static void ali_early_error_handler(struct ata_port *ap) static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask) { - char model_num[40]; + char model_num[ATA_ID_PROD_LEN]; /* No DMA on anything but a disk for now */ if (adev->class != ATA_DEV_ATA) mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); - ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); + ata_id_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num)); if (strstr(model_num, "WDC")) return mask &= ~ATA_MASK_UDMA; return ata_pci_default_filter(ap, adev, mask); diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 8cf167e59dee..81deb2c3824c 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -151,12 +151,12 @@ static const char *bad_ata66_3[] = { static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[]) { - unsigned char model_num[40]; + unsigned char model_num[ATA_ID_PROD_LEN]; char *s; unsigned int len; int i = 0; - ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); + ata_id_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); s = &model_num[0]; len = strnlen(s, sizeof(model_num)); diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 3ad0e51cb2ab..ff767755e98b 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -349,13 +349,12 @@ static u32 hpt37x_find_mode(struct ata_port *ap, int speed) static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[]) { - unsigned char model_num[40]; + unsigned char model_num[ATA_ID_PROD_LEN]; char *s; unsigned int len; int i = 0; - ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, - sizeof(model_num)); + ata_id_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); s = &model_num[0]; len = strnlen(s, sizeof(model_num)); diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index e8afd486434a..c84dfaede89c 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -531,15 +531,14 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused static void it821x_dev_config(struct ata_port *ap, struct ata_device *adev) { - unsigned char model_num[40]; + unsigned char model_num[ATA_ID_PROD_LEN]; char *s; unsigned int len; /* This block ought to be a library routine as it is in several drivers now */ - ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, - sizeof(model_num)); + ata_id_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num)); s = &model_num[0]; len = strnlen(s, sizeof(model_num)); diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 80191978d481..bf9452728d19 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -218,7 +218,7 @@ static unsigned long serverworks_osb4_filter(const struct ata_port *ap, struct a static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask) { const char *p; - char model_num[40]; + char model_num[ATA_ID_PROD_LEN]; int len, i; /* Disk, UDMA */ @@ -226,7 +226,7 @@ static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct at return ata_pci_default_filter(ap, adev, mask); /* Actually do need to check */ - ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); + ata_id_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num)); /* Precuationary - why not do this in the libata core ?? */ len = strlen(model_num); diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 7808d0369d91..d27ab312cdfb 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -541,9 +541,9 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) { int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO; unsigned int n, quirks = 0; - unsigned char model_num[41]; + unsigned char model_num[ATA_ID_PROD_LEN + 1]; - ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num)); + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); for (n = 0; sil_blacklist[n].product; n++) if (!strcmp(sil_blacklist[n].product, model_num)) { diff --git a/include/linux/ata.h b/include/linux/ata.h index 1df941648a57..3a50739e25a6 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -44,9 +44,9 @@ enum { ATA_MAX_SECTORS_LBA48 = 65535,/* TODO: 65536? */ ATA_ID_WORDS = 256, - ATA_ID_SERNO_OFS = 10, - ATA_ID_FW_REV_OFS = 23, - ATA_ID_PROD_OFS = 27, + ATA_ID_SERNO = 10, + ATA_ID_FW_REV = 23, + ATA_ID_PROD = 27, ATA_ID_OLD_PIO_MODES = 51, ATA_ID_FIELD_VALID = 53, ATA_ID_MWDMA_MODES = 63, @@ -58,8 +58,11 @@ enum { ATA_ID_MAJOR_VER = 80, ATA_ID_PIO4 = (1 << 1), + ATA_ID_SERNO_LEN = 20, + ATA_ID_FW_REV_LEN = 8, + ATA_ID_PROD_LEN = 40, + ATA_PCI_CTL_OFS = 2, - ATA_SERNO_LEN = 20, ATA_UDMA0 = (1 << 0), ATA_UDMA1 = ATA_UDMA0 | (1 << 1), ATA_UDMA2 = ATA_UDMA1 | (1 << 2), -- cgit v1.2.3 From 553c4aa630af7bc885e056d0436e4eb7f238579b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 26 Dec 2006 19:39:50 +0900 Subject: libata: handle pci_enable_device() failure while resuming Handle pci_enable_device() failure while resuming. This patch kills the "ignoring return value of 'pci_enable_device'" warning message and propagates __must_check through ata_pci_device_do_resume(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 4 +++- drivers/ata/libata-core.c | 22 +++++++++++++++++----- drivers/ata/sata_sil.c | 6 +++++- drivers/ata/sata_sil24.c | 5 ++++- include/linux/libata.h | 2 +- 5 files changed, 30 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index ca53d5a9c0c5..03b7a0051887 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1397,7 +1397,9 @@ static int ahci_pci_device_resume(struct pci_dev *pdev) void __iomem *mmio = host->mmio_base; int rc; - ata_pci_device_do_resume(pdev); + rc = ata_pci_device_do_resume(pdev); + if (rc) + return rc; if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { rc = ahci_reset_controller(mmio, pdev); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index a03019c40ac4..89f3cf57b677 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6196,12 +6196,22 @@ void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg) } } -void ata_pci_device_do_resume(struct pci_dev *pdev) +int ata_pci_device_do_resume(struct pci_dev *pdev) { + int rc; + pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - pci_enable_device(pdev); + + rc = pci_enable_device(pdev); + if (rc) { + dev_printk(KERN_ERR, &pdev->dev, + "failed to enable device after resume (%d)\n", rc); + return rc; + } + pci_set_master(pdev); + return 0; } int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) @@ -6221,10 +6231,12 @@ int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) int ata_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); + int rc; - ata_pci_device_do_resume(pdev); - ata_host_resume(host); - return 0; + rc = ata_pci_device_do_resume(pdev); + if (rc == 0) + ata_host_resume(host); + return rc; } #endif /* CONFIG_PCI */ diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index d27ab312cdfb..1f3fdcf29876 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -710,8 +710,12 @@ err_out: static int sil_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); + int rc; + + rc = ata_pci_device_do_resume(pdev); + if (rc) + return rc; - ata_pci_device_do_resume(pdev); sil_init_controller(pdev, host->n_ports, host->ports[0]->flags, host->mmio_base); ata_host_resume(host); diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 5aa288d2fb86..da982ed4bc47 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -1200,8 +1200,11 @@ static int sil24_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); struct sil24_host_priv *hpriv = host->private_data; + int rc; - ata_pci_device_do_resume(pdev); + rc = ata_pci_device_do_resume(pdev); + if (rc) + return rc; if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL); diff --git a/include/linux/libata.h b/include/linux/libata.h index dab4dc505ce7..a8ecaaad55ff 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -716,7 +716,7 @@ extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_i unsigned int n_ports); extern void ata_pci_remove_one (struct pci_dev *pdev); extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg); -extern void ata_pci_device_do_resume(struct pci_dev *pdev); +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); extern int ata_pci_clear_simplex(struct pci_dev *pdev); -- cgit v1.2.3 From 726f0785b608d09bdd64bdbadc09217ebbf9920e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 3 Jan 2007 17:30:39 +0900 Subject: libata: kill qc->nsect and cursect libata used two separate sets of variables to record request size and current offset for ATA and ATAPI. This is confusing and fragile. This patch replaces qc->nsect/cursect with qc->nbytes/curbytes and kills them. Also, ata_pio_sector() is updated to use bytes for qc->cursg_ofs instead of sectors. The field used to be used in bytes for ATAPI and in sectors for ATA. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 14 +++++++------- drivers/ata/libata-eh.c | 7 +------ drivers/ata/libata-scsi.c | 4 ++-- drivers/ata/pata_pdc202xx_old.c | 5 +---- drivers/ata/sata_qstor.c | 2 +- include/linux/libata.h | 6 +----- 6 files changed, 13 insertions(+), 25 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 89f3cf57b677..c1444d8f92c6 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1249,7 +1249,6 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, buflen += sg[i].length; ata_sg_init(qc, sg, n_elem); - qc->nsect = buflen / ATA_SECT_SIZE; qc->nbytes = buflen; } @@ -4006,11 +4005,11 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) unsigned int offset; unsigned char *buf; - if (qc->cursect == (qc->nsect - 1)) + if (qc->curbytes == qc->nbytes - ATA_SECT_SIZE) ap->hsm_task_state = HSM_ST_LAST; page = sg[qc->cursg].page; - offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE; + offset = sg[qc->cursg].offset + qc->cursg_ofs; /* get the current page and offset */ page = nth_page(page, (offset >> PAGE_SHIFT)); @@ -4035,10 +4034,10 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write); } - qc->cursect++; - qc->cursg_ofs++; + qc->curbytes += ATA_SECT_SIZE; + qc->cursg_ofs += ATA_SECT_SIZE; - if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) { + if (qc->cursg_ofs == (&sg[qc->cursg])->length) { qc->cursg++; qc->cursg_ofs = 0; } @@ -4063,7 +4062,8 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc) WARN_ON(qc->dev->multi_count == 0); - nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count); + nsect = min((qc->nbytes - qc->curbytes) / ATA_SECT_SIZE, + qc->dev->multi_count); while (nsect--) ata_pio_sector(qc); } else diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 748435807d68..52c85af7fe99 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1443,15 +1443,10 @@ 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; - unsigned int nbytes; if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask) continue; - nbytes = qc->nbytes; - if (!nbytes) - nbytes = qc->nsect << 9; - ata_dev_printk(qc->dev, KERN_ERR, "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x " "tag %d cdb 0x%x data %u %s\n " @@ -1461,7 +1456,7 @@ static void ata_eh_report(struct ata_port *ap) cmd->lbal, cmd->lbam, cmd->lbah, cmd->hob_feature, cmd->hob_nsect, cmd->hob_lbal, cmd->hob_lbam, cmd->hob_lbah, - cmd->device, qc->tag, qc->cdb[0], nbytes, + cmd->device, qc->tag, qc->cdb[0], qc->nbytes, dma_str[qc->dma_dir], res->command, res->feature, res->nsect, res->lbal, res->lbam, res->lbah, diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 6a99c0824751..9b5088ab2742 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1359,7 +1359,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc) goto nothing_to_do; qc->flags |= ATA_QCFLAG_IO; - qc->nsect = n_block; + qc->nbytes = n_block * ATA_SECT_SIZE; rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags, qc->tag); @@ -2660,7 +2660,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->nsect = scmd->request_bufflen / ATA_SECT_SIZE; + qc->nbytes = scmd->request_bufflen; /* request result TF */ qc->flags |= ATA_QCFLAG_RESULT_TF; diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index ad691b9e7743..ba982ba68ad5 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -189,10 +189,7 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) /* Cases the state machine will not complete correctly without help */ if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATA_PROT_ATAPI_DMA) { - if (tf->flags & ATA_TFLAG_LBA48) - len = qc->nsect * 512; - else - len = qc->nbytes; + len = qc->nbytes; if (tf->flags & ATA_TFLAG_WRITE) len |= 0x06000000; diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 710909df4eaf..0292a79f9747 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -325,7 +325,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc) /* host control block (HCB) */ buf[ 0] = QS_HCB_HDR; buf[ 1] = hflags; - *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE); + *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nbytes); *(__le32 *)(&buf[ 8]) = cpu_to_le32(nelem); addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES; *(__le64 *)(&buf[16]) = cpu_to_le64(addr); diff --git a/include/linux/libata.h b/include/linux/libata.h index a8ecaaad55ff..a2458dfefb17 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -427,9 +427,6 @@ struct ata_queued_cmd { unsigned int pad_len; - unsigned int nsect; - unsigned int cursect; - unsigned int nbytes; unsigned int curbytes; @@ -1145,8 +1142,7 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) qc->dma_dir = DMA_NONE; qc->__sg = NULL; qc->flags = 0; - qc->cursect = qc->cursg = qc->cursg_ofs = 0; - qc->nsect = 0; + qc->cursg = qc->cursg_ofs = 0; qc->nbytes = qc->curbytes = 0; qc->n_elem = 0; qc->err_mask = 0; -- cgit v1.2.3 From 9ac7849e35f705830f7b016ff272b0ff1f7ff759 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 20 Jan 2007 16:00:26 +0900 Subject: devres: device resource management Implement device resource management, in short, devres. A device driver can allocate arbirary size of devres data which is associated with a release function. On driver detach, release function is invoked on the devres data, then, devres data is freed. devreses are typed by associated release functions. Some devreses are better represented by single instance of the type while others need multiple instances sharing the same release function. Both usages are supported. devreses can be grouped using devres group such that a device driver can easily release acquired resources halfway through initialization or selectively release resources (e.g. resources for port 1 out of 4 ports). This patch adds devres core including documentation and the following managed interfaces. * alloc/free : devm_kzalloc(), devm_kzfree() * IO region : devm_request_region(), devm_release_region() * IRQ : devm_request_irq(), devm_free_irq() * DMA : dmam_alloc_coherent(), dmam_free_coherent(), dmam_declare_coherent_memory(), dmam_pool_create(), dmam_pool_destroy() * PCI : pcim_enable_device(), pcim_pin_device(), pci_is_managed() * iomap : devm_ioport_map(), devm_ioport_unmap(), devm_ioremap(), devm_ioremap_nocache(), devm_iounmap(), pcim_iomap_table(), pcim_iomap(), pcim_iounmap() Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- Documentation/driver-model/devres.txt | 268 ++++++++++++++ drivers/base/Kconfig | 12 + drivers/base/Makefile | 1 + drivers/base/base.h | 1 + drivers/base/core.c | 2 + drivers/base/dd.c | 3 + drivers/base/devres.c | 644 ++++++++++++++++++++++++++++++++++ drivers/base/dma-mapping.c | 218 ++++++++++++ drivers/base/dmapool.c | 59 ++++ drivers/pci/pci.c | 127 ++++++- include/linux/device.h | 38 ++ include/linux/dma-mapping.h | 29 +- include/linux/dmapool.h | 7 + include/linux/interrupt.h | 6 + include/linux/io.h | 17 + include/linux/ioport.h | 20 ++ include/linux/pci.h | 9 + kernel/irq/manage.c | 86 +++++ kernel/resource.c | 62 ++++ lib/Makefile | 3 +- lib/iomap.c | 246 ++++++++++++- 21 files changed, 1853 insertions(+), 5 deletions(-) create mode 100644 Documentation/driver-model/devres.txt create mode 100644 drivers/base/devres.c create mode 100644 drivers/base/dma-mapping.c (limited to 'include/linux') diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt new file mode 100644 index 000000000000..5163b85308f5 --- /dev/null +++ b/Documentation/driver-model/devres.txt @@ -0,0 +1,268 @@ +Devres - Managed Device Resource +================================ + +Tejun Heo + +First draft 10 January 2007 + + +1. Intro : Huh? Devres? +2. Devres : Devres in a nutshell +3. Devres Group : Group devres'es and release them together +4. Details : Life time rules, calling context, ... +5. Overhead : How much do we have to pay for this? +6. List of managed interfaces : Currently implemented managed interfaces + + + 1. Intro + -------- + +devres came up while trying to convert libata to use iomap. Each +iomapped address should be kept and unmapped on driver detach. For +example, a plain SFF ATA controller (that is, good old PCI IDE) in +native mode makes use of 5 PCI BARs and all of them should be +maintained. + +As with many other device drivers, libata low level drivers have +sufficient bugs in ->remove and ->probe failure path. Well, yes, +that's probably because libata low level driver developers are lazy +bunch, but aren't all low level driver developers? After spending a +day fiddling with braindamaged hardware with no document or +braindamaged document, if it's finally working, well, it's working. + +For one reason or another, low level drivers don't receive as much +attention or testing as core code, and bugs on driver detach or +initilaization failure doesn't happen often enough to be noticeable. +Init failure path is worse because it's much less travelled while +needs to handle multiple entry points. + +So, many low level drivers end up leaking resources on driver detach +and having half broken failure path implementation in ->probe() which +would leak resources or even cause oops when failure occurs. iomap +adds more to this mix. So do msi and msix. + + + 2. Devres + --------- + +devres is basically linked list of arbitrarily sized memory areas +associated with a struct device. Each devres entry is associated with +a release function. A devres can be released in several ways. No +matter what, all devres entries are released on driver detach. On +release, the associated release function is invoked and then the +devres entry is freed. + +Managed interface is created for resources commonly used by device +drivers using devres. For example, coherent DMA memory is acquired +using dma_alloc_coherent(). The managed version is called +dmam_alloc_coherent(). It is identical to dma_alloc_coherent() except +for the DMA memory allocated using it is managed and will be +automatically released on driver detach. Implementation looks like +the following. + + struct dma_devres { + size_t size; + void *vaddr; + dma_addr_t dma_handle; + }; + + static void dmam_coherent_release(struct device *dev, void *res) + { + struct dma_devres *this = res; + + dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle); + } + + dmam_alloc_coherent(dev, size, dma_handle, gfp) + { + struct dma_devres *dr; + void *vaddr; + + dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp); + ... + + /* alloc DMA memory as usual */ + vaddr = dma_alloc_coherent(...); + ... + + /* record size, vaddr, dma_handle in dr */ + dr->vaddr = vaddr; + ... + + devres_add(dev, dr); + + return vaddr; + } + +If a driver uses dmam_alloc_coherent(), the area is guaranteed to be +freed whether initialization fails half-way or the device gets +detached. If most resources are acquired using managed interface, a +driver can have much simpler init and exit code. Init path basically +looks like the following. + + my_init_one() + { + struct mydev *d; + + d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + d->ring = dmam_alloc_coherent(...); + if (!d->ring) + return -ENOMEM; + + if (check something) + return -EINVAL; + ... + + return register_to_upper_layer(d); + } + +And exit path, + + my_remove_one() + { + unregister_from_upper_layer(d); + shutdown_my_hardware(); + } + +As shown above, low level drivers can be simplified a lot by using +devres. Complexity is shifted from less maintained low level drivers +to better maintained higher layer. Also, as init failure path is +shared with exit path, both can get more testing. + + + 3. Devres group + --------------- + +Devres entries can be grouped using devres group. When a group is +released, all contained normal devres entries and properly nested +groups are released. One usage is to rollback series of acquired +resources on failure. For example, + + if (!devres_open_group(dev, NULL, GFP_KERNEL)) + return -ENOMEM; + + acquire A; + if (failed) + goto err; + + acquire B; + if (failed) + goto err; + ... + + devres_remove_group(dev, NULL); + return 0; + + err: + devres_release_group(dev, NULL); + return err_code; + +As resource acquision failure usually means probe failure, constructs +like above are usually useful in midlayer driver (e.g. libata core +layer) where interface function shouldn't have side effect on failure. +For LLDs, just returning error code suffices in most cases. + +Each group is identified by void *id. It can either be explicitly +specified by @id argument to devres_open_group() or automatically +created by passing NULL as @id as in the above example. In both +cases, devres_open_group() returns the group's id. The returned id +can be passed to other devres functions to select the target group. +If NULL is given to those functions, the latest open group is +selected. + +For example, you can do something like the following. + + int my_midlayer_create_something() + { + if (!devres_open_group(dev, my_midlayer_create_something, GFP_KERNEL)) + return -ENOMEM; + + ... + + devres_close_group(dev, my_midlayer_something); + return 0; + } + + void my_midlayer_destroy_something() + { + devres_release_group(dev, my_midlayer_create_soemthing); + } + + + 4. Details + ---------- + +Lifetime of a devres entry begins on devres allocation and finishes +when it is released or destroyed (removed and freed) - no reference +counting. + +devres core guarantees atomicity to all basic devres operations and +has support for single-instance devres types (atomic +lookup-and-add-if-not-found). Other than that, synchronizing +concurrent accesses to allocated devres data is caller's +responsibility. This is usually non-issue because bus ops and +resource allocations already do the job. + +For an example of single-instance devres type, read pcim_iomap_table() +in lib/iomap.c. + +All devres interface functions can be called without context if the +right gfp mask is given. + + + 5. Overhead + ----------- + +Each devres bookkeeping info is allocated together with requested data +area. With debug option turned off, bookkeeping info occupies 16 +bytes on 32bit machines and 24 bytes on 64bit (three pointers rounded +up to ull alignment). If singly linked list is used, it can be +reduced to two pointers (8 bytes on 32bit, 16 bytes on 64bit). + +Each devres group occupies 8 pointers. It can be reduced to 6 if +singly linked list is used. + +Memory space overhead on ahci controller with two ports is between 300 +and 400 bytes on 32bit machine after naive conversion (we can +certainly invest a bit more effort into libata core layer). + + + 6. List of managed interfaces + ----------------------------- + +IO region + devm_request_region() + devm_request_mem_region() + devm_release_region() + devm_release_mem_region() + +IRQ + devm_request_irq() + devm_free_irq() + +DMA + dmam_alloc_coherent() + dmam_free_coherent() + dmam_alloc_noncoherent() + dmam_free_noncoherent() + dmam_declare_coherent_memory() + dmam_pool_create() + dmam_pool_destroy() + +PCI + pcim_enable_device() : after success, all PCI ops become managed + pcim_pin_device() : keep PCI device enabled after release + +IOMAP + devm_ioport_map() + devm_ioport_unmap() + devm_ioremap() + devm_ioremap_nocache() + devm_iounmap() + pcim_iomap() + pcim_iounmap() + pcim_iomap_table() : array of mapped addresses indexed by BAR + pcim_iomap_regions() : do request_region() and iomap() on multiple BARs diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 1429f3a2629e..5d6312e33490 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -37,6 +37,18 @@ config DEBUG_DRIVER If you are unsure about this, say N here. +config DEBUG_DEVRES + bool "Managed device resources verbose debug messages" + depends on DEBUG_KERNEL + help + This option enables kernel parameter devres.log. If set to + non-zero, devres debug messages are printed. Select this if + you are having a problem with devres or want to debug + resource management for a managed device. devres.log can be + switched on and off from sysfs node. + + If you are unsure about this, Say N here. + config SYS_HYPERVISOR bool default n diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 7bbb9eeda235..e9eb7382ac3a 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -3,6 +3,7 @@ obj-y := core.o sys.o bus.o dd.o \ driver.o class.o platform.o \ cpu.o firmware.o init.o map.o dmapool.o \ + dma-mapping.o devres.o \ attribute_container.o transport_class.o obj-y += power/ obj-$(CONFIG_ISA) += isa.o diff --git a/drivers/base/base.h b/drivers/base/base.h index d26644a59537..de7e1442ce60 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -44,3 +44,4 @@ struct class_device_attribute *to_class_dev_attr(struct attribute *_attr) extern char *make_class_name(const char *name, struct kobject *kobj); +extern void devres_release_all(struct device *dev); diff --git a/drivers/base/core.c b/drivers/base/core.c index e13614241c9e..a8ac34ba6107 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -428,6 +428,8 @@ void device_initialize(struct device *dev) INIT_LIST_HEAD(&dev->dma_pools); INIT_LIST_HEAD(&dev->node); init_MUTEX(&dev->sem); + spin_lock_init(&dev->devres_lock); + INIT_LIST_HEAD(&dev->devres_head); device_init_wakeup(dev, 0); set_dev_node(dev, -1); } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index b5bf243d9cd6..6a48824e43ff 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -112,6 +112,7 @@ static int really_probe(void *void_data) atomic_inc(&probe_count); pr_debug("%s: Probing driver %s with device %s\n", drv->bus->name, drv->name, dev->bus_id); + WARN_ON(!list_empty(&dev->devres_head)); dev->driver = drv; if (driver_sysfs_add(dev)) { @@ -137,6 +138,7 @@ static int really_probe(void *void_data) goto done; probe_failed: + devres_release_all(dev); driver_sysfs_remove(dev); dev->driver = NULL; @@ -327,6 +329,7 @@ static void __device_release_driver(struct device * dev) dev->bus->remove(dev); else if (drv->remove) drv->remove(dev); + devres_release_all(dev); dev->driver = NULL; put_driver(drv); } diff --git a/drivers/base/devres.c b/drivers/base/devres.c new file mode 100644 index 000000000000..e177c9533b6c --- /dev/null +++ b/drivers/base/devres.c @@ -0,0 +1,644 @@ +/* + * drivers/base/devres.c - device resource management + * + * Copyright (c) 2006 SUSE Linux Products GmbH + * Copyright (c) 2006 Tejun Heo + * + * This file is released under the GPLv2. + */ + +#include +#include + +struct devres_node { + struct list_head entry; + dr_release_t release; +#ifdef CONFIG_DEBUG_DEVRES + const char *name; + size_t size; +#endif +}; + +struct devres { + struct devres_node node; + /* -- 3 pointers */ + unsigned long long data[]; /* guarantee ull alignment */ +}; + +struct devres_group { + struct devres_node node[2]; + void *id; + int color; + /* -- 8 pointers */ +}; + +#ifdef CONFIG_DEBUG_DEVRES +static int log_devres = 0; +module_param_named(log, log_devres, int, S_IRUGO | S_IWUSR); + +static void set_node_dbginfo(struct devres_node *node, const char *name, + size_t size) +{ + node->name = name; + node->size = size; +} + +static void devres_log(struct device *dev, struct devres_node *node, + const char *op) +{ + if (unlikely(log_devres)) + dev_printk(KERN_ERR, dev, "DEVRES %3s %p %s (%lu bytes)\n", + op, node, node->name, (unsigned long)node->size); +} +#else /* CONFIG_DEBUG_DEVRES */ +#define set_node_dbginfo(node, n, s) do {} while (0) +#define devres_log(dev, node, op) do {} while (0) +#endif /* CONFIG_DEBUG_DEVRES */ + +/* + * Release functions for devres group. These callbacks are used only + * for identification. + */ +static void group_open_release(struct device *dev, void *res) +{ + /* noop */ +} + +static void group_close_release(struct device *dev, void *res) +{ + /* noop */ +} + +static struct devres_group * node_to_group(struct devres_node *node) +{ + if (node->release == &group_open_release) + return container_of(node, struct devres_group, node[0]); + if (node->release == &group_close_release) + return container_of(node, struct devres_group, node[1]); + return NULL; +} + +static __always_inline struct devres * alloc_dr(dr_release_t release, + size_t size, gfp_t gfp) +{ + size_t tot_size = sizeof(struct devres) + size; + struct devres *dr; + + dr = kmalloc_track_caller(tot_size, gfp); + if (unlikely(!dr)) + return NULL; + + memset(dr, 0, tot_size); + INIT_LIST_HEAD(&dr->node.entry); + dr->node.release = release; + return dr; +} + +static void add_dr(struct device *dev, struct devres_node *node) +{ + devres_log(dev, node, "ADD"); + BUG_ON(!list_empty(&node->entry)); + list_add_tail(&node->entry, &dev->devres_head); +} + +/** + * devres_alloc - Allocate device resource data + * @release: Release function devres will be associated with + * @size: Allocation size + * @gfp: Allocation flags + * + * allocate devres of @size bytes. The allocated area is zeroed, then + * associated with @release. The returned pointer can be passed to + * other devres_*() functions. + * + * RETURNS: + * Pointer to allocated devres on success, NULL on failure. + */ +#ifdef CONFIG_DEBUG_DEVRES +void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp, + const char *name) +{ + struct devres *dr; + + dr = alloc_dr(release, size, gfp); + if (unlikely(!dr)) + return NULL; + set_node_dbginfo(&dr->node, name, size); + return dr->data; +} +EXPORT_SYMBOL_GPL(__devres_alloc); +#else +void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp) +{ + struct devres *dr; + + dr = alloc_dr(release, size, gfp); + if (unlikely(!dr)) + return NULL; + return dr->data; +} +EXPORT_SYMBOL_GPL(devres_alloc); +#endif + +/** + * devres_free - Free device resource data + * @res: Pointer to devres data to free + * + * Free devres created with devres_alloc(). + */ +void devres_free(void *res) +{ + if (res) { + struct devres *dr = container_of(res, struct devres, data); + + BUG_ON(!list_empty(&dr->node.entry)); + kfree(dr); + } +} +EXPORT_SYMBOL_GPL(devres_free); + +/** + * devres_add - Register device resource + * @dev: Device to add resource to + * @res: Resource to register + * + * Register devres @res to @dev. @res should have been allocated + * using devres_alloc(). On driver detach, the associated release + * function will be invoked and devres will be freed automatically. + */ +void devres_add(struct device *dev, void *res) +{ + struct devres *dr = container_of(res, struct devres, data); + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + add_dr(dev, &dr->node); + spin_unlock_irqrestore(&dev->devres_lock, flags); +} +EXPORT_SYMBOL_GPL(devres_add); + +static struct devres *find_dr(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + struct devres_node *node; + + list_for_each_entry_reverse(node, &dev->devres_head, entry) { + struct devres *dr = container_of(node, struct devres, node); + + if (node->release != release) + continue; + if (match && !match(dev, dr->data, match_data)) + continue; + return dr; + } + + return NULL; +} + +/** + * devres_find - Find device resource + * @dev: Device to lookup resource from + * @release: Look for resources associated with this release function + * @match: Match function (optional) + * @match_data: Data for the match function + * + * Find the latest devres of @dev which is associated with @release + * and for which @match returns 1. If @match is NULL, it's considered + * to match all. + * + * RETURNS: + * Pointer to found devres, NULL if not found. + */ +void * devres_find(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + struct devres *dr; + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + dr = find_dr(dev, release, match, match_data); + spin_unlock_irqrestore(&dev->devres_lock, flags); + + if (dr) + return dr->data; + return NULL; +} +EXPORT_SYMBOL_GPL(devres_find); + +/** + * devres_get - Find devres, if non-existent, add one atomically + * @dev: Device to lookup or add devres for + * @new_res: Pointer to new initialized devres to add if not found + * @match: Match function (optional) + * @match_data: Data for the match function + * + * Find the latest devres of @dev which has the same release function + * as @new_res and for which @match return 1. If found, @new_res is + * freed; otherwise, @new_res is added atomically. + * + * RETURNS: + * Pointer to found or added devres. + */ +void * devres_get(struct device *dev, void *new_res, + dr_match_t match, void *match_data) +{ + struct devres *new_dr = container_of(new_res, struct devres, data); + struct devres *dr; + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + dr = find_dr(dev, new_dr->node.release, match, match_data); + if (!dr) { + add_dr(dev, &new_dr->node); + dr = new_dr; + new_dr = NULL; + } + spin_unlock_irqrestore(&dev->devres_lock, flags); + devres_free(new_dr); + + return dr->data; +} +EXPORT_SYMBOL_GPL(devres_get); + +/** + * devres_remove - Find a device resource and remove it + * @dev: Device to find resource from + * @release: Look for resources associated with this release function + * @match: Match function (optional) + * @match_data: Data for the match function + * + * Find the latest devres of @dev associated with @release and for + * which @match returns 1. If @match is NULL, it's considered to + * match all. If found, the resource is removed atomically and + * returned. + * + * RETURNS: + * Pointer to removed devres on success, NULL if not found. + */ +void * devres_remove(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + struct devres *dr; + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + dr = find_dr(dev, release, match, match_data); + if (dr) { + list_del_init(&dr->node.entry); + devres_log(dev, &dr->node, "REM"); + } + spin_unlock_irqrestore(&dev->devres_lock, flags); + + if (dr) + return dr->data; + return NULL; +} +EXPORT_SYMBOL_GPL(devres_remove); + +/** + * devres_destroy - Find a device resource and destroy it + * @dev: Device to find resource from + * @release: Look for resources associated with this release function + * @match: Match function (optional) + * @match_data: Data for the match function + * + * Find the latest devres of @dev associated with @release and for + * which @match returns 1. If @match is NULL, it's considered to + * match all. If found, the resource is removed atomically and freed. + * + * RETURNS: + * 0 if devres is found and freed, -ENOENT if not found. + */ +int devres_destroy(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data) +{ + void *res; + + res = devres_remove(dev, release, match, match_data); + if (unlikely(!res)) + return -ENOENT; + + devres_free(res); + return 0; +} +EXPORT_SYMBOL_GPL(devres_destroy); + +static int remove_nodes(struct device *dev, + struct list_head *first, struct list_head *end, + struct list_head *todo) +{ + int cnt = 0, nr_groups = 0; + struct list_head *cur; + + /* First pass - move normal devres entries to @todo and clear + * devres_group colors. + */ + cur = first; + while (cur != end) { + struct devres_node *node; + struct devres_group *grp; + + node = list_entry(cur, struct devres_node, entry); + cur = cur->next; + + grp = node_to_group(node); + if (grp) { + /* clear color of group markers in the first pass */ + grp->color = 0; + nr_groups++; + } else { + /* regular devres entry */ + if (&node->entry == first) + first = first->next; + list_move_tail(&node->entry, todo); + cnt++; + } + } + + if (!nr_groups) + return cnt; + + /* Second pass - Scan groups and color them. A group gets + * color value of two iff the group is wholly contained in + * [cur, end). That is, for a closed group, both opening and + * closing markers should be in the range, while just the + * opening marker is enough for an open group. + */ + cur = first; + while (cur != end) { + struct devres_node *node; + struct devres_group *grp; + + node = list_entry(cur, struct devres_node, entry); + cur = cur->next; + + grp = node_to_group(node); + BUG_ON(!grp || list_empty(&grp->node[0].entry)); + + grp->color++; + if (list_empty(&grp->node[1].entry)) + grp->color++; + + BUG_ON(grp->color <= 0 || grp->color > 2); + if (grp->color == 2) { + /* No need to update cur or end. The removed + * nodes are always before both. + */ + list_move_tail(&grp->node[0].entry, todo); + list_del_init(&grp->node[1].entry); + } + } + + return cnt; +} + +static int release_nodes(struct device *dev, struct list_head *first, + struct list_head *end, unsigned long flags) +{ + LIST_HEAD(todo); + int cnt; + struct devres *dr, *tmp; + + cnt = remove_nodes(dev, first, end, &todo); + + spin_unlock_irqrestore(&dev->devres_lock, flags); + + /* Release. Note that both devres and devres_group are + * handled as devres in the following loop. This is safe. + */ + list_for_each_entry_safe_reverse(dr, tmp, &todo, node.entry) { + devres_log(dev, &dr->node, "REL"); + dr->node.release(dev, dr->data); + kfree(dr); + } + + return cnt; +} + +/** + * devres_release_all - Release all resources + * @dev: Device to release resources for + * + * Release all resources associated with @dev. This function is + * called on driver detach. + */ +int devres_release_all(struct device *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + return release_nodes(dev, dev->devres_head.next, &dev->devres_head, + flags); +} + +/** + * devres_open_group - Open a new devres group + * @dev: Device to open devres group for + * @id: Separator ID + * @gfp: Allocation flags + * + * Open a new devres group for @dev with @id. For @id, using a + * pointer to an object which won't be used for another group is + * recommended. If @id is NULL, address-wise unique ID is created. + * + * RETURNS: + * ID of the new group, NULL on failure. + */ +void * devres_open_group(struct device *dev, void *id, gfp_t gfp) +{ + struct devres_group *grp; + unsigned long flags; + + grp = kmalloc(sizeof(*grp), gfp); + if (unlikely(!grp)) + return NULL; + + grp->node[0].release = &group_open_release; + grp->node[1].release = &group_close_release; + INIT_LIST_HEAD(&grp->node[0].entry); + INIT_LIST_HEAD(&grp->node[1].entry); + set_node_dbginfo(&grp->node[0], "grp<", 0); + set_node_dbginfo(&grp->node[1], "grp>", 0); + grp->id = grp; + if (id) + grp->id = id; + + spin_lock_irqsave(&dev->devres_lock, flags); + add_dr(dev, &grp->node[0]); + spin_unlock_irqrestore(&dev->devres_lock, flags); + return grp->id; +} +EXPORT_SYMBOL_GPL(devres_open_group); + +/* Find devres group with ID @id. If @id is NULL, look for the latest. */ +static struct devres_group * find_group(struct device *dev, void *id) +{ + struct devres_node *node; + + list_for_each_entry_reverse(node, &dev->devres_head, entry) { + struct devres_group *grp; + + if (node->release != &group_open_release) + continue; + + grp = container_of(node, struct devres_group, node[0]); + + if (id) { + if (grp->id == id) + return grp; + } else if (list_empty(&grp->node[1].entry)) + return grp; + } + + return NULL; +} + +/** + * devres_close_group - Close a devres group + * @dev: Device to close devres group for + * @id: ID of target group, can be NULL + * + * Close the group identified by @id. If @id is NULL, the latest open + * group is selected. + */ +void devres_close_group(struct device *dev, void *id) +{ + struct devres_group *grp; + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + + grp = find_group(dev, id); + if (grp) + add_dr(dev, &grp->node[1]); + else + WARN_ON(1); + + spin_unlock_irqrestore(&dev->devres_lock, flags); +} +EXPORT_SYMBOL_GPL(devres_close_group); + +/** + * devres_remove_group - Remove a devres group + * @dev: Device to remove group for + * @id: ID of target group, can be NULL + * + * Remove the group identified by @id. If @id is NULL, the latest + * open group is selected. Note that removing a group doesn't affect + * any other resources. + */ +void devres_remove_group(struct device *dev, void *id) +{ + struct devres_group *grp; + unsigned long flags; + + spin_lock_irqsave(&dev->devres_lock, flags); + + grp = find_group(dev, id); + if (grp) { + list_del_init(&grp->node[0].entry); + list_del_init(&grp->node[1].entry); + devres_log(dev, &grp->node[0], "REM"); + } else + WARN_ON(1); + + spin_unlock_irqrestore(&dev->devres_lock, flags); + + kfree(grp); +} +EXPORT_SYMBOL_GPL(devres_remove_group); + +/** + * devres_release_group - Release resources in a devres group + * @dev: Device to release group for + * @id: ID of target group, can be NULL + * + * Release all resources in the group identified by @id. If @id is + * NULL, the latest open group is selected. The selected group and + * groups properly nested inside the selected group are removed. + * + * RETURNS: + * The number of released non-group resources. + */ +int devres_release_group(struct device *dev, void *id) +{ + struct devres_group *grp; + unsigned long flags; + int cnt = 0; + + spin_lock_irqsave(&dev->devres_lock, flags); + + grp = find_group(dev, id); + if (grp) { + struct list_head *first = &grp->node[0].entry; + struct list_head *end = &dev->devres_head; + + if (!list_empty(&grp->node[1].entry)) + end = grp->node[1].entry.next; + + cnt = release_nodes(dev, first, end, flags); + } else { + WARN_ON(1); + spin_unlock_irqrestore(&dev->devres_lock, flags); + } + + return cnt; +} +EXPORT_SYMBOL_GPL(devres_release_group); + +/* + * Managed kzalloc/kfree + */ +static void devm_kzalloc_release(struct device *dev, void *res) +{ + /* noop */ +} + +static int devm_kzalloc_match(struct device *dev, void *res, void *data) +{ + return res == data; +} + +/** + * devm_kzalloc - Managed kzalloc + * @dev: Device to allocate memory for + * @size: Allocation size + * @gfp: Allocation gfp flags + * + * Managed kzalloc. Memory allocated with this function is + * automatically freed on driver detach. Like all other devres + * resources, guaranteed alignment is unsigned long long. + * + * RETURNS: + * Pointer to allocated memory on success, NULL on failure. + */ +void * devm_kzalloc(struct device *dev, size_t size, gfp_t gfp) +{ + struct devres *dr; + + /* use raw alloc_dr for kmalloc caller tracing */ + dr = alloc_dr(devm_kzalloc_release, size, gfp); + if (unlikely(!dr)) + return NULL; + + set_node_dbginfo(&dr->node, "devm_kzalloc_release", size); + devres_add(dev, dr->data); + return dr->data; +} +EXPORT_SYMBOL_GPL(devm_kzalloc); + +/** + * devm_kfree - Managed kfree + * @dev: Device this memory belongs to + * @p: Memory to free + * + * Free memory allocated with dev_kzalloc(). + */ +void devm_kfree(struct device *dev, void *p) +{ + int rc; + + rc = devres_destroy(dev, devm_kzalloc_release, devm_kzalloc_match, p); + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_kfree); diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c new file mode 100644 index 000000000000..ca9186f70a69 --- /dev/null +++ b/drivers/base/dma-mapping.c @@ -0,0 +1,218 @@ +/* + * drivers/base/dma-mapping.c - arch-independent dma-mapping routines + * + * Copyright (c) 2006 SUSE Linux Products GmbH + * Copyright (c) 2006 Tejun Heo + * + * This file is released under the GPLv2. + */ + +#include + +/* + * Managed DMA API + */ +struct dma_devres { + size_t size; + void *vaddr; + dma_addr_t dma_handle; +}; + +static void dmam_coherent_release(struct device *dev, void *res) +{ + struct dma_devres *this = res; + + dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle); +} + +static void dmam_noncoherent_release(struct device *dev, void *res) +{ + struct dma_devres *this = res; + + dma_free_noncoherent(dev, this->size, this->vaddr, this->dma_handle); +} + +static int dmam_match(struct device *dev, void *res, void *match_data) +{ + struct dma_devres *this = res, *match = match_data; + + if (this->vaddr == match->vaddr) { + WARN_ON(this->size != match->size || + this->dma_handle != match->dma_handle); + return 1; + } + return 0; +} + +/** + * dmam_alloc_coherent - Managed dma_alloc_coherent() + * @dev: Device to allocate coherent memory for + * @size: Size of allocation + * @dma_handle: Out argument for allocated DMA handle + * @gfp: Allocation flags + * + * Managed dma_alloc_coherent(). Memory allocated using this function + * will be automatically released on driver detach. + * + * RETURNS: + * Pointer to allocated memory on success, NULL on failure. + */ +void * dmam_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp) +{ + struct dma_devres *dr; + void *vaddr; + + dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp); + if (!dr) + return NULL; + + vaddr = dma_alloc_coherent(dev, size, dma_handle, gfp); + if (!vaddr) { + devres_free(dr); + return NULL; + } + + dr->vaddr = vaddr; + dr->dma_handle = *dma_handle; + dr->size = size; + + devres_add(dev, dr); + + return vaddr; +} +EXPORT_SYMBOL(dmam_alloc_coherent); + +/** + * dmam_free_coherent - Managed dma_free_coherent() + * @dev: Device to free coherent memory for + * @size: Size of allocation + * @vaddr: Virtual address of the memory to free + * @dma_handle: DMA handle of the memory to free + * + * Managed dma_free_coherent(). + */ +void dmam_free_coherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + struct dma_devres match_data = { size, vaddr, dma_handle }; + + dma_free_coherent(dev, size, vaddr, dma_handle); + WARN_ON(devres_destroy(dev, dmam_coherent_release, dmam_match, + &match_data)); +} +EXPORT_SYMBOL(dmam_free_coherent); + +/** + * dmam_alloc_non_coherent - Managed dma_alloc_non_coherent() + * @dev: Device to allocate non_coherent memory for + * @size: Size of allocation + * @dma_handle: Out argument for allocated DMA handle + * @gfp: Allocation flags + * + * Managed dma_alloc_non_coherent(). Memory allocated using this + * function will be automatically released on driver detach. + * + * RETURNS: + * Pointer to allocated memory on success, NULL on failure. + */ +void *dmam_alloc_noncoherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp) +{ + struct dma_devres *dr; + void *vaddr; + + dr = devres_alloc(dmam_noncoherent_release, sizeof(*dr), gfp); + if (!dr) + return NULL; + + vaddr = dma_alloc_noncoherent(dev, size, dma_handle, gfp); + if (!vaddr) { + devres_free(dr); + return NULL; + } + + dr->vaddr = vaddr; + dr->dma_handle = *dma_handle; + dr->size = size; + + devres_add(dev, dr); + + return vaddr; +} +EXPORT_SYMBOL(dmam_alloc_noncoherent); + +/** + * dmam_free_coherent - Managed dma_free_noncoherent() + * @dev: Device to free noncoherent memory for + * @size: Size of allocation + * @vaddr: Virtual address of the memory to free + * @dma_handle: DMA handle of the memory to free + * + * Managed dma_free_noncoherent(). + */ +void dmam_free_noncoherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + struct dma_devres match_data = { size, vaddr, dma_handle }; + + dma_free_noncoherent(dev, size, vaddr, dma_handle); + WARN_ON(!devres_destroy(dev, dmam_noncoherent_release, dmam_match, + &match_data)); +} +EXPORT_SYMBOL(dmam_free_noncoherent); + +#ifdef ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY + +static void dmam_coherent_decl_release(struct device *dev, void *res) +{ + dma_release_declared_memory(dev); +} + +/** + * dmam_declare_coherent_memory - Managed dma_declare_coherent_memory() + * @dev: Device to declare coherent memory for + * @bus_addr: Bus address of coherent memory to be declared + * @device_addr: Device address of coherent memory to be declared + * @size: Size of coherent memory to be declared + * @flags: Flags + * + * Managed dma_declare_coherent_memory(). + * + * RETURNS: + * 0 on success, -errno on failure. + */ +int dmam_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, + dma_addr_t device_addr, size_t size, int flags) +{ + void *res; + int rc; + + res = devres_alloc(dmam_coherent_decl_release, 0, GFP_KERNEL); + if (!res) + return -ENOMEM; + + rc = dma_declare_coherent_memory(dev, bus_addr, device_addr, size, + flags); + if (rc == 0) + devres_add(dev, res); + else + devres_free(res); + + return rc; +} +EXPORT_SYMBOL(dmam_declare_coherent_memory); + +/** + * dmam_release_declared_memory - Managed dma_release_declared_memory(). + * @dev: Device to release declared coherent memory for + * + * Managed dmam_release_declared_memory(). + */ +void dmam_release_declared_memory(struct device *dev) +{ + WARN_ON(devres_destroy(dev, dmam_coherent_decl_release, NULL, NULL)); +} +EXPORT_SYMBOL(dmam_release_declared_memory); + +#endif diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c index f95d50277274..cd467c9f33b3 100644 --- a/drivers/base/dmapool.c +++ b/drivers/base/dmapool.c @@ -415,8 +415,67 @@ dma_pool_free (struct dma_pool *pool, void *vaddr, dma_addr_t dma) spin_unlock_irqrestore (&pool->lock, flags); } +/* + * Managed DMA pool + */ +static void dmam_pool_release(struct device *dev, void *res) +{ + struct dma_pool *pool = *(struct dma_pool **)res; + + dma_pool_destroy(pool); +} + +static int dmam_pool_match(struct device *dev, void *res, void *match_data) +{ + return *(struct dma_pool **)res == match_data; +} + +/** + * dmam_pool_create - Managed dma_pool_create() + * @name: name of pool, for diagnostics + * @dev: device that will be doing the DMA + * @size: size of the blocks in this pool. + * @align: alignment requirement for blocks; must be a power of two + * @allocation: returned blocks won't cross this boundary (or zero) + * + * Managed dma_pool_create(). DMA pool created with this function is + * automatically destroyed on driver detach. + */ +struct dma_pool *dmam_pool_create(const char *name, struct device *dev, + size_t size, size_t align, size_t allocation) +{ + struct dma_pool **ptr, *pool; + + ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return NULL; + + pool = *ptr = dma_pool_create(name, dev, size, align, allocation); + if (pool) + devres_add(dev, ptr); + else + devres_free(ptr); + + return pool; +} + +/** + * dmam_pool_destroy - Managed dma_pool_destroy() + * @pool: dma pool that will be destroyed + * + * Managed dma_pool_destroy(). + */ +void dmam_pool_destroy(struct dma_pool *pool) +{ + struct device *dev = pool->dev; + + dma_pool_destroy(pool); + WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool)); +} EXPORT_SYMBOL (dma_pool_create); EXPORT_SYMBOL (dma_pool_destroy); EXPORT_SYMBOL (dma_pool_alloc); EXPORT_SYMBOL (dma_pool_free); +EXPORT_SYMBOL (dmam_pool_create); +EXPORT_SYMBOL (dmam_pool_destroy); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 84c757ba0664..8b44cff2c176 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -744,6 +744,104 @@ int pci_enable_device(struct pci_dev *dev) return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); } +/* + * Managed PCI resources. This manages device on/off, intx/msi/msix + * on/off and BAR regions. pci_dev itself records msi/msix status, so + * there's no need to track it separately. pci_devres is initialized + * when a device is enabled using managed PCI device enable interface. + */ +struct pci_devres { + unsigned int disable:1; + unsigned int orig_intx:1; + unsigned int restore_intx:1; + u32 region_mask; +}; + +static void pcim_release(struct device *gendev, void *res) +{ + struct pci_dev *dev = container_of(gendev, struct pci_dev, dev); + struct pci_devres *this = res; + int i; + + if (dev->msi_enabled) + pci_disable_msi(dev); + if (dev->msix_enabled) + pci_disable_msix(dev); + + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) + if (this->region_mask & (1 << i)) + pci_release_region(dev, i); + + if (this->restore_intx) + pci_intx(dev, this->orig_intx); + + if (this->disable) + pci_disable_device(dev); +} + +static struct pci_devres * get_pci_dr(struct pci_dev *pdev) +{ + struct pci_devres *dr, *new_dr; + + dr = devres_find(&pdev->dev, pcim_release, NULL, NULL); + if (dr) + return dr; + + new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL); + if (!new_dr) + return NULL; + return devres_get(&pdev->dev, new_dr, NULL, NULL); +} + +static struct pci_devres * find_pci_dr(struct pci_dev *pdev) +{ + if (pci_is_managed(pdev)) + return devres_find(&pdev->dev, pcim_release, NULL, NULL); + return NULL; +} + +/** + * pcim_enable_device - Managed pci_enable_device() + * @pdev: PCI device to be initialized + * + * Managed pci_enable_device(). + */ +int pcim_enable_device(struct pci_dev *pdev) +{ + struct pci_devres *dr; + int rc; + + dr = get_pci_dr(pdev); + if (unlikely(!dr)) + return -ENOMEM; + WARN_ON(!!dr->disable); + + rc = pci_enable_device(pdev); + if (!rc) { + pdev->is_managed = 1; + dr->disable = 1; + } + return rc; +} + +/** + * pcim_pin_device - Pin managed PCI device + * @pdev: PCI device to pin + * + * Pin managed PCI device @pdev. Pinned device won't be disabled on + * driver detach. @pdev must have been enabled with + * pcim_enable_device(). + */ +void pcim_pin_device(struct pci_dev *pdev) +{ + struct pci_devres *dr; + + dr = find_pci_dr(pdev); + WARN_ON(!dr || !dr->disable); + if (dr) + dr->disable = 0; +} + /** * pcibios_disable_device - disable arch specific PCI resources for device dev * @dev: the PCI device to disable @@ -767,8 +865,13 @@ void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {} void pci_disable_device(struct pci_dev *dev) { + struct pci_devres *dr; u16 pci_command; + dr = find_pci_dr(dev); + if (dr) + dr->disable = 0; + if (atomic_sub_return(1, &dev->enable_cnt) != 0) return; @@ -867,6 +970,8 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) */ void pci_release_region(struct pci_dev *pdev, int bar) { + struct pci_devres *dr; + if (pci_resource_len(pdev, bar) == 0) return; if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) @@ -875,6 +980,10 @@ void pci_release_region(struct pci_dev *pdev, int bar) else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) release_mem_region(pci_resource_start(pdev, bar), pci_resource_len(pdev, bar)); + + dr = find_pci_dr(pdev); + if (dr) + dr->region_mask &= ~(1 << bar); } /** @@ -893,6 +1002,8 @@ void pci_release_region(struct pci_dev *pdev, int bar) */ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) { + struct pci_devres *dr; + if (pci_resource_len(pdev, bar) == 0) return 0; @@ -906,7 +1017,11 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) pci_resource_len(pdev, bar), res_name)) goto err_out; } - + + dr = find_pci_dr(pdev); + if (dr) + dr->region_mask |= 1 << bar; + return 0; err_out: @@ -1144,7 +1259,15 @@ pci_intx(struct pci_dev *pdev, int enable) } if (new != pci_command) { + struct pci_devres *dr; + pci_write_config_word(pdev, PCI_COMMAND, new); + + dr = find_pci_dr(pdev); + if (dr && !dr->restore_intx) { + dr->restore_intx = 1; + dr->orig_intx = !enable; + } } } @@ -1226,6 +1349,8 @@ device_initcall(pci_init); EXPORT_SYMBOL_GPL(pci_restore_bars); EXPORT_SYMBOL(pci_enable_device_bars); EXPORT_SYMBOL(pci_enable_device); +EXPORT_SYMBOL(pcim_enable_device); +EXPORT_SYMBOL(pcim_pin_device); EXPORT_SYMBOL(pci_disable_device); EXPORT_SYMBOL(pci_find_capability); EXPORT_SYMBOL(pci_bus_find_capability); diff --git a/include/linux/device.h b/include/linux/device.h index 5ca1cdba563a..26e4692f2d1a 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -354,6 +354,41 @@ extern int __must_check device_create_bin_file(struct device *dev, struct bin_attribute *attr); extern void device_remove_bin_file(struct device *dev, struct bin_attribute *attr); + +/* device resource management */ +typedef void (*dr_release_t)(struct device *dev, void *res); +typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data); + +#ifdef CONFIG_DEBUG_DEVRES +extern void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp, + const char *name); +#define devres_alloc(release, size, gfp) \ + __devres_alloc(release, size, gfp, #release) +#else +extern void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp); +#endif +extern void devres_free(void *res); +extern void devres_add(struct device *dev, void *res); +extern void * devres_find(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data); +extern void * devres_get(struct device *dev, void *new_res, + dr_match_t match, void *match_data); +extern void * devres_remove(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data); +extern int devres_destroy(struct device *dev, dr_release_t release, + dr_match_t match, void *match_data); + +/* devres group */ +extern void * __must_check devres_open_group(struct device *dev, void *id, + gfp_t gfp); +extern void devres_close_group(struct device *dev, void *id); +extern void devres_remove_group(struct device *dev, void *id); +extern int devres_release_group(struct device *dev, void *id); + +/* managed kzalloc/kfree for device drivers, no kmalloc, always use kzalloc */ +extern void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp); +extern void devm_kfree(struct device *dev, void *p); + struct device { struct klist klist_children; struct klist_node knode_parent; /* node in sibling list */ @@ -397,6 +432,9 @@ struct device { /* arch specific additions */ struct dev_archdata archdata; + spinlock_t devres_lock; + struct list_head devres_head; + /* class_device migration path */ struct list_head node; struct class *class; diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index ff203c465fed..9a663c6db16a 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -66,6 +66,33 @@ dma_mark_declared_memory_occupied(struct device *dev, } #endif -#endif +/* + * Managed DMA API + */ +extern void *dmam_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp); +extern void dmam_free_coherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle); +extern void *dmam_alloc_noncoherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp); +extern void dmam_free_noncoherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle); +#ifdef ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY +extern int dmam_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, + dma_addr_t device_addr, size_t size, + int flags); +extern void dmam_release_declared_memory(struct device *dev); +#else /* ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY */ +static inline int dmam_declare_coherent_memory(struct device *dev, + dma_addr_t bus_addr, dma_addr_t device_addr, + size_t size, gfp_t gfp) +{ + return 0; +} +static inline void dmam_release_declared_memory(struct device *dev) +{ +} +#endif /* ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY */ +#endif diff --git a/include/linux/dmapool.h b/include/linux/dmapool.h index 76f12f46db7f..022e34fcbd1b 100644 --- a/include/linux/dmapool.h +++ b/include/linux/dmapool.h @@ -24,5 +24,12 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t addr); +/* + * Managed DMA pool + */ +struct dma_pool *dmam_pool_create(const char *name, struct device *dev, + size_t size, size_t align, size_t allocation); +void dmam_pool_destroy(struct dma_pool *pool); + #endif diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index e36e86c869fb..5a8ba0b8ccba 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,11 @@ extern int request_irq(unsigned int, irq_handler_t handler, unsigned long, const char *, void *); extern void free_irq(unsigned int, void *); +extern int devm_request_irq(struct device *dev, unsigned int irq, + irq_handler_t handler, unsigned long irqflags, + const char *devname, void *dev_id); +extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id); + /* * On lockdep we dont want to enable hardirqs in hardirq * context. Use local_irq_enable_in_hardirq() to annotate diff --git a/include/linux/io.h b/include/linux/io.h index 81877ea39309..f5edf9c5de0a 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -28,6 +28,23 @@ void __iowrite64_copy(void __iomem *to, const void *from, size_t count); int ioremap_page_range(unsigned long addr, unsigned long end, unsigned long phys_addr, pgprot_t prot); +/* + * Managed iomap interface + */ +void __iomem * devm_ioport_map(struct device *dev, unsigned long port, + unsigned int nr); +void devm_ioport_unmap(struct device *dev, void __iomem *addr); + +void __iomem * devm_ioremap(struct device *dev, unsigned long offset, + unsigned long size); +void __iomem * devm_ioremap_nocache(struct device *dev, unsigned long offset, + unsigned long size); +void devm_iounmap(struct device *dev, void __iomem *addr); + +void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); +void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr); +void __iomem * const * pcim_iomap_table(struct pci_dev *pdev); + /** * check_signature - find BIOS signatures * @io_addr: mmio address to check diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 15228d79c5bc..6859a3b14088 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -137,4 +137,24 @@ static inline int __deprecated check_region(resource_size_t s, { return __check_region(&ioport_resource, s, n); } + +/* Wrappers for managed devices */ +struct device; +#define devm_request_region(dev,start,n,name) \ + __devm_request_region(dev, &ioport_resource, (start), (n), (name)) +#define devm_request_mem_region(dev,start,n,name) \ + __devm_request_region(dev, &iomem_resource, (start), (n), (name)) + +extern struct resource * __devm_request_region(struct device *dev, + struct resource *parent, resource_size_t start, + resource_size_t n, const char *name); + +#define devm_release_region(start,n) \ + __devm_release_region(dev, &ioport_resource, (start), (n)) +#define devm_release_mem_region(start,n) \ + __devm_release_region(dev, &iomem_resource, (start), (n)) + +extern void __devm_release_region(struct device *dev, struct resource *parent, + resource_size_t start, resource_size_t n); + #endif /* _LINUX_IOPORT_H */ diff --git a/include/linux/pci.h b/include/linux/pci.h index 805412cc6875..9e3042e7e1cc 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -167,6 +167,7 @@ struct pci_dev { unsigned int broken_parity_status:1; /* Device generates false positive parity */ unsigned int msi_enabled:1; unsigned int msix_enabled:1; + unsigned int is_managed:1; atomic_t enable_cnt; /* pci_enable_device has been called */ u32 saved_config_space[16]; /* config space saved at suspend time */ @@ -528,6 +529,14 @@ static inline int pci_write_config_dword(struct pci_dev *dev, int where, u32 val int __must_check pci_enable_device(struct pci_dev *dev); int __must_check pci_enable_device_bars(struct pci_dev *dev, int mask); +int __must_check pcim_enable_device(struct pci_dev *pdev); +void pcim_pin_device(struct pci_dev *pdev); + +static inline int pci_is_managed(struct pci_dev *pdev) +{ + return pdev->is_managed; +} + void pci_disable_device(struct pci_dev *dev); void pci_set_master(struct pci_dev *dev); #define HAVE_PCI_SET_MWI diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 8b961adc3bd2..c4b7ed1cebf7 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -482,3 +482,89 @@ int request_irq(unsigned int irq, irq_handler_t handler, return retval; } EXPORT_SYMBOL(request_irq); + +/* + * Device resource management aware IRQ request/free implementation. + */ +struct irq_devres { + unsigned int irq; + void *dev_id; +}; + +static void devm_irq_release(struct device *dev, void *res) +{ + struct irq_devres *this = res; + + free_irq(this->irq, this->dev_id); +} + +static int devm_irq_match(struct device *dev, void *res, void *data) +{ + struct irq_devres *this = res, *match = data; + + return this->irq == match->irq && this->dev_id == match->dev_id; +} + +/** + * devm_request_irq - allocate an interrupt line for a managed device + * @dev: device to request interrupt for + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * Except for the extra @dev argument, this function takes the + * same arguments and performs the same function as + * request_irq(). IRQs requested with this function will be + * automatically freed on driver detach. + * + * If an IRQ allocated with this function needs to be freed + * separately, dev_free_irq() must be used. + */ +int devm_request_irq(struct device *dev, unsigned int irq, + irq_handler_t handler, unsigned long irqflags, + const char *devname, void *dev_id) +{ + struct irq_devres *dr; + int rc; + + dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres), + GFP_KERNEL); + if (!dr) + return -ENOMEM; + + rc = request_irq(irq, handler, irqflags, devname, dev_id); + if (rc) { + kfree(dr); + return rc; + } + + dr->irq = irq; + dr->dev_id = dev_id; + devres_add(dev, dr); + + return 0; +} +EXPORT_SYMBOL(devm_request_irq); + +/** + * devm_free_irq - free an interrupt + * @dev: device to free interrupt for + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Except for the extra @dev argument, this function takes the + * same arguments and performs the same function as free_irq(). + * This function instead of free_irq() should be used to manually + * free IRQs allocated with dev_request_irq(). + */ +void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) +{ + struct irq_devres match_data = { irq, dev_id }; + + free_irq(irq, dev_id); + WARN_ON(devres_destroy(dev, devm_irq_release, devm_irq_match, + &match_data)); +} +EXPORT_SYMBOL(devm_free_irq); diff --git a/kernel/resource.c b/kernel/resource.c index 7b9a497419d9..2a3f88636580 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -617,6 +618,67 @@ void __release_region(struct resource *parent, resource_size_t start, } EXPORT_SYMBOL(__release_region); +/* + * Managed region resource + */ +struct region_devres { + struct resource *parent; + resource_size_t start; + resource_size_t n; +}; + +static void devm_region_release(struct device *dev, void *res) +{ + struct region_devres *this = res; + + __release_region(this->parent, this->start, this->n); +} + +static int devm_region_match(struct device *dev, void *res, void *match_data) +{ + struct region_devres *this = res, *match = match_data; + + return this->parent == match->parent && + this->start == match->start && this->n == match->n; +} + +struct resource * __devm_request_region(struct device *dev, + struct resource *parent, resource_size_t start, + resource_size_t n, const char *name) +{ + struct region_devres *dr = NULL; + struct resource *res; + + dr = devres_alloc(devm_region_release, sizeof(struct region_devres), + GFP_KERNEL); + if (!dr) + return NULL; + + dr->parent = parent; + dr->start = start; + dr->n = n; + + res = __request_region(parent, start, n, name); + if (res) + devres_add(dev, dr); + else + devres_free(dr); + + return res; +} +EXPORT_SYMBOL(__devm_request_region); + +void __devm_release_region(struct device *dev, struct resource *parent, + resource_size_t start, resource_size_t n) +{ + struct region_devres match_data = { parent, start, n }; + + __release_region(parent, start, n); + WARN_ON(devres_destroy(dev, devm_region_release, devm_region_match, + &match_data)); +} +EXPORT_SYMBOL(__devm_release_region); + /* * Called from init/main.c to reserve IO ports. */ diff --git a/lib/Makefile b/lib/Makefile index 77b4bad7d441..29b2e9912bbb 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -5,7 +5,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \ - sha1.o irq_regs.o reciprocal_div.o + sha1.o irq_regs.o reciprocal_div.o iomap.o lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o @@ -41,7 +41,6 @@ obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o obj-$(CONFIG_CRC16) += crc16.o obj-$(CONFIG_CRC32) += crc32.o obj-$(CONFIG_LIBCRC32C) += libcrc32c.o -obj-$(CONFIG_GENERIC_IOMAP) += iomap.o obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/ diff --git a/lib/iomap.c b/lib/iomap.c index d6ccdd85df53..3214028141da 100644 --- a/lib/iomap.c +++ b/lib/iomap.c @@ -4,8 +4,10 @@ * (C) Copyright 2004 Linus Torvalds */ #include +#include + +#ifdef CONFIG_GENERIC_IOMAP #include -#include /* * Read/write from/to an (offsettable) iomem cookie. It might be a PIO @@ -254,3 +256,245 @@ void pci_iounmap(struct pci_dev *dev, void __iomem * addr) } EXPORT_SYMBOL(pci_iomap); EXPORT_SYMBOL(pci_iounmap); + +#endif /* CONFIG_GENERIC_IOMAP */ + +/* + * Generic iomap devres + */ +static void devm_ioport_map_release(struct device *dev, void *res) +{ + ioport_unmap(*(void __iomem **)res); +} + +static int devm_ioport_map_match(struct device *dev, void *res, + void *match_data) +{ + return *(void **)res == match_data; +} + +/** + * devm_ioport_map - Managed ioport_map() + * @dev: Generic device to map ioport for + * @port: Port to map + * @nr: Number of ports to map + * + * Managed ioport_map(). Map is automatically unmapped on driver + * detach. + */ +void __iomem * devm_ioport_map(struct device *dev, unsigned long port, + unsigned int nr) +{ + void __iomem **ptr, *addr; + + ptr = devres_alloc(devm_ioport_map_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return NULL; + + addr = ioport_map(port, nr); + if (addr) { + *ptr = addr; + devres_add(dev, ptr); + } else + devres_free(ptr); + + return addr; +} +EXPORT_SYMBOL(devm_ioport_map); + +/** + * devm_ioport_unmap - Managed ioport_unmap() + * @dev: Generic device to unmap for + * @addr: Address to unmap + * + * Managed ioport_unmap(). @addr must have been mapped using + * devm_ioport_map(). + */ +void devm_ioport_unmap(struct device *dev, void __iomem *addr) +{ + ioport_unmap(addr); + WARN_ON(devres_destroy(dev, devm_ioport_map_release, + devm_ioport_map_match, (void *)addr)); +} +EXPORT_SYMBOL(devm_ioport_unmap); + +static void devm_ioremap_release(struct device *dev, void *res) +{ + iounmap(*(void __iomem **)res); +} + +static int devm_ioremap_match(struct device *dev, void *res, void *match_data) +{ + return *(void **)res == match_data; +} + +/** + * devm_ioremap - Managed ioremap() + * @dev: Generic device to remap IO address for + * @offset: BUS offset to map + * @size: Size of map + * + * Managed ioremap(). Map is automatically unmapped on driver detach. + */ +void __iomem *devm_ioremap(struct device *dev, unsigned long offset, + unsigned long size) +{ + void __iomem **ptr, *addr; + + ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return NULL; + + addr = ioremap(offset, size); + if (addr) { + *ptr = addr; + devres_add(dev, ptr); + } else + devres_free(ptr); + + return addr; +} +EXPORT_SYMBOL(devm_ioremap); + +/** + * devm_ioremap_nocache - Managed ioremap_nocache() + * @dev: Generic device to remap IO address for + * @offset: BUS offset to map + * @size: Size of map + * + * Managed ioremap_nocache(). Map is automatically unmapped on driver + * detach. + */ +void __iomem *devm_ioremap_nocache(struct device *dev, unsigned long offset, + unsigned long size) +{ + void __iomem **ptr, *addr; + + ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return NULL; + + addr = ioremap_nocache(offset, size); + if (addr) { + *ptr = addr; + devres_add(dev, ptr); + } else + devres_free(ptr); + + return addr; +} +EXPORT_SYMBOL(devm_ioremap_nocache); + +/** + * devm_iounmap - Managed iounmap() + * @dev: Generic device to unmap for + * @addr: Address to unmap + * + * Managed iounmap(). @addr must have been mapped using devm_ioremap*(). + */ +void devm_iounmap(struct device *dev, void __iomem *addr) +{ + iounmap(addr); + WARN_ON(devres_destroy(dev, devm_ioremap_release, devm_ioremap_match, + (void *)addr)); +} +EXPORT_SYMBOL(devm_iounmap); + +/* + * PCI iomap devres + */ +#define PCIM_IOMAP_MAX PCI_ROM_RESOURCE + +struct pcim_iomap_devres { + void __iomem *table[PCIM_IOMAP_MAX]; +}; + +static void pcim_iomap_release(struct device *gendev, void *res) +{ + struct pci_dev *dev = container_of(gendev, struct pci_dev, dev); + struct pcim_iomap_devres *this = res; + int i; + + for (i = 0; i < PCIM_IOMAP_MAX; i++) + if (this->table[i]) + pci_iounmap(dev, this->table[i]); +} + +/** + * pcim_iomap_table - access iomap allocation table + * @pdev: PCI device to access iomap table for + * + * Access iomap allocation table for @dev. If iomap table doesn't + * exist and @pdev is managed, it will be allocated. All iomaps + * recorded in the iomap table are automatically unmapped on driver + * detach. + * + * This function might sleep when the table is first allocated but can + * be safely called without context and guaranteed to succed once + * allocated. + */ +void __iomem * const * pcim_iomap_table(struct pci_dev *pdev) +{ + struct pcim_iomap_devres *dr, *new_dr; + + dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL); + if (dr) + return dr->table; + + new_dr = devres_alloc(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL); + if (!new_dr) + return NULL; + dr = devres_get(&pdev->dev, new_dr, NULL, NULL); + return dr->table; +} +EXPORT_SYMBOL(pcim_iomap_table); + +/** + * pcim_iomap - Managed pcim_iomap() + * @pdev: PCI device to iomap for + * @bar: BAR to iomap + * @maxlen: Maximum length of iomap + * + * Managed pci_iomap(). Map is automatically unmapped on driver + * detach. + */ +void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen) +{ + void __iomem **tbl; + + BUG_ON(bar >= PCIM_IOMAP_MAX); + + tbl = (void __iomem **)pcim_iomap_table(pdev); + if (!tbl || tbl[bar]) /* duplicate mappings not allowed */ + return NULL; + + tbl[bar] = pci_iomap(pdev, bar, maxlen); + return tbl[bar]; +} +EXPORT_SYMBOL(pcim_iomap); + +/** + * pcim_iounmap - Managed pci_iounmap() + * @pdev: PCI device to iounmap for + * @addr: Address to unmap + * + * Managed pci_iounmap(). @addr must have been mapped using pcim_iomap(). + */ +void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr) +{ + void __iomem **tbl; + int i; + + pci_iounmap(pdev, addr); + + tbl = (void __iomem **)pcim_iomap_table(pdev); + BUG_ON(!tbl); + + for (i = 0; i < PCIM_IOMAP_MAX; i++) + if (tbl[i] == addr) { + tbl[i] = NULL; + return; + } + WARN_ON(1); +} +EXPORT_SYMBOL(pcim_iounmap); -- cgit v1.2.3 From 0529c159dbdd79794796c1b50b39442d72efbe97 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 20 Jan 2007 16:00:26 +0900 Subject: libata: implement ata_host_detach() Implement ata_host_detach() which calls ata_port_detach() for each port in the host and export it. ata_port_detach() is now internal and thus un-exported. ata_host_detach() will be used as the 'deregister from libata layer' function after devres conversion. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 3 +-- drivers/ata/libata-core.c | 22 +++++++++++++++++++--- include/linux/libata.h | 2 +- 3 files changed, 21 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 03b7a0051887..649dfa57e51c 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1792,8 +1792,7 @@ static void ahci_remove_one (struct pci_dev *pdev) unsigned int i; int have_msi; - for (i = 0; i < host->n_ports; i++) - ata_port_detach(host->ports[i]); + ata_host_detach(host); have_msi = hpriv->flags & AHCI_FLAG_MSI; free_irq(host->irq, host); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 781d0959a228..a927c4c8bef3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5991,6 +5991,23 @@ void ata_port_detach(struct ata_port *ap) scsi_remove_host(ap->scsi_host); } +/** + * ata_host_detach - Detach all ports of an ATA host + * @host: Host to detach + * + * Detach all ports of @host. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_host_detach(struct ata_host *host) +{ + int i; + + for (i = 0; i < host->n_ports; i++) + ata_port_detach(host->ports[i]); +} + /** * ata_host_remove - PCI layer callback for device removal * @host: ATA host set that was removed @@ -6006,8 +6023,7 @@ void ata_host_remove(struct ata_host *host) { unsigned int i; - for (i = 0; i < host->n_ports; i++) - ata_port_detach(host->ports[i]); + ata_host_detach(host); free_irq(host->irq, host); if (host->irq2) @@ -6382,7 +6398,7 @@ EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_host_init); EXPORT_SYMBOL_GPL(ata_device_add); -EXPORT_SYMBOL_GPL(ata_port_detach); +EXPORT_SYMBOL_GPL(ata_host_detach); EXPORT_SYMBOL_GPL(ata_host_remove); EXPORT_SYMBOL_GPL(ata_sg_init); EXPORT_SYMBOL_GPL(ata_sg_init_one); diff --git a/include/linux/libata.h b/include/linux/libata.h index a2458dfefb17..e9a0cfdcfe2c 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -719,7 +719,7 @@ extern int ata_pci_device_resume(struct pci_dev *pdev); extern int ata_pci_clear_simplex(struct pci_dev *pdev); #endif /* CONFIG_PCI */ extern int ata_device_add(const struct ata_probe_ent *ent); -extern void ata_port_detach(struct ata_port *ap); +extern void ata_host_detach(struct ata_host *host); extern void ata_host_init(struct ata_host *, struct device *, unsigned long, const struct ata_port_operations *); extern void ata_host_remove(struct ata_host *host); -- cgit v1.2.3 From f0d36efdc624beb3d9e29b9ab9e9537bf0f25d5b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 20 Jan 2007 16:00:28 +0900 Subject: libata: update libata core layer to use devres Update libata core layer to use devres. * ata_device_add() acquires all resources in managed mode. * ata_host is allocated as devres associated with ata_host_release. * Port attached status is handled as devres associated with ata_host_attach_release(). * Initialization failure and host removal is handedl by releasing devres group. * Except for ata_scsi_release() removal, LLD interface remains the same. Some functions use hacky is_managed test to support both managed and unmanaged devices. These will go away once all LLDs are updated to use devres. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 21 ++---- drivers/ata/libata-core.c | 177 ++++++++++++++++++++-------------------------- drivers/ata/libata-scsi.c | 3 +- drivers/ata/libata-sff.c | 56 ++++++--------- include/linux/libata.h | 9 ++- 5 files changed, 106 insertions(+), 160 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 649dfa57e51c..d72568392e6c 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1784,37 +1784,24 @@ err_out: return rc; } -static void ahci_remove_one (struct pci_dev *pdev) +static void ahci_remove_one(struct pci_dev *pdev) { struct device *dev = pci_dev_to_dev(pdev); struct ata_host *host = dev_get_drvdata(dev); struct ahci_host_priv *hpriv = host->private_data; - unsigned int i; - int have_msi; - ata_host_detach(host); + ata_host_remove(host); - have_msi = hpriv->flags & AHCI_FLAG_MSI; - free_irq(host->irq, host); - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - - ata_scsi_release(ap->scsi_host); - scsi_host_put(ap->scsi_host); - } - - kfree(hpriv); pci_iounmap(pdev, host->mmio_base); - kfree(host); - if (have_msi) + if (hpriv->flags & AHCI_FLAG_MSI) pci_disable_msi(pdev); else pci_intx(pdev, 0); pci_release_regions(pdev); pci_disable_device(pdev); dev_set_drvdata(dev, NULL); + kfree(hpriv); } static int __init ahci_init(void) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index a927c4c8bef3..20b2409a0d20 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5486,28 +5486,25 @@ void ata_host_resume(struct ata_host *host) * LOCKING: * Inherited from caller. */ - -int ata_port_start (struct ata_port *ap) +int ata_port_start(struct ata_port *ap) { struct device *dev = ap->dev; int rc; - ap->prd = dma_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, GFP_KERNEL); + ap->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, + GFP_KERNEL); if (!ap->prd) return -ENOMEM; rc = ata_pad_alloc(ap, dev); - if (rc) { - dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); + if (rc) return rc; - } - - DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma); + DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, + (unsigned long long)ap->prd_dma); return 0; } - /** * ata_port_stop - Undo ata_port_start() * @ap: Port to shut down @@ -5519,12 +5516,11 @@ int ata_port_start (struct ata_port *ap) * LOCKING: * Inherited from caller. */ - void ata_port_stop (struct ata_port *ap) { struct device *dev = ap->dev; - dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); + dmam_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); ata_pad_free(ap, dev); } @@ -5707,6 +5703,27 @@ static struct ata_port * ata_port_add(const struct ata_probe_ent *ent, return ap; } +static void ata_host_release(struct device *gendev, void *res) +{ + struct ata_host *host = dev_get_drvdata(gendev); + int i; + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (!ap) + continue; + + if (ap->ops->port_stop) + ap->ops->port_stop(ap); + + scsi_host_put(ap->scsi_host); + } + + if (host->ops->host_stop) + host->ops->host_stop(host); +} + /** * ata_sas_host_init - Initialize a host struct * @host: host to initialize @@ -5759,11 +5776,17 @@ int ata_device_add(const struct ata_probe_ent *ent) dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n"); return 0; } + + if (!devres_open_group(dev, ata_device_add, GFP_KERNEL)) + return 0; + /* alloc a container for our list of ATA ports (buses) */ - host = kzalloc(sizeof(struct ata_host) + - (ent->n_ports * sizeof(void *)), GFP_KERNEL); + host = devres_alloc(ata_host_release, sizeof(struct ata_host) + + (ent->n_ports * sizeof(void *)), GFP_KERNEL); if (!host) - return 0; + goto err_out; + devres_add(dev, host); + dev_set_drvdata(dev, host); ata_host_init(host, dev, ent->_host_flags, ent->port_ops); host->n_ports = ent->n_ports; @@ -5821,8 +5844,8 @@ int ata_device_add(const struct ata_probe_ent *ent) } /* obtain irq, that may be shared between channels */ - rc = request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags, - DRV_NAME, host); + rc = devm_request_irq(dev, ent->irq, ent->port_ops->irq_handler, + ent->irq_flags, DRV_NAME, host); if (rc) { dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n", ent->irq, rc); @@ -5835,15 +5858,19 @@ int ata_device_add(const struct ata_probe_ent *ent) so trap it now */ BUG_ON(ent->irq == ent->irq2); - rc = request_irq(ent->irq2, ent->port_ops->irq_handler, ent->irq_flags, - DRV_NAME, host); + rc = devm_request_irq(dev, ent->irq2, + ent->port_ops->irq_handler, ent->irq_flags, + DRV_NAME, host); if (rc) { dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n", ent->irq2, rc); - goto err_out_free_irq; + goto err_out; } } + /* resource acquisition complete */ + devres_close_group(dev, ata_device_add); + /* perform each probe synchronously */ DPRINTK("probe begin\n"); for (i = 0; i < host->n_ports; i++) { @@ -5912,24 +5939,13 @@ int ata_device_add(const struct ata_probe_ent *ent) ata_scsi_scan_host(ap); } - dev_set_drvdata(dev, host); - VPRINTK("EXIT, returning %u\n", ent->n_ports); return ent->n_ports; /* success */ -err_out_free_irq: - free_irq(ent->irq, host); -err_out: - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - if (ap) { - ap->ops->port_stop(ap); - scsi_host_put(ap->scsi_host); - } - } - - kfree(host); - VPRINTK("EXIT, returning 0\n"); + err_out: + devres_release_group(dev, ata_device_add); + dev_set_drvdata(dev, NULL); + VPRINTK("EXIT, returning %d\n", rc); return 0; } @@ -6018,66 +6034,10 @@ void ata_host_detach(struct ata_host *host) * LOCKING: * Inherited from calling layer (may sleep). */ - void ata_host_remove(struct ata_host *host) { - unsigned int i; - ata_host_detach(host); - - free_irq(host->irq, host); - if (host->irq2) - free_irq(host->irq2, host); - - for (i = 0; i < host->n_ports; i++) { - struct ata_port *ap = host->ports[i]; - - ata_scsi_release(ap->scsi_host); - - if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) { - struct ata_ioports *ioaddr = &ap->ioaddr; - - /* FIXME: Add -ac IDE pci mods to remove these special cases */ - if (ioaddr->cmd_addr == ATA_PRIMARY_CMD) - release_region(ATA_PRIMARY_CMD, 8); - else if (ioaddr->cmd_addr == ATA_SECONDARY_CMD) - release_region(ATA_SECONDARY_CMD, 8); - } - - scsi_host_put(ap->scsi_host); - } - - if (host->ops->host_stop) - host->ops->host_stop(host); - - kfree(host); -} - -/** - * ata_scsi_release - SCSI layer callback hook for host unload - * @shost: libata host to be unloaded - * - * Performs all duties necessary to shut down a libata port... - * Kill port kthread, disable port, and release resources. - * - * LOCKING: - * Inherited from SCSI layer. - * - * RETURNS: - * One. - */ - -int ata_scsi_release(struct Scsi_Host *shost) -{ - struct ata_port *ap = ata_shost_to_port(shost); - - DPRINTK("ENTER\n"); - - ap->ops->port_disable(ap); - ap->ops->port_stop(ap); - - DPRINTK("EXIT\n"); - return 1; + devres_release_group(host->dev, ata_device_add); } struct ata_probe_ent * @@ -6085,7 +6045,11 @@ ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) { struct ata_probe_ent *probe_ent; - probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL); + /* XXX - the following if can go away once all LLDs are managed */ + if (!list_empty(&dev->devres_head)) + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + else + probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL); if (!probe_ent) { printk(KERN_ERR DRV_NAME "(%s): out of memory\n", kobject_name(&(dev->kobj))); @@ -6139,7 +6103,11 @@ void ata_pci_host_stop (struct ata_host *host) { struct pci_dev *pdev = to_pci_dev(host->dev); - pci_iounmap(pdev, host->mmio_base); + /* XXX - the following if can go away once all LLDs are managed */ + if (!list_empty(&host->dev->devres_head)) + pcim_iounmap(pdev, host->mmio_base); + else + pci_iounmap(pdev, host->mmio_base); } /** @@ -6155,17 +6123,19 @@ void ata_pci_host_stop (struct ata_host *host) * LOCKING: * Inherited from PCI layer (may sleep). */ - -void ata_pci_remove_one (struct pci_dev *pdev) +void ata_pci_remove_one(struct pci_dev *pdev) { struct device *dev = pci_dev_to_dev(pdev); struct ata_host *host = dev_get_drvdata(dev); - ata_host_remove(host); - - pci_release_regions(pdev); - pci_disable_device(pdev); - dev_set_drvdata(dev, NULL); + /* XXX - the following if can go away once all LLDs are managed */ + if (!list_empty(&host->dev->devres_head)) { + ata_host_remove(host); + pci_release_regions(pdev); + pci_disable_device(pdev); + dev_set_drvdata(dev, NULL); + } else + ata_host_detach(host); } /* move to PCI subsystem */ @@ -6219,7 +6189,11 @@ int ata_pci_device_do_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - rc = pci_enable_device(pdev); + /* XXX - the following if can go away once all LLDs are managed */ + if (!list_empty(&pdev->dev.devres_head)) + rc = pcim_enable_device(pdev); + else + rc = pci_enable_device(pdev); if (rc) { dev_printk(KERN_ERR, &pdev->dev, "failed to enable device after resume (%d)\n", rc); @@ -6458,7 +6432,6 @@ EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy); EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth); -EXPORT_SYMBOL_GPL(ata_scsi_release); EXPORT_SYMBOL_GPL(ata_host_intr); EXPORT_SYMBOL_GPL(sata_scr_valid); EXPORT_SYMBOL_GPL(sata_scr_read); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index cc229e31432f..0009818a4306 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3305,7 +3305,8 @@ EXPORT_SYMBOL_GPL(ata_sas_port_init); void ata_sas_port_destroy(struct ata_port *ap) { - ap->ops->port_stop(ap); + if (ap->ops->port_stop) + ap->ops->port_stop(ap); kfree(ap); } EXPORT_SYMBOL_GPL(ata_sas_port_destroy); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 9bbc8749620a..21efe92a7135 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1006,15 +1006,18 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, unsigned int n_ports) { + struct device *dev = &pdev->dev; struct ata_probe_ent *probe_ent = NULL; struct ata_port_info *port[2]; u8 mask; unsigned int legacy_mode = 0; - int disable_dev_on_err = 1; int rc; DPRINTK("ENTER\n"); + if (!devres_open_group(dev, NULL, GFP_KERNEL)) + return -ENOMEM; + BUG_ON(n_ports < 1 || n_ports > 2); port[0] = port_info[0]; @@ -1031,9 +1034,9 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, boot for the primary video which is BIOS enabled */ - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) - return rc; + goto err_out; if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { u8 tmp8; @@ -1049,7 +1052,8 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, left a device in compatibility mode */ if (legacy_mode) { printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); - return -EOPNOTSUPP; + rc = -EOPNOTSUPP; + goto err_out; } #endif } @@ -1057,13 +1061,13 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, if (!legacy_mode) { rc = pci_request_regions(pdev, DRV_NAME); if (rc) { - disable_dev_on_err = 0; + pcim_pin_device(pdev); goto err_out; } } else { /* Deal with combined mode hack. This side of the logic all goes away once the combined mode hack is killed in 2.6.21 */ - if (!request_region(ATA_PRIMARY_CMD, 8, "libata")) { + if (!devm_request_region(dev, ATA_PRIMARY_CMD, 8, "libata")) { struct resource *conflict, res; res.start = ATA_PRIMARY_CMD; res.end = ATA_PRIMARY_CMD + 8 - 1; @@ -1073,7 +1077,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, if (!strcmp(conflict->name, "libata")) legacy_mode |= ATA_PORT_PRIMARY; else { - disable_dev_on_err = 0; + pcim_pin_device(pdev); printk(KERN_WARNING "ata: 0x%0X IDE port busy\n" \ "ata: conflict with %s\n", ATA_PRIMARY_CMD, @@ -1082,7 +1086,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, } else legacy_mode |= ATA_PORT_PRIMARY; - if (!request_region(ATA_SECONDARY_CMD, 8, "libata")) { + if (!devm_request_region(dev, ATA_SECONDARY_CMD, 8, "libata")) { struct resource *conflict, res; res.start = ATA_SECONDARY_CMD; res.end = ATA_SECONDARY_CMD + 8 - 1; @@ -1092,7 +1096,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, if (!strcmp(conflict->name, "libata")) legacy_mode |= ATA_PORT_SECONDARY; else { - disable_dev_on_err = 0; + pcim_pin_device(pdev); printk(KERN_WARNING "ata: 0x%X IDE port busy\n" \ "ata: conflict with %s\n", ATA_SECONDARY_CMD, @@ -1112,16 +1116,16 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, /* we have legacy mode, but all ports are unavailable */ if (legacy_mode == (1 << 3)) { rc = -EBUSY; - goto err_out_regions; + goto err_out; } /* TODO: If we get no DMA mask we should fall back to PIO */ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + goto err_out; rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); if (rc) - goto err_out_regions; + goto err_out; if (legacy_mode) { probe_ent = ata_pci_init_legacy_port(pdev, port, legacy_mode); @@ -1133,40 +1137,22 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, } if (!probe_ent) { rc = -ENOMEM; - goto err_out_regions; + goto err_out; } pci_set_master(pdev); if (!ata_device_add(probe_ent)) { rc = -ENODEV; - goto err_out_ent; + goto err_out; } - kfree(probe_ent); - + devm_kfree(dev, probe_ent); + devres_remove_group(dev, NULL); return 0; -err_out_ent: - kfree(probe_ent); -err_out_regions: - /* All this conditional stuff is needed for the combined mode hack - until 2.6.21 when it can go */ - if (legacy_mode) { - pci_release_region(pdev, 4); - if (legacy_mode & ATA_PORT_PRIMARY) { - release_region(ATA_PRIMARY_CMD, 8); - pci_release_region(pdev, 1); - } - if (legacy_mode & ATA_PORT_SECONDARY) { - release_region(ATA_SECONDARY_CMD, 8); - pci_release_region(pdev, 3); - } - } else - pci_release_regions(pdev); err_out: - if (disable_dev_on_err) - pci_disable_device(pdev); + devres_release_group(dev, NULL); return rc; } diff --git a/include/linux/libata.h b/include/linux/libata.h index e9a0cfdcfe2c..f96277ed184f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include @@ -726,7 +726,6 @@ extern void ata_host_remove(struct ata_host *host); 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 int ata_scsi_release(struct Scsi_Host *host); 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 *); @@ -1227,14 +1226,14 @@ static inline unsigned int __ac_err_mask(u8 status) static inline int ata_pad_alloc(struct ata_port *ap, struct device *dev) { ap->pad_dma = 0; - ap->pad = dma_alloc_coherent(dev, ATA_DMA_PAD_BUF_SZ, - &ap->pad_dma, GFP_KERNEL); + ap->pad = dmam_alloc_coherent(dev, ATA_DMA_PAD_BUF_SZ, + &ap->pad_dma, GFP_KERNEL); return (ap->pad == NULL) ? -ENOMEM : 0; } static inline void ata_pad_free(struct ata_port *ap, struct device *dev) { - dma_free_coherent(dev, ATA_DMA_PAD_BUF_SZ, ap->pad, ap->pad_dma); + dmam_free_coherent(dev, ATA_DMA_PAD_BUF_SZ, ap->pad, ap->pad_dma); } static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host) -- cgit v1.2.3 From b878ca5d37953ad1c4578b225a13a3c3e7e743b7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 20 Jan 2007 16:00:28 +0900 Subject: libata: remove unused functions Now that all LLDs are converted to use devres, default stop callbacks are unused. Remove them. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 81 ++++------------------------------------------- include/linux/libata.h | 4 --- 2 files changed, 6 insertions(+), 79 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 20b2409a0d20..b3091de894c2 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5505,31 +5505,6 @@ int ata_port_start(struct ata_port *ap) return 0; } -/** - * ata_port_stop - Undo ata_port_start() - * @ap: Port to shut down - * - * Frees the PRD table. - * - * May be used as the port_stop() entry in ata_port_operations. - * - * LOCKING: - * Inherited from caller. - */ -void ata_port_stop (struct ata_port *ap) -{ - struct device *dev = ap->dev; - - dmam_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); - ata_pad_free(ap, dev); -} - -void ata_host_stop (struct ata_host *host) -{ - if (host->mmio_base) - iounmap(host->mmio_base); -} - /** * ata_dev_init - Initialize an ata_device structure * @dev: Device structure to initialize @@ -5869,7 +5844,7 @@ int ata_device_add(const struct ata_probe_ent *ent) } /* resource acquisition complete */ - devres_close_group(dev, ata_device_add); + devres_remove_group(dev, ata_device_add); /* perform each probe synchronously */ DPRINTK("probe begin\n"); @@ -6024,22 +5999,6 @@ void ata_host_detach(struct ata_host *host) ata_port_detach(host->ports[i]); } -/** - * ata_host_remove - PCI layer callback for device removal - * @host: ATA host set that was removed - * - * Unregister all objects associated with this host set. Free those - * objects. - * - * LOCKING: - * Inherited from calling layer (may sleep). - */ -void ata_host_remove(struct ata_host *host) -{ - ata_host_detach(host); - devres_release_group(host->dev, ata_device_add); -} - struct ata_probe_ent * ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) { @@ -6099,26 +6058,13 @@ void ata_std_ports(struct ata_ioports *ioaddr) #ifdef CONFIG_PCI -void ata_pci_host_stop (struct ata_host *host) -{ - struct pci_dev *pdev = to_pci_dev(host->dev); - - /* XXX - the following if can go away once all LLDs are managed */ - if (!list_empty(&host->dev->devres_head)) - pcim_iounmap(pdev, host->mmio_base); - else - pci_iounmap(pdev, host->mmio_base); -} - /** * ata_pci_remove_one - PCI layer callback for device removal * @pdev: PCI device that was removed * - * PCI layer indicates to libata via this hook that - * hot-unplug or module unload event has occurred. - * Handle this by unregistering all objects associated - * with this PCI device. Free those objects. Then finally - * release PCI resources and disable device. + * PCI layer indicates to libata via this hook that hot-unplug or + * module unload event has occurred. Detach all ports. Resource + * release is handled via devres. * * LOCKING: * Inherited from PCI layer (may sleep). @@ -6128,14 +6074,7 @@ void ata_pci_remove_one(struct pci_dev *pdev) struct device *dev = pci_dev_to_dev(pdev); struct ata_host *host = dev_get_drvdata(dev); - /* XXX - the following if can go away once all LLDs are managed */ - if (!list_empty(&host->dev->devres_head)) { - ata_host_remove(host); - pci_release_regions(pdev); - pci_disable_device(pdev); - dev_set_drvdata(dev, NULL); - } else - ata_host_detach(host); + ata_host_detach(host); } /* move to PCI subsystem */ @@ -6189,11 +6128,7 @@ int ata_pci_device_do_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - /* XXX - the following if can go away once all LLDs are managed */ - if (!list_empty(&pdev->dev.devres_head)) - rc = pcim_enable_device(pdev); - else - rc = pci_enable_device(pdev); + rc = pcim_enable_device(pdev); if (rc) { dev_printk(KERN_ERR, &pdev->dev, "failed to enable device after resume (%d)\n", rc); @@ -6373,7 +6308,6 @@ EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_host_init); EXPORT_SYMBOL_GPL(ata_device_add); EXPORT_SYMBOL_GPL(ata_host_detach); -EXPORT_SYMBOL_GPL(ata_host_remove); EXPORT_SYMBOL_GPL(ata_sg_init); EXPORT_SYMBOL_GPL(ata_sg_init_one); EXPORT_SYMBOL_GPL(ata_hsm_move); @@ -6390,8 +6324,6 @@ EXPORT_SYMBOL_GPL(ata_check_status); EXPORT_SYMBOL_GPL(ata_altstatus); EXPORT_SYMBOL_GPL(ata_exec_command); EXPORT_SYMBOL_GPL(ata_port_start); -EXPORT_SYMBOL_GPL(ata_port_stop); -EXPORT_SYMBOL_GPL(ata_host_stop); EXPORT_SYMBOL_GPL(ata_interrupt); EXPORT_SYMBOL_GPL(ata_mmio_data_xfer); EXPORT_SYMBOL_GPL(ata_pio_data_xfer); @@ -6452,7 +6384,6 @@ EXPORT_SYMBOL_GPL(ata_timing_merge); #ifdef CONFIG_PCI EXPORT_SYMBOL_GPL(pci_test_config_bits); -EXPORT_SYMBOL_GPL(ata_pci_host_stop); EXPORT_SYMBOL_GPL(ata_pci_init_native_mode); EXPORT_SYMBOL_GPL(ata_pci_init_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); diff --git a/include/linux/libata.h b/include/linux/libata.h index f96277ed184f..cebbcc8d45fd 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -722,7 +722,6 @@ extern int ata_device_add(const struct ata_probe_ent *ent); extern void ata_host_detach(struct ata_host *host); extern void ata_host_init(struct ata_host *, struct device *, unsigned long, const struct ata_port_operations *); -extern void ata_host_remove(struct ata_host *host); 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 *)); @@ -768,8 +767,6 @@ extern u8 ata_check_status(struct ata_port *ap); extern u8 ata_altstatus(struct ata_port *ap); extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); extern int ata_port_start (struct ata_port *ap); -extern void ata_port_stop (struct ata_port *ap); -extern void ata_host_stop (struct ata_host *host); extern irqreturn_t ata_interrupt (int irq, void *dev_instance); extern void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data); @@ -856,7 +853,6 @@ struct pci_bits { unsigned long val; }; -extern void ata_pci_host_stop (struct ata_host *host); extern struct ata_probe_ent * ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int portmask); extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits); -- cgit v1.2.3 From d24bbbf251e70bf984cbaa9b1fcadc5f56fc3ae9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 20 Jan 2007 16:00:28 +0900 Subject: devres: implement pcim_iomap_regions() Implement pcim_iomap_regions(). This function takes mask of BARs to request and iomap. No BAR should have length of zero. BARs are iomapped using pcim_iomap_table(). Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- include/linux/io.h | 2 ++ lib/iomap.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) (limited to 'include/linux') diff --git a/include/linux/io.h b/include/linux/io.h index f5edf9c5de0a..45a9c944cb0a 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -45,6 +45,8 @@ void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr); void __iomem * const * pcim_iomap_table(struct pci_dev *pdev); +int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name); + /** * check_signature - find BIOS signatures * @io_addr: mmio address to check diff --git a/lib/iomap.c b/lib/iomap.c index 3214028141da..4990c736bc4b 100644 --- a/lib/iomap.c +++ b/lib/iomap.c @@ -498,3 +498,56 @@ void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr) WARN_ON(1); } EXPORT_SYMBOL(pcim_iounmap); + +/** + * pcim_iomap_regions - Request and iomap PCI BARs + * @pdev: PCI device to map IO resources for + * @mask: Mask of BARs to request and iomap + * @name: Name used when requesting regions + * + * Request and iomap regions specified by @mask. + */ +int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name) +{ + void __iomem * const *iomap; + int i, rc; + + iomap = pcim_iomap_table(pdev); + if (!iomap) + return -ENOMEM; + + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + unsigned long len; + + if (!(mask & (1 << i))) + continue; + + rc = -EINVAL; + len = pci_resource_len(pdev, i); + if (!len) + goto err_inval; + + rc = pci_request_region(pdev, i, name); + if (rc) + goto err_region; + + rc = -ENOMEM; + if (!pcim_iomap(pdev, i, 0)) + goto err_iomap; + } + + return 0; + + err_iomap: + pcim_iounmap(pdev, iomap[i]); + err_region: + pci_release_region(pdev, i); + err_inval: + while (--i >= 0) { + pcim_iounmap(pdev, iomap[i]); + pci_release_region(pdev, i); + } + + return rc; +} +EXPORT_SYMBOL(pcim_iomap_regions); -- cgit v1.2.3 From 0d5ff566779f894ca9937231a181eb31e4adff0e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 1 Feb 2007 15:06:36 +0900 Subject: libata: convert to iomap Convert libata core layer and LLDs to use iomap. * managed iomap is used. Pointer to pcim_iomap_table() is cached at host->iomap and used through out LLDs. This basically replaces host->mmio_base. * if possible, pcim_iomap_regions() is used Most iomap operation conversions are taken from Jeff Garzik 's iomap branch. Signed-off-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 79 +++--- drivers/ata/ata_generic.c | 4 +- drivers/ata/ata_piix.c | 6 +- drivers/ata/libata-core.c | 213 +++------------- drivers/ata/libata-sff.c | 544 ++++++++-------------------------------- 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_cmd64x.c | 6 +- drivers/ata/pata_cs5520.c | 33 ++- drivers/ata/pata_cs5530.c | 29 ++- 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 | 22 +- drivers/ata/pata_hpt3x2n.c | 22 +- drivers/ata/pata_hpt3x3.c | 2 +- drivers/ata/pata_isapnp.c | 15 +- drivers/ata/pata_it8213.c | 2 +- drivers/ata/pata_it821x.c | 6 +- drivers/ata/pata_ixp4xx_cf.c | 32 +-- drivers/ata/pata_jmicron.c | 2 +- drivers/ata/pata_legacy.c | 101 ++++---- drivers/ata/pata_marvell.c | 4 +- drivers/ata/pata_mpc52xx.c | 28 +-- drivers/ata/pata_mpiix.c | 61 ++--- drivers/ata/pata_netcell.c | 2 +- drivers/ata/pata_ns87410.c | 2 +- drivers/ata/pata_oldpiix.c | 2 +- drivers/ata/pata_opti.c | 20 +- drivers/ata/pata_optidma.c | 32 +-- drivers/ata/pata_pcmcia.c | 21 +- drivers/ata/pata_pdc2027x.c | 63 +++-- drivers/ata/pata_pdc202xx_old.c | 28 +-- drivers/ata/pata_platform.c | 50 ++-- drivers/ata/pata_qdi.c | 40 +-- 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 | 10 +- drivers/ata/pata_sl82c105.c | 2 +- drivers/ata/pata_triflex.c | 2 +- drivers/ata/pata_via.c | 4 +- drivers/ata/pata_winbond.c | 27 +- drivers/ata/pdc_adma.c | 47 ++-- drivers/ata/sata_inic162x.c | 32 +-- drivers/ata/sata_mv.c | 58 ++--- drivers/ata/sata_nv.c | 95 +++---- drivers/ata/sata_promise.c | 55 ++-- drivers/ata/sata_qstor.c | 54 ++-- drivers/ata/sata_sil.c | 46 ++-- drivers/ata/sata_sil24.c | 73 +++--- drivers/ata/sata_sis.c | 22 +- drivers/ata/sata_svw.c | 83 +++--- drivers/ata/sata_sx4.c | 88 +++---- drivers/ata/sata_uli.c | 21 +- drivers/ata/sata_via.c | 41 ++- drivers/ata/sata_vsc.c | 80 +++--- include/linux/libata.h | 68 +++-- 63 files changed, 977 insertions(+), 1448 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 20ab3ffce559..6d664849cc09 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -446,16 +446,12 @@ static inline int ahci_nr_ports(u32 cap) return (cap & 0x1f) + 1; } -static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port) +static inline void __iomem *ahci_port_base(void __iomem *base, + unsigned int port) { return base + 0x100 + (port * 0x80); } -static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port) -{ - return (void __iomem *) ahci_port_base_ul((unsigned long)base, port); -} - static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) { unsigned int sc_reg; @@ -469,7 +465,7 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) return 0xffffffffU; } - return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -487,7 +483,7 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, return; } - writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); } static void ahci_start_engine(void __iomem *port_mmio) @@ -729,7 +725,7 @@ static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev, static unsigned int ahci_dev_classify(struct ata_port *ap) { - void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; + void __iomem *port_mmio = ap->ioaddr.cmd_addr; struct ata_taskfile tf; u32 tmp; @@ -757,7 +753,7 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, static int ahci_clo(struct ata_port *ap) { - void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; + void __iomem *port_mmio = ap->ioaddr.cmd_addr; struct ahci_host_priv *hpriv = ap->host->private_data; u32 tmp; @@ -779,7 +775,7 @@ static int ahci_clo(struct ata_port *ap) static int ahci_softreset(struct ata_port *ap, unsigned int *class) { struct ahci_port_priv *pp = ap->private_data; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); const u32 cmd_fis_len = 5; /* five dwords */ const char *reason = NULL; @@ -887,7 +883,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) struct ahci_port_priv *pp = ap->private_data; u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; struct ata_taskfile tf; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); int rc; @@ -915,7 +911,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) { - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); int rc; @@ -940,7 +936,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class) static void ahci_postreset(struct ata_port *ap, unsigned int *class) { - void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; + void __iomem *port_mmio = ap->ioaddr.cmd_addr; u32 new_tmp, tmp; ata_std_postreset(ap, class); @@ -959,7 +955,7 @@ static void ahci_postreset(struct ata_port *ap, unsigned int *class) static u8 ahci_check_status(struct ata_port *ap) { - void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr; + void __iomem *mmio = ap->ioaddr.cmd_addr; return readl(mmio + PORT_TFDATA) & 0xFF; } @@ -1105,7 +1101,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) static void ahci_host_intr(struct ata_port *ap) { - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); struct ata_eh_info *ehi = &ap->eh_info; struct ahci_port_priv *pp = ap->private_data; @@ -1203,7 +1199,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance) VPRINTK("ENTER\n"); hpriv = host->private_data; - mmio = host->mmio_base; + mmio = host->iomap[AHCI_PCI_BAR]; /* sigh. 0xffffffff is a valid return from h/w */ irq_stat = readl(mmio + HOST_IRQ_STAT); @@ -1248,7 +1244,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance) static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; + void __iomem *port_mmio = ap->ioaddr.cmd_addr; if (qc->tf.protocol == ATA_PROT_NCQ) writel(1 << qc->tag, port_mmio + PORT_SCR_ACT); @@ -1260,7 +1256,7 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) static void ahci_freeze(struct ata_port *ap) { - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); /* turn IRQ off */ @@ -1269,7 +1265,7 @@ static void ahci_freeze(struct ata_port *ap) static void ahci_thaw(struct ata_port *ap) { - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); u32 tmp; @@ -1284,7 +1280,7 @@ static void ahci_thaw(struct ata_port *ap) static void ahci_error_handler(struct ata_port *ap) { - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); if (!(ap->pflags & ATA_PFLAG_FROZEN)) { @@ -1300,7 +1296,7 @@ static void ahci_error_handler(struct ata_port *ap) static void ahci_vt8251_error_handler(struct ata_port *ap) { - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); if (!(ap->pflags & ATA_PFLAG_FROZEN)) { @@ -1317,7 +1313,7 @@ static void ahci_vt8251_error_handler(struct ata_port *ap) static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); if (qc->flags & ATA_QCFLAG_FAILED) @@ -1334,7 +1330,7 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) { struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp = ap->private_data; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); const char *emsg = NULL; int rc; @@ -1355,7 +1351,7 @@ static int ahci_port_resume(struct ata_port *ap) { struct ahci_port_priv *pp = ap->private_data; struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); ahci_power_up(port_mmio, hpriv->cap); @@ -1367,7 +1363,7 @@ static int ahci_port_resume(struct ata_port *ap) static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) { struct ata_host *host = dev_get_drvdata(&pdev->dev); - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; u32 ctl; if (mesg.event == PM_EVENT_SUSPEND) { @@ -1388,7 +1384,7 @@ static int ahci_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); struct ahci_host_priv *hpriv = host->private_data; - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; int rc; rc = ata_pci_device_do_resume(pdev); @@ -1414,7 +1410,7 @@ static int ahci_port_start(struct ata_port *ap) struct device *dev = ap->host->dev; struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_port_priv *pp; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); void *mem; dma_addr_t mem_dma; @@ -1474,7 +1470,7 @@ static int ahci_port_start(struct ata_port *ap) static void ahci_port_stop(struct ata_port *ap) { struct ahci_host_priv *hpriv = ap->host->private_data; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR]; void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); const char *emsg = NULL; int rc; @@ -1485,11 +1481,11 @@ static void ahci_port_stop(struct ata_port *ap) ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc); } -static void ahci_setup_port(struct ata_ioports *port, unsigned long base, +static void ahci_setup_port(struct ata_ioports *port, void __iomem *base, unsigned int port_idx) { VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx); - base = ahci_port_base_ul(base, port_idx); + base = ahci_port_base(base, port_idx); VPRINTK("base now==0x%lx\n", base); port->cmd_addr = base; @@ -1502,7 +1498,7 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) { struct ahci_host_priv *hpriv = probe_ent->private_data; struct pci_dev *pdev = to_pci_dev(probe_ent->dev); - void __iomem *mmio = probe_ent->mmio_base; + void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR]; unsigned int i, cap_n_ports, using_dac; int rc; @@ -1569,7 +1565,7 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) } for (i = 0; i < probe_ent->n_ports; i++) - ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i); + ahci_setup_port(&probe_ent->port[i], mmio, i); ahci_init_controller(mmio, pdev, probe_ent->n_ports, probe_ent->port_flags, hpriv); @@ -1583,7 +1579,7 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent) { struct ahci_host_priv *hpriv = probe_ent->private_data; struct pci_dev *pdev = to_pci_dev(probe_ent->dev); - void __iomem *mmio = probe_ent->mmio_base; + void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR]; u32 vers, cap, impl, speed; const char *speed_s; u16 cc; @@ -1657,8 +1653,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct device *dev = &pdev->dev; struct ata_probe_ent *probe_ent; struct ahci_host_priv *hpriv; - unsigned long base; - void __iomem *mmio_base; int rc; VPRINTK("ENTER\n"); @@ -1679,11 +1673,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { + rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME); + if (rc == -EBUSY) pcim_pin_device(pdev); + if (rc) return rc; - } if (pci_enable_msi(pdev)) pci_intx(pdev, 1); @@ -1695,11 +1689,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pcim_iomap(pdev, AHCI_PCI_BAR, 0); - if (mmio_base == NULL) - return -ENOMEM; - base = (unsigned long) mmio_base; - hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; @@ -1712,7 +1701,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); probe_ent->private_data = hpriv; /* initialize adapter */ diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index a25cbd653b0c..c79887f31841 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -79,7 +79,7 @@ static int generic_set_mode(struct ata_port *ap, struct ata_device **unused) /* Bits 5 and 6 indicate if DMA is active on master/slave */ if (ap->ioaddr.bmdma_addr) - dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; @@ -138,7 +138,7 @@ static struct ata_port_operations generic_port_ops = { .bmdma_stop = ata_bmdma_stop, .bmdma_status = ata_bmdma_status, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index c6bf1a338d1a..37fe6c2b8ca2 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -299,7 +299,7 @@ static const struct ata_port_operations piix_pata_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -330,7 +330,7 @@ static const struct ata_port_operations ich_pata_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -358,7 +358,7 @@ static const struct ata_port_operations piix_sata_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ed11ee41673c..f210dbd4cbe6 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -601,51 +601,7 @@ void ata_dev_disable(struct ata_device *dev) } /** - * ata_pio_devchk - PATA device presence detection - * @ap: ATA channel to examine - * @device: Device to examine (starting at zero) - * - * This technique was originally described in - * Hale Landis's ATADRVR (www.ata-atapi.com), and - * later found its way into the ATA/ATAPI spec. - * - * Write a pattern to the ATA shadow registers, - * and if a device is present, it will respond by - * correctly storing and echoing back the - * ATA shadow register contents. - * - * LOCKING: - * caller. - */ - -static unsigned int ata_pio_devchk(struct ata_port *ap, - unsigned int device) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - u8 nsect, lbal; - - ap->ops->dev_select(ap, device); - - outb(0x55, ioaddr->nsect_addr); - outb(0xaa, ioaddr->lbal_addr); - - outb(0xaa, ioaddr->nsect_addr); - outb(0x55, ioaddr->lbal_addr); - - outb(0x55, ioaddr->nsect_addr); - outb(0xaa, ioaddr->lbal_addr); - - nsect = inb(ioaddr->nsect_addr); - lbal = inb(ioaddr->lbal_addr); - - if ((nsect == 0x55) && (lbal == 0xaa)) - return 1; /* we found a device */ - - return 0; /* nothing found */ -} - -/** - * ata_mmio_devchk - PATA device presence detection + * ata_devchk - PATA device presence detection * @ap: ATA channel to examine * @device: Device to examine (starting at zero) * @@ -662,25 +618,24 @@ static unsigned int ata_pio_devchk(struct ata_port *ap, * caller. */ -static unsigned int ata_mmio_devchk(struct ata_port *ap, - unsigned int device) +static unsigned int ata_devchk(struct ata_port *ap, unsigned int device) { struct ata_ioports *ioaddr = &ap->ioaddr; u8 nsect, lbal; ap->ops->dev_select(ap, device); - writeb(0x55, (void __iomem *) ioaddr->nsect_addr); - writeb(0xaa, (void __iomem *) ioaddr->lbal_addr); + iowrite8(0x55, ioaddr->nsect_addr); + iowrite8(0xaa, ioaddr->lbal_addr); - writeb(0xaa, (void __iomem *) ioaddr->nsect_addr); - writeb(0x55, (void __iomem *) ioaddr->lbal_addr); + iowrite8(0xaa, ioaddr->nsect_addr); + iowrite8(0x55, ioaddr->lbal_addr); - writeb(0x55, (void __iomem *) ioaddr->nsect_addr); - writeb(0xaa, (void __iomem *) ioaddr->lbal_addr); + iowrite8(0x55, ioaddr->nsect_addr); + iowrite8(0xaa, ioaddr->lbal_addr); - nsect = readb((void __iomem *) ioaddr->nsect_addr); - lbal = readb((void __iomem *) ioaddr->lbal_addr); + nsect = ioread8(ioaddr->nsect_addr); + lbal = ioread8(ioaddr->lbal_addr); if ((nsect == 0x55) && (lbal == 0xaa)) return 1; /* we found a device */ @@ -688,27 +643,6 @@ static unsigned int ata_mmio_devchk(struct ata_port *ap, return 0; /* nothing found */ } -/** - * ata_devchk - PATA device presence detection - * @ap: ATA channel to examine - * @device: Device to examine (starting at zero) - * - * Dispatch ATA device presence detection, depending - * on whether we are using PIO or MMIO to talk to the - * ATA shadow registers. - * - * LOCKING: - * caller. - */ - -static unsigned int ata_devchk(struct ata_port *ap, - unsigned int device) -{ - if (ap->flags & ATA_FLAG_MMIO) - return ata_mmio_devchk(ap, device); - return ata_pio_devchk(ap, device); -} - /** * ata_dev_classify - determine device type based on ATA-spec signature * @tf: ATA taskfile register set for device to be identified @@ -926,11 +860,7 @@ void ata_std_dev_select (struct ata_port *ap, unsigned int device) else tmp = ATA_DEVICE_OBS | ATA_DEV1; - if (ap->flags & ATA_FLAG_MMIO) { - writeb(tmp, (void __iomem *) ap->ioaddr.device_addr); - } else { - outb(tmp, ap->ioaddr.device_addr); - } + iowrite8(tmp, ap->ioaddr.device_addr); ata_pause(ap); /* needed; also flushes, for mmio */ } @@ -2616,13 +2546,8 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask) u8 nsect, lbal; ap->ops->dev_select(ap, 1); - if (ap->flags & ATA_FLAG_MMIO) { - nsect = readb((void __iomem *) ioaddr->nsect_addr); - lbal = readb((void __iomem *) ioaddr->lbal_addr); - } else { - nsect = inb(ioaddr->nsect_addr); - lbal = inb(ioaddr->lbal_addr); - } + nsect = ioread8(ioaddr->nsect_addr); + lbal = ioread8(ioaddr->lbal_addr); if ((nsect == 1) && (lbal == 1)) break; if (time_after(jiffies, timeout)) { @@ -2650,19 +2575,11 @@ static unsigned int ata_bus_softreset(struct ata_port *ap, DPRINTK("ata%u: bus reset via SRST\n", ap->id); /* software reset. causes dev0 to be selected */ - if (ap->flags & ATA_FLAG_MMIO) { - writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); - udelay(20); /* FIXME: flush */ - writeb(ap->ctl | ATA_SRST, (void __iomem *) ioaddr->ctl_addr); - udelay(20); /* FIXME: flush */ - writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); - } else { - outb(ap->ctl, ioaddr->ctl_addr); - udelay(10); - outb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); - udelay(10); - outb(ap->ctl, ioaddr->ctl_addr); - } + iowrite8(ap->ctl, ioaddr->ctl_addr); + udelay(20); /* FIXME: flush */ + iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + udelay(20); /* FIXME: flush */ + iowrite8(ap->ctl, ioaddr->ctl_addr); /* spec mandates ">= 2ms" before checking status. * We wait 150ms, because that was the magic delay used for @@ -2763,10 +2680,7 @@ void ata_bus_reset(struct ata_port *ap) if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) { /* set up device control for ATA_FLAG_SATA_RESET */ - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); - else - outb(ap->ctl, ioaddr->ctl_addr); + iowrite8(ap->ctl, ioaddr->ctl_addr); } DPRINTK("EXIT\n"); @@ -3159,12 +3073,8 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes) } /* set up device control */ - if (ap->ioaddr.ctl_addr) { - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, (void __iomem *) ap->ioaddr.ctl_addr); - else - outb(ap->ctl, ap->ioaddr.ctl_addr); - } + if (ap->ioaddr.ctl_addr) + iowrite8(ap->ctl, ap->ioaddr.ctl_addr); DPRINTK("EXIT\n"); } @@ -3880,53 +3790,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) } /** - * ata_mmio_data_xfer - Transfer data by MMIO - * @adev: device for this I/O - * @buf: data buffer - * @buflen: buffer length - * @write_data: read/write - * - * Transfer data from/to the device data register by MMIO. - * - * LOCKING: - * Inherited from caller. - */ - -void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data) -{ - struct ata_port *ap = adev->ap; - unsigned int i; - unsigned int words = buflen >> 1; - u16 *buf16 = (u16 *) buf; - void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr; - - /* Transfer multiple of 2 bytes */ - if (write_data) { - for (i = 0; i < words; i++) - writew(le16_to_cpu(buf16[i]), mmio); - } else { - for (i = 0; i < words; i++) - buf16[i] = cpu_to_le16(readw(mmio)); - } - - /* Transfer trailing 1 byte, if any. */ - if (unlikely(buflen & 0x01)) { - u16 align_buf[1] = { 0 }; - unsigned char *trailing_buf = buf + buflen - 1; - - if (write_data) { - memcpy(align_buf, trailing_buf, 1); - writew(le16_to_cpu(align_buf[0]), mmio); - } else { - align_buf[0] = cpu_to_le16(readw(mmio)); - memcpy(trailing_buf, align_buf, 1); - } - } -} - -/** - * ata_pio_data_xfer - Transfer data by PIO + * ata_data_xfer - Transfer data by PIO * @adev: device to target * @buf: data buffer * @buflen: buffer length @@ -3937,18 +3801,17 @@ void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, * LOCKING: * Inherited from caller. */ - -void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data) +void ata_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; /* Transfer multiple of 2 bytes */ if (write_data) - outsw(ap->ioaddr.data_addr, buf, words); + iowrite16_rep(ap->ioaddr.data_addr, buf, words); else - insw(ap->ioaddr.data_addr, buf, words); + ioread16_rep(ap->ioaddr.data_addr, buf, words); /* Transfer trailing 1 byte, if any. */ if (unlikely(buflen & 0x01)) { @@ -3957,16 +3820,16 @@ void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, if (write_data) { memcpy(align_buf, trailing_buf, 1); - outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr); + iowrite16(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr); } else { - align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr)); + align_buf[0] = cpu_to_le16(ioread16(ap->ioaddr.data_addr)); memcpy(trailing_buf, align_buf, 1); } } } /** - * ata_pio_data_xfer_noirq - Transfer data by PIO + * ata_data_xfer_noirq - Transfer data by PIO * @adev: device to target * @buf: data buffer * @buflen: buffer length @@ -3978,13 +3841,12 @@ void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, * LOCKING: * Inherited from caller. */ - -void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data) +void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) { unsigned long flags; local_irq_save(flags); - ata_pio_data_xfer(adev, buf, buflen, write_data); + ata_data_xfer(adev, buf, buflen, write_data); local_irq_restore(flags); } @@ -5770,7 +5632,7 @@ int ata_device_add(const struct ata_probe_ent *ent) host->n_ports = ent->n_ports; host->irq = ent->irq; host->irq2 = ent->irq2; - host->mmio_base = ent->mmio_base; + host->iomap = ent->iomap; host->private_data = ent->private_data; /* register each port bound to this device */ @@ -5808,8 +5670,8 @@ int ata_device_add(const struct ata_probe_ent *ent) (ap->pio_mask << ATA_SHIFT_PIO); /* print per-port info to dmesg */ - ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%lX " - "ctl 0x%lX bmdma 0x%lX irq %d\n", + ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p " + "ctl 0x%p bmdma 0x%p irq %d\n", ap->flags & ATA_FLAG_SATA ? 'S' : 'P', ata_mode_string(xfer_mode_mask), ap->ioaddr.cmd_addr, @@ -6328,9 +6190,8 @@ EXPORT_SYMBOL_GPL(ata_altstatus); EXPORT_SYMBOL_GPL(ata_exec_command); EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_interrupt); -EXPORT_SYMBOL_GPL(ata_mmio_data_xfer); -EXPORT_SYMBOL_GPL(ata_pio_data_xfer); -EXPORT_SYMBOL_GPL(ata_pio_data_xfer_noirq); +EXPORT_SYMBOL_GPL(ata_data_xfer); +EXPORT_SYMBOL_GPL(ata_data_xfer_noirq); EXPORT_SYMBOL_GPL(ata_qc_prep); EXPORT_SYMBOL_GPL(ata_noop_qc_prep); EXPORT_SYMBOL_GPL(ata_bmdma_setup); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 21efe92a7135..c561b3be4a97 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -56,10 +56,7 @@ u8 ata_irq_on(struct ata_port *ap) ap->ctl &= ~ATA_NIEN; ap->last_ctl = ap->ctl; - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); - else - outb(ap->ctl, ioaddr->ctl_addr); + iowrite8(ap->ctl, ioaddr->ctl_addr); tmp = ata_wait_idle(ap); ap->ops->irq_clear(ap); @@ -68,7 +65,7 @@ u8 ata_irq_on(struct ata_port *ap) } /** - * ata_tf_load_pio - send taskfile registers to host controller + * ata_tf_load - send taskfile registers to host controller * @ap: Port to which output is sent * @tf: ATA taskfile register set * @@ -78,81 +75,23 @@ u8 ata_irq_on(struct ata_port *ap) * Inherited from caller. */ -static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; - - if (tf->ctl != ap->last_ctl) { - outb(tf->ctl, ioaddr->ctl_addr); - ap->last_ctl = tf->ctl; - ata_wait_idle(ap); - } - - if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - outb(tf->hob_feature, ioaddr->feature_addr); - outb(tf->hob_nsect, ioaddr->nsect_addr); - outb(tf->hob_lbal, ioaddr->lbal_addr); - outb(tf->hob_lbam, ioaddr->lbam_addr); - outb(tf->hob_lbah, ioaddr->lbah_addr); - VPRINTK("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); - } - - if (is_addr) { - outb(tf->feature, ioaddr->feature_addr); - outb(tf->nsect, ioaddr->nsect_addr); - outb(tf->lbal, ioaddr->lbal_addr); - outb(tf->lbam, ioaddr->lbam_addr); - outb(tf->lbah, ioaddr->lbah_addr); - VPRINTK("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) { - outb(tf->device, ioaddr->device_addr); - VPRINTK("device 0x%X\n", tf->device); - } - - ata_wait_idle(ap); -} - -/** - * ata_tf_load_mmio - send taskfile registers to host controller - * @ap: Port to which output is sent - * @tf: ATA taskfile register set - * - * Outputs ATA taskfile to standard ATA host controller using MMIO. - * - * LOCKING: - * Inherited from caller. - */ - -static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) +void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; if (tf->ctl != ap->last_ctl) { - writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr); + iowrite8(tf->ctl, ioaddr->ctl_addr); ap->last_ctl = tf->ctl; ata_wait_idle(ap); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr); - writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr); - writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr); - writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr); - writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr); + iowrite8(tf->hob_feature, ioaddr->feature_addr); + iowrite8(tf->hob_nsect, ioaddr->nsect_addr); + iowrite8(tf->hob_lbal, ioaddr->lbal_addr); + iowrite8(tf->hob_lbam, ioaddr->lbam_addr); + iowrite8(tf->hob_lbah, ioaddr->lbah_addr); VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", tf->hob_feature, tf->hob_nsect, @@ -162,11 +101,11 @@ static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) } if (is_addr) { - writeb(tf->feature, (void __iomem *) ioaddr->feature_addr); - writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr); - writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr); - writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr); - writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr); + iowrite8(tf->feature, ioaddr->feature_addr); + iowrite8(tf->nsect, ioaddr->nsect_addr); + iowrite8(tf->lbal, ioaddr->lbal_addr); + iowrite8(tf->lbam, ioaddr->lbam_addr); + iowrite8(tf->lbah, ioaddr->lbah_addr); VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", tf->feature, tf->nsect, @@ -176,108 +115,34 @@ static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) } if (tf->flags & ATA_TFLAG_DEVICE) { - writeb(tf->device, (void __iomem *) ioaddr->device_addr); + iowrite8(tf->device, ioaddr->device_addr); VPRINTK("device 0x%X\n", tf->device); } ata_wait_idle(ap); } - -/** - * ata_tf_load - send taskfile registers to host controller - * @ap: Port to which output is sent - * @tf: ATA taskfile register set - * - * Outputs ATA taskfile to standard ATA host controller using MMIO - * or PIO as indicated by the ATA_FLAG_MMIO flag. - * Writes the control, feature, nsect, lbal, lbam, and lbah registers. - * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect, - * hob_lbal, hob_lbam, and hob_lbah. - * - * This function waits for idle (!BUSY and !DRQ) after writing - * registers. If the control register has a new value, this - * function also waits for idle after writing control and before - * writing the remaining registers. - * - * May be used as the tf_load() entry in ata_port_operations. - * - * LOCKING: - * Inherited from caller. - */ -void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) -{ - if (ap->flags & ATA_FLAG_MMIO) - ata_tf_load_mmio(ap, tf); - else - ata_tf_load_pio(ap, tf); -} - -/** - * ata_exec_command_pio - issue ATA command to host controller - * @ap: port to which command is being issued - * @tf: ATA taskfile register set - * - * Issues PIO write to ATA command register, with proper - * synchronization with interrupt handler / other threads. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ - -static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf) -{ - DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); - - outb(tf->command, ap->ioaddr.command_addr); - ata_pause(ap); -} - - /** - * ata_exec_command_mmio - issue ATA command to host controller + * ata_exec_command - issue ATA command to host controller * @ap: port to which command is being issued * @tf: ATA taskfile register set * - * Issues MMIO write to ATA command register, with proper - * synchronization with interrupt handler / other threads. - * - * FIXME: missing write posting for 400nS delay enforcement + * Issues ATA command, with proper synchronization with interrupt + * handler / other threads. * * LOCKING: * spin_lock_irqsave(host lock) */ - -static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) +void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); - writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr); + iowrite8(tf->command, ap->ioaddr.command_addr); ata_pause(ap); } - -/** - * ata_exec_command - issue ATA command to host controller - * @ap: port to which command is being issued - * @tf: ATA taskfile register set - * - * Issues PIO/MMIO write to ATA command register, with proper - * synchronization with interrupt handler / other threads. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ -void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) -{ - if (ap->flags & ATA_FLAG_MMIO) - ata_exec_command_mmio(ap, tf); - else - ata_exec_command_pio(ap, tf); -} - /** - * ata_tf_read_pio - input device's ATA taskfile shadow registers + * ata_tf_read - input device's ATA taskfile shadow registers * @ap: Port from which input is read * @tf: ATA taskfile register set for storing input * @@ -287,121 +152,28 @@ void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) * LOCKING: * Inherited from caller. */ - -static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - - tf->command = ata_check_status(ap); - tf->feature = inb(ioaddr->error_addr); - tf->nsect = inb(ioaddr->nsect_addr); - tf->lbal = inb(ioaddr->lbal_addr); - tf->lbam = inb(ioaddr->lbam_addr); - tf->lbah = inb(ioaddr->lbah_addr); - tf->device = inb(ioaddr->device_addr); - - if (tf->flags & ATA_TFLAG_LBA48) { - outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); - tf->hob_feature = inb(ioaddr->error_addr); - tf->hob_nsect = inb(ioaddr->nsect_addr); - tf->hob_lbal = inb(ioaddr->lbal_addr); - tf->hob_lbam = inb(ioaddr->lbam_addr); - tf->hob_lbah = inb(ioaddr->lbah_addr); - } -} - -/** - * ata_tf_read_mmio - 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 via MMIO. - * - * LOCKING: - * Inherited from caller. - */ - -static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf) +void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; tf->command = ata_check_status(ap); - tf->feature = readb((void __iomem *)ioaddr->error_addr); - tf->nsect = readb((void __iomem *)ioaddr->nsect_addr); - tf->lbal = readb((void __iomem *)ioaddr->lbal_addr); - tf->lbam = readb((void __iomem *)ioaddr->lbam_addr); - tf->lbah = readb((void __iomem *)ioaddr->lbah_addr); - tf->device = readb((void __iomem *)ioaddr->device_addr); + 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 = ioread8(ioaddr->device_addr); if (tf->flags & ATA_TFLAG_LBA48) { - writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr); - tf->hob_feature = readb((void __iomem *)ioaddr->error_addr); - tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr); - tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr); - tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr); - tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr); + 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); } } - -/** - * ata_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. - * - * Reads nsect, lbal, lbam, lbah, and device. If ATA_TFLAG_LBA48 - * is set, also reads the hob registers. - * - * May be used as the tf_read() entry in ata_port_operations. - * - * LOCKING: - * Inherited from caller. - */ -void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) -{ - if (ap->flags & ATA_FLAG_MMIO) - ata_tf_read_mmio(ap, tf); - else - ata_tf_read_pio(ap, tf); -} - -/** - * ata_check_status_pio - Read device status reg & clear interrupt - * @ap: port where the device is - * - * Reads ATA taskfile status register for currently-selected device - * and return its value. This also clears pending interrupts - * from this device - * - * LOCKING: - * Inherited from caller. - */ -static u8 ata_check_status_pio(struct ata_port *ap) -{ - return inb(ap->ioaddr.status_addr); -} - -/** - * ata_check_status_mmio - Read device status reg & clear interrupt - * @ap: port where the device is - * - * Reads ATA taskfile status register for currently-selected device - * via MMIO and return its value. This also clears pending interrupts - * from this device - * - * LOCKING: - * Inherited from caller. - */ -static u8 ata_check_status_mmio(struct ata_port *ap) -{ - return readb((void __iomem *) ap->ioaddr.status_addr); -} - - /** * ata_check_status - Read device status reg & clear interrupt * @ap: port where the device is @@ -410,19 +182,14 @@ static u8 ata_check_status_mmio(struct ata_port *ap) * and return its value. This also clears pending interrupts * from this device * - * May be used as the check_status() entry in ata_port_operations. - * * LOCKING: * Inherited from caller. */ u8 ata_check_status(struct ata_port *ap) { - if (ap->flags & ATA_FLAG_MMIO) - return ata_check_status_mmio(ap); - return ata_check_status_pio(ap); + return ioread8(ap->ioaddr.status_addr); } - /** * ata_altstatus - Read device alternate status reg * @ap: port where the device is @@ -441,58 +208,52 @@ u8 ata_altstatus(struct ata_port *ap) if (ap->ops->check_altstatus) return ap->ops->check_altstatus(ap); - if (ap->flags & ATA_FLAG_MMIO) - return readb((void __iomem *)ap->ioaddr.altstatus_addr); - return inb(ap->ioaddr.altstatus_addr); + return ioread8(ap->ioaddr.altstatus_addr); } /** - * ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction + * ata_bmdma_setup - Set up PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. * * LOCKING: * spin_lock_irqsave(host lock) */ - -static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc) +void ata_bmdma_setup(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 dmactl; - void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; /* load PRD table addr. */ mb(); /* make sure PRD table writes are visible to controller */ - writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS); + iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); /* specify data direction, triple-check start bit is clear */ - dmactl = readb(mmio + ATA_DMA_CMD); + dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); if (!rw) dmactl |= ATA_DMA_WR; - writeb(dmactl, mmio + ATA_DMA_CMD); + iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); /* issue r/w command */ ap->ops->exec_command(ap, &qc->tf); } /** - * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction + * ata_bmdma_start - Start a PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. * * LOCKING: * spin_lock_irqsave(host lock) */ - -static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc) +void ata_bmdma_start (struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; u8 dmactl; /* start host DMA transaction */ - dmactl = readb(mmio + ATA_DMA_CMD); - writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD); + dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); /* Strictly, one may wish to issue a readb() here, to * flush the mmio write. However, control also passes @@ -507,96 +268,6 @@ static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc) */ } -/** - * ata_bmdma_setup_pio - Set up PCI IDE BMDMA transaction (PIO) - * @qc: Info associated with this ATA transaction. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ - -static void ata_bmdma_setup_pio (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. */ - outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); - - /* specify data direction, triple-check start bit is clear */ - dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); - if (!rw) - dmactl |= ATA_DMA_WR; - outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - - /* issue r/w command */ - ap->ops->exec_command(ap, &qc->tf); -} - -/** - * ata_bmdma_start_pio - Start a PCI IDE BMDMA transaction (PIO) - * @qc: Info associated with this ATA transaction. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ - -static void ata_bmdma_start_pio (struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - u8 dmactl; - - /* start host DMA transaction */ - dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - outb(dmactl | ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); -} - - -/** - * ata_bmdma_start - Start a PCI IDE BMDMA transaction - * @qc: Info associated with this ATA transaction. - * - * Writes the ATA_DMA_START flag to the DMA command register. - * - * May be used as the bmdma_start() entry in ata_port_operations. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ -void ata_bmdma_start(struct ata_queued_cmd *qc) -{ - if (qc->ap->flags & ATA_FLAG_MMIO) - ata_bmdma_start_mmio(qc); - else - ata_bmdma_start_pio(qc); -} - - -/** - * ata_bmdma_setup - Set up PCI IDE BMDMA transaction - * @qc: Info associated with this ATA transaction. - * - * Writes address of PRD table to device's PRD Table Address - * register, sets the DMA control register, and calls - * ops->exec_command() to start the transfer. - * - * May be used as the bmdma_setup() entry in ata_port_operations. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ -void ata_bmdma_setup(struct ata_queued_cmd *qc) -{ - if (qc->ap->flags & ATA_FLAG_MMIO) - ata_bmdma_setup_mmio(qc); - else - ata_bmdma_setup_pio(qc); -} - - /** * ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt. * @ap: Port associated with this ATA transaction. @@ -608,23 +279,16 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc) * LOCKING: * spin_lock_irqsave(host lock) */ - void ata_bmdma_irq_clear(struct ata_port *ap) { - if (!ap->ioaddr.bmdma_addr) + void __iomem *mmio = ap->ioaddr.bmdma_addr; + + if (!mmio) return; - if (ap->flags & ATA_FLAG_MMIO) { - void __iomem *mmio = - ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS; - writeb(readb(mmio), mmio); - } else { - unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; - outb(inb(addr), addr); - } + iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS); } - /** * ata_bmdma_status - Read PCI IDE BMDMA status * @ap: Port associated with this ATA transaction. @@ -636,19 +300,11 @@ void ata_bmdma_irq_clear(struct ata_port *ap) * LOCKING: * spin_lock_irqsave(host lock) */ - u8 ata_bmdma_status(struct ata_port *ap) { - u8 host_stat; - if (ap->flags & ATA_FLAG_MMIO) { - void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; - host_stat = readb(mmio + ATA_DMA_STATUS); - } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - return host_stat; + return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); } - /** * ata_bmdma_stop - Stop PCI IDE BMDMA transfer * @qc: Command we are ending DMA for @@ -660,21 +316,14 @@ u8 ata_bmdma_status(struct ata_port *ap) * LOCKING: * spin_lock_irqsave(host lock) */ - void ata_bmdma_stop(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - if (ap->flags & ATA_FLAG_MMIO) { - void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; + void __iomem *mmio = ap->ioaddr.bmdma_addr; - /* clear start/stop bit */ - writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START, - mmio + ATA_DMA_CMD); - } else { - /* clear start/stop bit */ - outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - } + /* clear start/stop bit */ + iowrite8(ioread8(mmio + ATA_DMA_CMD) & ~ATA_DMA_START, + mmio + ATA_DMA_CMD); /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ ata_altstatus(ap); /* dummy read */ @@ -696,10 +345,7 @@ void ata_bmdma_freeze(struct ata_port *ap) ap->ctl |= ATA_NIEN; ap->last_ctl = ap->ctl; - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr); - else - outb(ap->ctl, ioaddr->ctl_addr); + iowrite8(ap->ctl, ioaddr->ctl_addr); /* Under certain circumstances, some controllers raise IRQ on * ATA_NIEN manipulation. Also, many controllers fail to mask @@ -868,11 +514,24 @@ static int ata_resources_present(struct pci_dev *pdev, int port) struct ata_probe_ent * ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports) { - struct ata_probe_ent *probe_ent = - ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); - int p = 0; - unsigned long bmdma; + struct ata_probe_ent *probe_ent; + int i, p = 0; + void __iomem * const *iomap; + + /* iomap BARs */ + for (i = 0; i < 4; i++) { + if (pcim_iomap(pdev, i, 0) == NULL) { + dev_printk(KERN_ERR, &pdev->dev, + "failed to iomap PCI BAR %d\n", i); + return NULL; + } + } + + pcim_iomap(pdev, 4, 0); /* may fail */ + iomap = pcim_iomap_table(pdev); + /* alloc and init probe_ent */ + probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); if (!probe_ent) return NULL; @@ -887,33 +546,30 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports &= ~ATA_PORT_SECONDARY; if (ports & ATA_PORT_PRIMARY) { - probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0); + probe_ent->port[p].cmd_addr = iomap[0]; probe_ent->port[p].altstatus_addr = - probe_ent->port[p].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - bmdma = pci_resource_start(pdev, 4); - if (bmdma) { + probe_ent->port[p].ctl_addr = (void __iomem *) + ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS); + if (iomap[4]) { if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) && - (inb(bmdma + 2) & 0x80)) + (ioread8(iomap[4] + 2) & 0x80)) probe_ent->_host_flags |= ATA_HOST_SIMPLEX; - probe_ent->port[p].bmdma_addr = bmdma; + probe_ent->port[p].bmdma_addr = iomap[4]; } ata_std_ports(&probe_ent->port[p]); p++; } if (ports & ATA_PORT_SECONDARY) { - probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2); + probe_ent->port[p].cmd_addr = iomap[2]; probe_ent->port[p].altstatus_addr = - probe_ent->port[p].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - bmdma = pci_resource_start(pdev, 4); - if (bmdma) { - bmdma += 8; + probe_ent->port[p].ctl_addr = (void __iomem *) + ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS); + if (iomap[4]) { if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) && - (inb(bmdma + 2) & 0x80)) + (ioread8(iomap[4] + 10) & 0x80)) probe_ent->_host_flags |= ATA_HOST_SIMPLEX; - probe_ent->port[p].bmdma_addr = bmdma; + probe_ent->port[p].bmdma_addr = iomap[4] + 8; } ata_std_ports(&probe_ent->port[p]); probe_ent->pinfo2 = port[1]; @@ -924,13 +580,29 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int return probe_ent; } - static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, struct ata_port_info **port, int port_mask) { struct ata_probe_ent *probe_ent; - unsigned long bmdma = pci_resource_start(pdev, 4); + void __iomem *iomap[5] = { }, *bmdma; + + if (port_mask & ATA_PORT_PRIMARY) { + iomap[0] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CMD, 8); + iomap[1] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CTL, 1); + if (!iomap[0] || !iomap[1]) + return NULL; + } + + if (port_mask & ATA_PORT_SECONDARY) { + iomap[2] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CMD, 8); + iomap[3] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CTL, 1); + if (!iomap[2] || !iomap[3]) + return NULL; + } + + bmdma = pcim_iomap(pdev, 4, 16); /* may fail */ + /* alloc and init probe_ent */ probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); if (!probe_ent) return NULL; @@ -940,13 +612,13 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, if (port_mask & ATA_PORT_PRIMARY) { probe_ent->irq = ATA_PRIMARY_IRQ(pdev); - probe_ent->port[0].cmd_addr = ATA_PRIMARY_CMD; + probe_ent->port[0].cmd_addr = iomap[0]; probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = ATA_PRIMARY_CTL; + probe_ent->port[0].ctl_addr = iomap[1]; if (bmdma) { probe_ent->port[0].bmdma_addr = bmdma; if ((!(port[0]->flags & ATA_FLAG_IGN_SIMPLEX)) && - (inb(bmdma + 2) & 0x80)) + (ioread8(bmdma + 2) & 0x80)) probe_ent->_host_flags |= ATA_HOST_SIMPLEX; } ata_std_ports(&probe_ent->port[0]); @@ -958,13 +630,13 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, probe_ent->irq2 = ATA_SECONDARY_IRQ(pdev); else probe_ent->irq = ATA_SECONDARY_IRQ(pdev); - probe_ent->port[1].cmd_addr = ATA_SECONDARY_CMD; + probe_ent->port[1].cmd_addr = iomap[2]; probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = ATA_SECONDARY_CTL; + probe_ent->port[1].ctl_addr = iomap[3]; if (bmdma) { probe_ent->port[1].bmdma_addr = bmdma + 8; if ((!(port[1]->flags & ATA_FLAG_IGN_SIMPLEX)) && - (inb(bmdma + 10) & 0x80)) + (ioread8(bmdma + 10) & 0x80)) probe_ent->_host_flags |= ATA_HOST_SIMPLEX; } ata_std_ports(&probe_ent->port[1]); diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index f4fdb10211e3..dffa1f539fc9 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -370,7 +370,7 @@ static struct ata_port_operations ali_early_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -409,7 +409,7 @@ static struct ata_port_operations ali_20_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -445,7 +445,7 @@ static struct ata_port_operations ali_c2_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -480,7 +480,7 @@ static struct ata_port_operations ali_c5_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 7ee0c83c657a..ed0e4f6fc715 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -362,7 +362,7 @@ static struct ata_port_operations amd33_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -394,7 +394,7 @@ static struct ata_port_operations amd66_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -426,7 +426,7 @@ static struct ata_port_operations amd100_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -458,7 +458,7 @@ static struct ata_port_operations amd133_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -490,7 +490,7 @@ static struct ata_port_operations nv100_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -522,7 +522,7 @@ static struct ata_port_operations nv133_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c index 5baea1222227..ace5a98dd59d 100644 --- a/drivers/ata/pata_artop.c +++ b/drivers/ata/pata_artop.c @@ -341,7 +341,7 @@ static const struct ata_port_operations artop6210_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -371,7 +371,7 @@ static const struct ata_port_operations artop6260_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 2bfb99493a72..f89ef7b15999 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -252,7 +252,7 @@ static struct ata_port_operations atiixp_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index d97aa9bb0500..3a75978c1aee 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -313,7 +313,7 @@ static struct ata_port_operations cmd64x_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -345,7 +345,7 @@ static struct ata_port_operations cmd646r1_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -377,7 +377,7 @@ static struct ata_port_operations cmd648_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 63bdcbe45583..801a00efa3ee 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -99,9 +99,9 @@ static void cs5520_set_timings(struct ata_port *ap, struct ata_device *adev, int static void cs5520_enable_dma(struct ata_port *ap, struct ata_device *adev) { /* Set the DMA enable/disable flag */ - u8 reg = inb(ap->ioaddr.bmdma_addr + 0x02); + u8 reg = ioread8(ap->ioaddr.bmdma_addr + 0x02); reg |= 1<<(adev->devno + 5); - outb(reg, ap->ioaddr.bmdma_addr + 0x02); + iowrite8(reg, ap->ioaddr.bmdma_addr + 0x02); } /** @@ -193,7 +193,7 @@ static struct ata_port_operations cs5520_port_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -204,6 +204,7 @@ static struct ata_port_operations cs5520_port_ops = { static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id) { u8 pcicfg; + void *iomap[5]; static struct ata_probe_ent probe[2]; int ports = 0; @@ -234,6 +235,16 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic return -ENODEV; } + /* Map IO ports */ + iomap[0] = devm_ioport_map(&dev->dev, 0x1F0, 8); + iomap[1] = devm_ioport_map(&dev->dev, 0x3F6, 1); + iomap[2] = devm_ioport_map(&dev->dev, 0x170, 8); + iomap[3] = devm_ioport_map(&dev->dev, 0x376, 1); + iomap[4] = pcim_iomap(dev, 2, 0); + + if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4]) + return -ENOMEM; + /* We have to do our own plumbing as the PCI setup for this chipset is non-standard so we can't punt to the libata code */ @@ -247,10 +258,10 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic probe[0].irq_flags = 0; probe[0].port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST; probe[0].n_ports = 1; - probe[0].port[0].cmd_addr = 0x1F0; - probe[0].port[0].ctl_addr = 0x3F6; - probe[0].port[0].altstatus_addr = 0x3F6; - probe[0].port[0].bmdma_addr = pci_resource_start(dev, 2); + probe[0].port[0].cmd_addr = iomap[0]; + probe[0].port[0].ctl_addr = iomap[1]; + probe[0].port[0].altstatus_addr = iomap[1]; + probe[0].port[0].bmdma_addr = iomap[4]; /* The secondary lurks at different addresses but is otherwise the same beastie */ @@ -258,10 +269,10 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic probe[1] = probe[0]; INIT_LIST_HEAD(&probe[1].node); probe[1].irq = 15; - probe[1].port[0].cmd_addr = 0x170; - probe[1].port[0].ctl_addr = 0x376; - probe[1].port[0].altstatus_addr = 0x376; - probe[1].port[0].bmdma_addr = pci_resource_start(dev, 2) + 8; + probe[1].port[0].cmd_addr = iomap[2]; + probe[1].port[0].ctl_addr = iomap[3]; + probe[1].port[0].altstatus_addr = iomap[3]; + probe[1].port[0].bmdma_addr = iomap[4] + 8; /* Let libata fill in the port details */ ata_std_ports(&probe[0].port[0]); diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index 29d459be19be..b9fd5388b476 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -37,6 +37,13 @@ #define DRV_NAME "pata_cs5530" #define DRV_VERSION "0.7.1" +static void __iomem *cs5530_port_base(struct ata_port *ap) +{ + unsigned long bmdma = (unsigned long)ap->ioaddr.bmdma_addr; + + return (void __iomem *)((bmdma & ~0x0F) + 0x20 + 0x10 * ap->port_no); +} + /** * cs5530_set_piomode - PIO setup * @ap: ATA interface @@ -52,19 +59,19 @@ static void cs5530_set_piomode(struct ata_port *ap, struct ata_device *adev) {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010} }; - unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no; + void __iomem *base = cs5530_port_base(ap); u32 tuning; int format; /* Find out which table to use */ - tuning = inl(base + 0x04); + tuning = ioread32(base + 0x04); format = (tuning & 0x80000000UL) ? 1 : 0; /* Now load the right timing register */ if (adev->devno) base += 0x08; - outl(cs5530_pio_timings[format][adev->pio_mode - XFER_PIO_0], base); + iowrite32(cs5530_pio_timings[format][adev->pio_mode - XFER_PIO_0], base); } /** @@ -79,12 +86,12 @@ static void cs5530_set_piomode(struct ata_port *ap, struct ata_device *adev) static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev) { - unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no; + void __iomem *base = cs5530_port_base(ap); u32 tuning, timing = 0; u8 reg; /* Find out which table to use */ - tuning = inl(base + 0x04); + tuning = ioread32(base + 0x04); switch(adev->dma_mode) { case XFER_UDMA_0: @@ -105,20 +112,20 @@ static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev) /* Merge in the PIO format bit */ timing |= (tuning & 0x80000000UL); if (adev->devno == 0) /* Master */ - outl(timing, base + 0x04); + iowrite32(timing, base + 0x04); else { if (timing & 0x00100000) tuning |= 0x00100000; /* UDMA for both */ else tuning &= ~0x00100000; /* MWDMA for both */ - outl(tuning, base + 0x04); - outl(timing, base + 0x0C); + iowrite32(tuning, base + 0x04); + iowrite32(timing, base + 0x0C); } /* Set the DMA capable bit in the BMDMA area */ - reg = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + reg = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); reg |= (1 << (5 + adev->devno)); - outb(reg, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + iowrite8(reg, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); /* Remember the last DMA setup we did */ @@ -210,7 +217,7 @@ static struct ata_port_operations cs5530_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = cs5530_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index dd3958d2cff9..500f863cb987 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -214,7 +214,7 @@ static struct ata_port_operations cs5535_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index 8479186a2373..4ca103d668ed 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -165,7 +165,7 @@ static struct ata_port_operations cy82c693_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index 66814ee64d05..a112dac98dd9 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -261,7 +261,7 @@ static const struct ata_port_operations efar_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 8b826102dbd9..819d7a392781 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -361,7 +361,7 @@ static struct ata_port_operations hpt366_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 09e8be56ba36..c6d8774df0de 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -634,24 +634,24 @@ static void hpt370_bmdma_stop(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u8 dma_stat = inb(ap->ioaddr.bmdma_addr + 2); + u8 dma_stat = ioread8(ap->ioaddr.bmdma_addr + 2); u8 dma_cmd; - unsigned long bmdma = ap->ioaddr.bmdma_addr; + void __iomem *bmdma = ap->ioaddr.bmdma_addr; if (dma_stat & 0x01) { udelay(20); - dma_stat = inb(bmdma + 2); + dma_stat = ioread8(bmdma + 2); } if (dma_stat & 0x01) { /* Clear the engine */ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(10); /* Stop DMA */ - dma_cmd = inb(bmdma ); - outb(dma_cmd & 0xFE, bmdma); + dma_cmd = ioread8(bmdma ); + iowrite8(dma_cmd & 0xFE, bmdma); /* Clear Error */ - dma_stat = inb(bmdma + 2); - outb(dma_stat | 0x06 , bmdma + 2); + dma_stat = ioread8(bmdma + 2); + iowrite8(dma_stat | 0x06 , bmdma + 2); /* Clear the engine */ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37); udelay(10); @@ -796,7 +796,7 @@ static struct ata_port_operations hpt370_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -833,7 +833,7 @@ static struct ata_port_operations hpt370a_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -871,7 +871,7 @@ static struct ata_port_operations hpt372_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -909,7 +909,7 @@ static struct ata_port_operations hpt374_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c index 9f8ec576317c..b56dc4a7185b 100644 --- a/drivers/ata/pata_hpt3x2n.c +++ b/drivers/ata/pata_hpt3x2n.c @@ -263,26 +263,26 @@ static void hpt3x2n_bmdma_stop(struct ata_queued_cmd *qc) static void hpt3x2n_set_clock(struct ata_port *ap, int source) { - unsigned long bmdma = ap->ioaddr.bmdma_addr; + void __iomem *bmdma = ap->ioaddr.bmdma_addr; /* Tristate the bus */ - outb(0x80, bmdma+0x73); - outb(0x80, bmdma+0x77); + iowrite8(0x80, bmdma+0x73); + iowrite8(0x80, bmdma+0x77); /* Switch clock and reset channels */ - outb(source, bmdma+0x7B); - outb(0xC0, bmdma+0x79); + iowrite8(source, bmdma+0x7B); + iowrite8(0xC0, bmdma+0x79); /* Reset state machines */ - outb(0x37, bmdma+0x70); - outb(0x37, bmdma+0x74); + iowrite8(0x37, bmdma+0x70); + iowrite8(0x37, bmdma+0x74); /* Complete reset */ - outb(0x00, bmdma+0x79); + iowrite8(0x00, bmdma+0x79); /* Reconnect channels to bus */ - outb(0x00, bmdma+0x73); - outb(0x00, bmdma+0x77); + iowrite8(0x00, bmdma+0x73); + iowrite8(0x00, bmdma+0x77); } /* Check if our partner interface is busy */ @@ -373,7 +373,7 @@ static struct ata_port_operations hpt3x2n_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = hpt3x2n_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index faa2db44ba7f..46fc417856cc 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -148,7 +148,7 @@ static struct ata_port_operations hpt3x3_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 38a42eae598e..4d9ab268cf28 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -53,7 +53,7 @@ static struct ata_port_operations isapnp_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -73,6 +73,7 @@ static struct ata_port_operations isapnp_port_ops = { static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id) { struct ata_probe_ent ae; + void __iomem *cmd_addr, *ctl_addr; if (pnp_port_valid(idev, 0) == 0) return -ENODEV; @@ -81,6 +82,10 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev if (pnp_irq_valid(idev, 0) == 0) return -ENODEV; + cmd_addr = devm_ioport_map(&idev->dev, pnp_port_start(idev, 0), 8); + if (!cmd_addr) + return -ENOMEM; + memset(&ae, 0, sizeof(struct ata_probe_ent)); INIT_LIST_HEAD(&ae.node); ae.dev = &idev->dev; @@ -91,11 +96,13 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev ae.irq = pnp_irq(idev, 0); ae.irq_flags = 0; ae.port_flags = ATA_FLAG_SLAVE_POSS; - ae.port[0].cmd_addr = pnp_port_start(idev, 0); + ae.port[0].cmd_addr = cmd_addr; if (pnp_port_valid(idev, 1) == 0) { - ae.port[0].altstatus_addr = pnp_port_start(idev, 1); - ae.port[0].ctl_addr = pnp_port_start(idev, 1); + ctl_addr = devm_ioport_map(&idev->dev, + pnp_port_start(idev, 1), 1); + ae.port[0].altstatus_addr = ctl_addr; + ae.port[0].ctl_addr = ctl_addr; ae.port_flags |= ATA_FLAG_SRST; } ata_std_ports(&ae.port[0]); diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 383a611b662e..ec128316903d 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -273,7 +273,7 @@ static const struct ata_port_operations it8213_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index f23365b92c0f..e8a6e7d73b72 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -492,7 +492,7 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused /* Bits 5 and 6 indicate if DMA is active on master/slave */ /* It is possible that BMDMA isn't allocated */ if (ap->ioaddr.bmdma_addr) - dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; @@ -674,7 +674,7 @@ static struct ata_port_operations it821x_smart_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = it821x_smart_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -708,7 +708,7 @@ static struct ata_port_operations it821x_passthru_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = it821x_passthru_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_clear = ata_bmdma_irq_clear, .irq_handler = ata_interrupt, diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 230067d281e3..d9ee1837b7ff 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -140,9 +140,9 @@ static struct ata_port_operations ixp4xx_port_ops = { static void ixp4xx_setup_port(struct ata_ioports *ioaddr, struct ixp4xx_pata_data *data) { - ioaddr->cmd_addr = (unsigned long) data->cs0; - ioaddr->altstatus_addr = (unsigned long) data->cs1 + 0x06; - ioaddr->ctl_addr = (unsigned long) data->cs1 + 0x06; + ioaddr->cmd_addr = data->cs0; + ioaddr->altstatus_addr = data->cs1 + 0x06; + ioaddr->ctl_addr = data->cs1 + 0x06; ata_std_ports(ioaddr); @@ -152,19 +152,19 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr, * ixp4xx in little endian mode. */ - ioaddr->data_addr ^= 0x02; - ioaddr->cmd_addr ^= 0x03; - ioaddr->altstatus_addr ^= 0x03; - ioaddr->ctl_addr ^= 0x03; - ioaddr->error_addr ^= 0x03; - ioaddr->feature_addr ^= 0x03; - ioaddr->nsect_addr ^= 0x03; - ioaddr->lbal_addr ^= 0x03; - ioaddr->lbam_addr ^= 0x03; - ioaddr->lbah_addr ^= 0x03; - ioaddr->device_addr ^= 0x03; - ioaddr->status_addr ^= 0x03; - ioaddr->command_addr ^= 0x03; + *(unsigned long *)&ioaddr->data_addr ^= 0x02; + *(unsigned long *)&ioaddr->cmd_addr ^= 0x03; + *(unsigned long *)&ioaddr->altstatus_addr ^= 0x03; + *(unsigned long *)&ioaddr->ctl_addr ^= 0x03; + *(unsigned long *)&ioaddr->error_addr ^= 0x03; + *(unsigned long *)&ioaddr->feature_addr ^= 0x03; + *(unsigned long *)&ioaddr->nsect_addr ^= 0x03; + *(unsigned long *)&ioaddr->lbal_addr ^= 0x03; + *(unsigned long *)&ioaddr->lbam_addr ^= 0x03; + *(unsigned long *)&ioaddr->lbah_addr ^= 0x03; + *(unsigned long *)&ioaddr->device_addr ^= 0x03; + *(unsigned long *)&ioaddr->status_addr ^= 0x03; + *(unsigned long *)&ioaddr->command_addr ^= 0x03; #endif } diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 128a30958210..26365c107818 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -161,7 +161,7 @@ static const struct ata_port_operations jmicron_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, /* IRQ-related hooks */ .irq_handler = ata_interrupt, diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 9532b9bb6d2f..78b5f7136e1e 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -164,7 +164,7 @@ static struct ata_port_operations simple_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer_noirq, + .data_xfer = ata_data_xfer_noirq, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -187,7 +187,7 @@ static struct ata_port_operations legacy_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer_noirq, + .data_xfer = ata_data_xfer_noirq, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -253,31 +253,33 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig local_irq_save(flags); /* Perform the 32bit I/O synchronization sequence */ - inb(ap->ioaddr.nsect_addr); - inb(ap->ioaddr.nsect_addr); - inb(ap->ioaddr.nsect_addr); + ioread8(ap->ioaddr.nsect_addr); + ioread8(ap->ioaddr.nsect_addr); + ioread8(ap->ioaddr.nsect_addr); /* Now the data */ if (write_data) - outsl(ap->ioaddr.data_addr, buf, buflen >> 2); + iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); else - insl(ap->ioaddr.data_addr, buf, buflen >> 2); + ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); if (unlikely(slop)) { u32 pad; if (write_data) { memcpy(&pad, buf + buflen - slop, slop); - outl(le32_to_cpu(pad), ap->ioaddr.data_addr); + pad = le32_to_cpu(pad); + iowrite32(pad, ap->ioaddr.data_addr); } else { - pad = cpu_to_le16(inl(ap->ioaddr.data_addr)); + pad = ioread32(ap->ioaddr.data_addr); + pad = cpu_to_le16(pad); memcpy(buf + buflen - slop, &pad, slop); } } local_irq_restore(flags); } else - ata_pio_data_xfer_noirq(adev, buf, buflen, write_data); + ata_data_xfer_noirq(adev, buf, buflen, write_data); } static struct ata_port_operations pdc20230_port_ops = { @@ -326,8 +328,8 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev) inb(0x3E6); inb(0x3E6); - outb(recover << 4 | active, ap->ioaddr.device_addr); - inb(ap->ioaddr.status_addr); + iowrite8(recover << 4 | active, ap->ioaddr.device_addr); + ioread8(ap->ioaddr.status_addr); } static struct ata_port_operations ht6560a_port_ops = { @@ -345,7 +347,7 @@ static struct ata_port_operations ht6560a_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, /* Check vlb/noirq */ + .data_xfer = ata_data_xfer, /* Check vlb/noirq */ .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -379,7 +381,7 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) inb(0x3E6); inb(0x3E6); - outb(recover << 4 | active, ap->ioaddr.device_addr); + iowrite8(recover << 4 | active, ap->ioaddr.device_addr); if (adev->class != ATA_DEV_ATA) { u8 rconf = inb(0x3E6); @@ -388,7 +390,7 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) outb(rconf, 0x3E6); } } - inb(ap->ioaddr.status_addr); + ioread8(ap->ioaddr.status_addr); } static struct ata_port_operations ht6560b_port_ops = { @@ -406,7 +408,7 @@ static struct ata_port_operations ht6560b_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, /* FIXME: Check 32bit and noirq */ + .data_xfer = ata_data_xfer, /* FIXME: Check 32bit and noirq */ .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -454,12 +456,12 @@ static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev u8 rc; /* Enter configuration mode */ - inw(ap->ioaddr.error_addr); - inw(ap->ioaddr.error_addr); - outb(3, ap->ioaddr.nsect_addr); + ioread16(ap->ioaddr.error_addr); + ioread16(ap->ioaddr.error_addr); + iowrite8(3, ap->ioaddr.nsect_addr); /* Read VLB clock strapping */ - clock = 1000000000 / khz[inb(ap->ioaddr.lbah_addr) & 0x03]; + clock = 1000000000 / khz[ioread8(ap->ioaddr.lbah_addr) & 0x03]; /* Get the timing data in cycles */ ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000); @@ -477,33 +479,33 @@ static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev setup = FIT(t.setup, 1, 4) - 1; /* Select the right timing bank for write timing */ - rc = inb(ap->ioaddr.lbal_addr); + rc = ioread8(ap->ioaddr.lbal_addr); rc &= 0x7F; rc |= (adev->devno << 7); - outb(rc, ap->ioaddr.lbal_addr); + iowrite8(rc, ap->ioaddr.lbal_addr); /* Write the timings */ - outb(active << 4 | recover, ap->ioaddr.error_addr); + iowrite8(active << 4 | recover, ap->ioaddr.error_addr); /* Select the right bank for read timings, also load the shared timings for address */ - rc = inb(ap->ioaddr.device_addr); + rc = ioread8(ap->ioaddr.device_addr); rc &= 0xC0; rc |= adev->devno; /* Index select */ rc |= (setup << 4) | 0x04; - outb(rc, ap->ioaddr.device_addr); + iowrite8(rc, ap->ioaddr.device_addr); /* Load the read timings */ - outb(active << 4 | recover, ap->ioaddr.data_addr); + iowrite8(active << 4 | recover, ap->ioaddr.data_addr); /* Ensure the timing register mode is right */ - rc = inb (ap->ioaddr.lbal_addr); + rc = ioread8(ap->ioaddr.lbal_addr); rc &= 0x73; rc |= 0x84; - outb(rc, ap->ioaddr.lbal_addr); + iowrite8(rc, ap->ioaddr.lbal_addr); /* Exit command mode */ - outb(0x83, ap->ioaddr.nsect_addr); + iowrite8(0x83, ap->ioaddr.nsect_addr); } @@ -522,7 +524,7 @@ static struct ata_port_operations opti82c611a_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -551,9 +553,9 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev) sysclk = opti_syscfg(0xAC) & 0xC0; /* BIOS set */ /* Enter configuration mode */ - inw(ap->ioaddr.error_addr); - inw(ap->ioaddr.error_addr); - outb(3, ap->ioaddr.nsect_addr); + ioread16(ap->ioaddr.error_addr); + ioread16(ap->ioaddr.error_addr); + iowrite8(3, ap->ioaddr.nsect_addr); /* Read VLB clock strapping */ clock = 1000000000 / khz[sysclk]; @@ -574,33 +576,33 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev) setup = FIT(t.setup, 1, 4) - 1; /* Select the right timing bank for write timing */ - rc = inb(ap->ioaddr.lbal_addr); + rc = ioread8(ap->ioaddr.lbal_addr); rc &= 0x7F; rc |= (adev->devno << 7); - outb(rc, ap->ioaddr.lbal_addr); + iowrite8(rc, ap->ioaddr.lbal_addr); /* Write the timings */ - outb(active << 4 | recover, ap->ioaddr.error_addr); + iowrite8(active << 4 | recover, ap->ioaddr.error_addr); /* Select the right bank for read timings, also load the shared timings for address */ - rc = inb(ap->ioaddr.device_addr); + rc = ioread8(ap->ioaddr.device_addr); rc &= 0xC0; rc |= adev->devno; /* Index select */ rc |= (setup << 4) | 0x04; - outb(rc, ap->ioaddr.device_addr); + iowrite8(rc, ap->ioaddr.device_addr); /* Load the read timings */ - outb(active << 4 | recover, ap->ioaddr.data_addr); + iowrite8(active << 4 | recover, ap->ioaddr.data_addr); /* Ensure the timing register mode is right */ - rc = inb (ap->ioaddr.lbal_addr); + rc = ioread8(ap->ioaddr.lbal_addr); rc &= 0x73; rc |= 0x84; - outb(rc, ap->ioaddr.lbal_addr); + iowrite8(rc, ap->ioaddr.lbal_addr); /* Exit command mode */ - outb(0x83, ap->ioaddr.nsect_addr); + iowrite8(0x83, ap->ioaddr.nsect_addr); /* We need to know this for quad device on the MVB */ ap->host->private_data = ap; @@ -650,7 +652,7 @@ static struct ata_port_operations opti82c46x_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = opti82c46x_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -676,6 +678,7 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl struct ata_probe_ent ae; struct platform_device *pdev; struct ata_port_operations *ops = &legacy_port_ops; + void __iomem *io_addr, *ctrl_addr; int pio_modes = pio_mask; u32 mask = (1 << port); int ret; @@ -689,6 +692,12 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl devm_request_region(&pdev->dev, ctrl, 1, "pata_legacy") == NULL) goto fail; + ret = -ENOMEM; + io_addr = devm_ioport_map(&pdev->dev, io, 8); + ctrl_addr = devm_ioport_map(&pdev->dev, ctrl, 1); + if (!io_addr || !ctrl_addr) + goto fail; + if (ht6560a & mask) { ops = &ht6560a_port_ops; pio_modes = 0x07; @@ -754,9 +763,9 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl ae.irq = irq; ae.irq_flags = 0; ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST; - ae.port[0].cmd_addr = io; - ae.port[0].altstatus_addr = ctrl; - ae.port[0].ctl_addr = ctrl; + ae.port[0].cmd_addr = io_addr; + ae.port[0].altstatus_addr = ctrl_addr; + ae.port[0].ctl_addr = ctrl_addr; ata_std_ports(&ae.port[0]); ae.private_data = ld; diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 0a4409546a02..586cbb750c99 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -57,7 +57,7 @@ static int marvell_pre_reset(struct ata_port *ap) switch(ap->port_no) { case 0: - if (inb(ap->ioaddr.bmdma_addr + 1) & 1) + if (ioread8(ap->ioaddr.bmdma_addr + 1) & 1) ap->cbl = ATA_CBL_PATA40; else ap->cbl = ATA_CBL_PATA80; @@ -129,7 +129,7 @@ static const struct ata_port_operations marvell_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, /* Timeout handling */ .irq_handler = ata_interrupt, diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 5320ea854365..8a9d80c3628e 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -295,7 +295,7 @@ static struct ata_port_operations mpc52xx_ata_port_ops = { .error_handler = mpc52xx_ata_error_handler, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .port_start = ata_port_start, @@ -308,7 +308,7 @@ static struct ata_probe_ent mpc52xx_ata_probe_ent = { .pio_mask = 0x1f, /* Up to PIO4 */ .mwdma_mask = 0x00, /* No MWDMA */ .udma_mask = 0x00, /* No UDMA */ - .port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_MMIO, + .port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, .irq_flags = 0, }; @@ -324,18 +324,18 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv) ae->irq = priv->ata_irq; aio->cmd_addr = 0; /* Don't have a classic reg block */ - aio->altstatus_addr = (unsigned long)&priv->ata_regs->tf_control; - aio->ctl_addr = (unsigned long)&priv->ata_regs->tf_control; - aio->data_addr = (unsigned long)&priv->ata_regs->tf_data; - aio->error_addr = (unsigned long)&priv->ata_regs->tf_features; - aio->feature_addr = (unsigned long)&priv->ata_regs->tf_features; - aio->nsect_addr = (unsigned long)&priv->ata_regs->tf_sec_count; - aio->lbal_addr = (unsigned long)&priv->ata_regs->tf_sec_num; - aio->lbam_addr = (unsigned long)&priv->ata_regs->tf_cyl_low; - aio->lbah_addr = (unsigned long)&priv->ata_regs->tf_cyl_high; - aio->device_addr = (unsigned long)&priv->ata_regs->tf_dev_head; - aio->status_addr = (unsigned long)&priv->ata_regs->tf_command; - aio->command_addr = (unsigned long)&priv->ata_regs->tf_command; + aio->altstatus_addr = &priv->ata_regs->tf_control; + aio->ctl_addr = &priv->ata_regs->tf_control; + aio->data_addr = &priv->ata_regs->tf_data; + aio->error_addr = &priv->ata_regs->tf_features; + aio->feature_addr = &priv->ata_regs->tf_features; + aio->nsect_addr = &priv->ata_regs->tf_sec_count; + aio->lbal_addr = &priv->ata_regs->tf_sec_num; + aio->lbam_addr = &priv->ata_regs->tf_cyl_low; + aio->lbah_addr = &priv->ata_regs->tf_cyl_high; + aio->device_addr = &priv->ata_regs->tf_dev_head; + aio->status_addr = &priv->ata_regs->tf_command; + aio->command_addr = &priv->ata_regs->tf_command; ae->private_data = priv; diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index c4a1b10f3bca..9837faf0f620 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -188,7 +188,7 @@ static struct ata_port_operations mpiix_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = mpiix_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -199,10 +199,11 @@ static struct ata_port_operations mpiix_port_ops = { static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) { /* Single threaded by the PCI probe logic */ - static struct ata_probe_ent probe[2]; + static struct ata_probe_ent probe; static int printed_version; + void __iomem *cmd_addr, *ctl_addr; u16 idetim; - int enabled; + int irq; if (!printed_version++) dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n"); @@ -215,43 +216,43 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) if (!(idetim & ENABLED)) return -ENODEV; + if (!(idetim & SECONDARY)) { + irq = 14; + cmd_addr = devm_ioport_map(&dev->dev, 0x1F0, 8); + ctl_addr = devm_ioport_map(&dev->dev, 0x3F6, 1); + } else { + irq = 15; + cmd_addr = devm_ioport_map(&dev->dev, 0x170, 8); + ctl_addr = devm_ioport_map(&dev->dev, 0x376, 1); + } + + if (!cmd_addr || !ctl_addr) + return -ENOMEM; + /* 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 */ - INIT_LIST_HEAD(&probe[0].node); - probe[0].dev = pci_dev_to_dev(dev); - probe[0].port_ops = &mpiix_port_ops; - probe[0].sht = &mpiix_sht; - probe[0].pio_mask = 0x1F; - probe[0].irq = 14; - probe[0].irq_flags = SA_SHIRQ; - probe[0].port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; - probe[0].n_ports = 1; - probe[0].port[0].cmd_addr = 0x1F0; - probe[0].port[0].ctl_addr = 0x3F6; - probe[0].port[0].altstatus_addr = 0x3F6; - - /* The secondary lurks at different addresses but is otherwise - the same beastie */ - - INIT_LIST_HEAD(&probe[1].node); - probe[1] = probe[0]; - probe[1].irq = 15; - probe[1].port[0].cmd_addr = 0x170; - probe[1].port[0].ctl_addr = 0x376; - probe[1].port[0].altstatus_addr = 0x376; + INIT_LIST_HEAD(&probe.node); + probe.dev = pci_dev_to_dev(dev); + probe.port_ops = &mpiix_port_ops; + probe.sht = &mpiix_sht; + probe.pio_mask = 0x1F; + probe.irq = irq; + probe.irq_flags = SA_SHIRQ; + probe.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; + probe.n_ports = 1; + probe.port[0].cmd_addr = cmd_addr; + probe.port[0].ctl_addr = ctl_addr; + probe.port[0].altstatus_addr = ctl_addr; /* Let libata fill in the port details */ - ata_std_ports(&probe[0].port[0]); - ata_std_ports(&probe[1].port[0]); + ata_std_ports(&probe.port[0]); /* Now add the port that is active */ - enabled = (idetim & SECONDARY) ? 1 : 0; - - if (ata_device_add(&probe[enabled])) + if (ata_device_add(&probe)) return 0; return -ENODEV; } diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index 2a2f8df70582..23365a0ff9b0 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -89,7 +89,7 @@ static const struct ata_port_operations netcell_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, /* IRQ-related hooks */ .irq_handler = ata_interrupt, diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index fdafd92c92a9..95c4e0b3f2d4 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -179,7 +179,7 @@ static struct ata_port_operations ns87410_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ns87410_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index df9f7fd4b4e5..95d570a30a2f 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -259,7 +259,7 @@ static const struct ata_port_operations oldpiix_pata_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = oldpiix_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index 58951ccd1e4d..e76302631597 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -95,18 +95,18 @@ static void opti_error_handler(struct ata_port *ap) static void opti_write_reg(struct ata_port *ap, u8 val, int reg) { - unsigned long regio = ap->ioaddr.cmd_addr; + void __iomem *regio = ap->ioaddr.cmd_addr; /* These 3 unlock the control register access */ - inw(regio + 1); - inw(regio + 1); - outb(3, regio + 2); + ioread16(regio + 1); + ioread16(regio + 1); + iowrite8(3, regio + 2); /* Do the I/O */ - outb(val, regio + reg); + iowrite8(val, regio + reg); /* Relock */ - outb(0x83, regio + 2); + iowrite8(0x83, regio + 2); } /** @@ -124,7 +124,7 @@ static void opti_set_piomode(struct ata_port *ap, struct ata_device *adev) struct ata_device *pair = ata_dev_pair(adev); int clock; int pio = adev->pio_mode - XFER_PIO_0; - unsigned long regio = ap->ioaddr.cmd_addr; + void __iomem *regio = ap->ioaddr.cmd_addr; u8 addr; /* Address table precomputed with prefetch off and a DCLK of 2 */ @@ -137,8 +137,8 @@ static void opti_set_piomode(struct ata_port *ap, struct ata_device *adev) { 0x58, 0x44, 0x32, 0x22, 0x21 } }; - outb(0xff, regio + 5); - clock = inw(regio + 5) & 1; + iowrite8(0xff, regio + 5); + clock = ioread16(regio + 5) & 1; /* * As with many controllers the address setup time is shared @@ -205,7 +205,7 @@ static struct ata_port_operations opti_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index 74d2e7a28da0..067fca1fa8a1 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -91,12 +91,12 @@ static void optidma_error_handler(struct ata_port *ap) static void optidma_unlock(struct ata_port *ap) { - unsigned long regio = ap->ioaddr.cmd_addr; + void __iomem *regio = ap->ioaddr.cmd_addr; /* These 3 unlock the control register access */ - inw(regio + 1); - inw(regio + 1); - outb(3, regio + 2); + ioread16(regio + 1); + ioread16(regio + 1); + iowrite8(3, regio + 2); } /** @@ -108,10 +108,10 @@ static void optidma_unlock(struct ata_port *ap) static void optidma_lock(struct ata_port *ap) { - unsigned long regio = ap->ioaddr.cmd_addr; + void __iomem *regio = ap->ioaddr.cmd_addr; /* Relock */ - outb(0x83, regio + 2); + iowrite8(0x83, regio + 2); } /** @@ -133,7 +133,7 @@ static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo struct ata_device *pair = ata_dev_pair(adev); int pio = adev->pio_mode - XFER_PIO_0; int dma = adev->dma_mode - XFER_MW_DMA_0; - unsigned long regio = ap->ioaddr.cmd_addr; + void __iomem *regio = ap->ioaddr.cmd_addr; u8 addr; /* Address table precomputed with a DCLK of 2 */ @@ -178,20 +178,20 @@ static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo /* Commence primary programming sequence */ /* First we load the device number into the timing select */ - outb(adev->devno, regio + MISC_REG); + iowrite8(adev->devno, regio + MISC_REG); /* Now we load the data timings into read data/write data */ if (mode < XFER_MW_DMA_0) { - outb(data_rec_timing[pci_clock][pio], regio + READ_REG); - outb(data_rec_timing[pci_clock][pio], regio + WRITE_REG); + iowrite8(data_rec_timing[pci_clock][pio], regio + READ_REG); + iowrite8(data_rec_timing[pci_clock][pio], regio + WRITE_REG); } else if (mode < XFER_UDMA_0) { - outb(dma_data_rec_timing[pci_clock][dma], regio + READ_REG); - outb(dma_data_rec_timing[pci_clock][dma], regio + WRITE_REG); + iowrite8(dma_data_rec_timing[pci_clock][dma], regio + READ_REG); + iowrite8(dma_data_rec_timing[pci_clock][dma], regio + WRITE_REG); } /* Finally we load the address setup into the misc register */ - outb(addr | adev->devno, regio + MISC_REG); + iowrite8(addr | adev->devno, regio + MISC_REG); /* Programming sequence complete, timing 0 dev 0, timing 1 dev 1 */ - outb(0x85, regio + CNTRL_REG); + iowrite8(0x85, regio + CNTRL_REG); /* Switch back to IDE mode */ optidma_lock(ap); @@ -389,7 +389,7 @@ static struct ata_port_operations optidma_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -422,7 +422,7 @@ static struct ata_port_operations optiplus_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 5a9b24950f99..1830e9166943 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -88,7 +88,7 @@ static struct ata_port_operations pcmcia_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer_noirq, + .data_xfer = ata_data_xfer_noirq, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -121,6 +121,7 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) cistpl_cftable_entry_t *cfg; int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM; unsigned long io_base, ctl_base; + void __iomem *io_addr, *ctl_addr; info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) @@ -231,10 +232,17 @@ next_entry: CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq)); CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf)); + /* iomap */ + ret = -ENOMEM; + io_addr = devm_ioport_map(&pdev->dev, io_base, 8); + ctl_addr = devm_ioport_map(&pdev->dev, ctl_base, 1); + if (!io_addr || !ctl_addr) + goto failed; + /* Success. Disable the IRQ nIEN line, do quirks */ - outb(0x02, ctl_base); + iowrite8(0x02, ctl_addr); if (is_kme) - outb(0x81, ctl_base + 0x01); + iowrite8(0x81, ctl_addr + 0x01); /* FIXME: Could be more ports at base + 0x10 but we only deal with one right now */ @@ -256,11 +264,12 @@ next_entry: ae.irq = pdev->irq.AssignedIRQ; ae.irq_flags = SA_SHIRQ; ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; - ae.port[0].cmd_addr = io_base; - ae.port[0].altstatus_addr = ctl_base; - ae.port[0].ctl_addr = ctl_base; + ae.port[0].cmd_addr = io_addr; + ae.port[0].altstatus_addr = ctl_addr; + ae.port[0].ctl_addr = ctl_addr; ata_std_ports(&ae.port[0]); + ret = -ENODEV; if (ata_device_add(&ae) == 0) goto failed; diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 1c106b866c79..2ff91bbbab06 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -45,6 +45,8 @@ #endif enum { + PDC_MMIO_BAR = 5, + PDC_UDMA_100 = 0, PDC_UDMA_133 = 1, @@ -158,7 +160,7 @@ static struct ata_port_operations pdc2027x_pata100_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -190,7 +192,7 @@ static struct ata_port_operations pdc2027x_pata133_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -239,7 +241,7 @@ MODULE_DEVICE_TABLE(pci, pdc2027x_pci_tbl); */ static inline void __iomem *port_mmio(struct ata_port *ap, unsigned int offset) { - return ap->host->mmio_base + ap->port_no * 0x100 + offset; + return ap->host->iomap[PDC_MMIO_BAR] + ap->port_no * 0x100 + offset; } /** @@ -520,18 +522,19 @@ static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc) static long pdc_read_counter(struct ata_probe_ent *probe_ent) { + void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR]; long counter; int retry = 1; u32 bccrl, bccrh, bccrlv, bccrhv; retry: - bccrl = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff; - bccrh = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff; + bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff; + bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff; rmb(); /* Read the counter values again for verification */ - bccrlv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff; - bccrhv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff; + bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff; + bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff; rmb(); counter = (bccrh << 15) | bccrl; @@ -562,7 +565,7 @@ retry: */ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsigned int board_idx) { - + void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR]; u16 pll_ctl; long pll_clock_khz = pll_clock / 1000; long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ; @@ -581,7 +584,7 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi /* Show the current clock value of PLL control register * (maybe already configured by the firmware) */ - pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL); + pll_ctl = readw(mmio_base + PDC_PLL_CTL); PDPRINTK("pll_ctl[%X]\n", pll_ctl); #endif @@ -621,8 +624,8 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl); - writew(pll_ctl, probe_ent->mmio_base + PDC_PLL_CTL); - readw(probe_ent->mmio_base + PDC_PLL_CTL); /* flush */ + writew(pll_ctl, mmio_base + PDC_PLL_CTL); + readw(mmio_base + PDC_PLL_CTL); /* flush */ /* Wait the PLL circuit to be stable */ mdelay(30); @@ -632,7 +635,7 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi * Show the current clock value of PLL control register * (maybe configured by the firmware) */ - pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL); + pll_ctl = readw(mmio_base + PDC_PLL_CTL); PDPRINTK("pll_ctl[%X]\n", pll_ctl); #endif @@ -648,6 +651,7 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi */ static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent) { + void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR]; u32 scr; long start_count, end_count; long pll_clock; @@ -656,10 +660,10 @@ static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent) start_count = pdc_read_counter(probe_ent); /* Start the test mode */ - scr = readl(probe_ent->mmio_base + PDC_SYS_CTL); + scr = readl(mmio_base + PDC_SYS_CTL); PDPRINTK("scr[%X]\n", scr); - writel(scr | (0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL); - readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */ + writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL); + readl(mmio_base + PDC_SYS_CTL); /* flush */ /* Let the counter run for 100 ms. */ mdelay(100); @@ -668,10 +672,10 @@ static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent) end_count = pdc_read_counter(probe_ent); /* Stop the test mode */ - scr = readl(probe_ent->mmio_base + PDC_SYS_CTL); + scr = readl(mmio_base + PDC_SYS_CTL); PDPRINTK("scr[%X]\n", scr); - writel(scr & ~(0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL); - readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */ + writel(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL); + readl(mmio_base + PDC_SYS_CTL); /* flush */ /* calculate the input clock in Hz */ pll_clock = (start_count - end_count) * 10; @@ -716,7 +720,7 @@ static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, uns * @port: ata ioports to setup * @base: base address */ -static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base) +static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base) { port->cmd_addr = port->data_addr = base; @@ -750,7 +754,6 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de unsigned int board_idx = (unsigned int) ent->driver_data; struct ata_probe_ent *probe_ent; - unsigned long base; void __iomem *mmio_base; int rc; @@ -761,7 +764,7 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); + rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME); if (rc) return rc; @@ -781,12 +784,6 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pcim_iomap(pdev, 5, 0); - if (!mmio_base) - return -ENOMEM; - - base = (unsigned long) mmio_base; - probe_ent->sht = pdc2027x_port_info[board_idx].sht; probe_ent->port_flags = pdc2027x_port_info[board_idx].flags; probe_ent->pio_mask = pdc2027x_port_info[board_idx].pio_mask; @@ -796,12 +793,14 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); + + mmio_base = probe_ent->iomap[PDC_MMIO_BAR]; - pdc_ata_setup_port(&probe_ent->port[0], base + 0x17c0); - probe_ent->port[0].bmdma_addr = base + 0x1000; - pdc_ata_setup_port(&probe_ent->port[1], base + 0x15c0); - probe_ent->port[1].bmdma_addr = base + 0x1008; + pdc_ata_setup_port(&probe_ent->port[0], mmio_base + 0x17c0); + probe_ent->port[0].bmdma_addr = mmio_base + 0x1000; + pdc_ata_setup_port(&probe_ent->port[1], mmio_base + 0x15c0); + probe_ent->port[1].bmdma_addr = mmio_base + 0x1008; probe_ent->n_ports = 2; diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index c52e1e8aa2d2..7e194d81c1b6 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -170,17 +170,17 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) struct ata_taskfile *tf = &qc->tf; int sel66 = ap->port_no ? 0x08: 0x02; - unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr; - unsigned long clock = master + 0x11; - unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no); + void __iomem *master = ap->host->ports[0]->ioaddr.bmdma_addr; + void __iomem *clock = master + 0x11; + void __iomem *atapi_reg = master + 0x20 + (4 * ap->port_no); u32 len; /* Check we keep host level locking here */ if (adev->dma_mode >= XFER_UDMA_2) - outb(inb(clock) | sel66, clock); + iowrite8(ioread8(clock) | sel66, clock); else - outb(inb(clock) & ~sel66, clock); + iowrite8(ioread8(clock) & ~sel66, clock); /* The DMA clocks may have been trashed by a reset. FIXME: make conditional and move to qc_issue ? */ @@ -196,7 +196,7 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) else len |= 0x05000000; - outl(len, atapi_reg); + iowrite32(len, atapi_reg); } /* Activate DMA */ @@ -219,19 +219,19 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc) int sel66 = ap->port_no ? 0x08: 0x02; /* The clock bits are in the same register for both channels */ - unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr; - unsigned long clock = master + 0x11; - unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no); + void __iomem *master = ap->host->ports[0]->ioaddr.bmdma_addr; + void __iomem *clock = master + 0x11; + void __iomem *atapi_reg = master + 0x20 + (4 * ap->port_no); /* Cases the state machine will not complete correctly */ if (tf->protocol == ATA_PROT_ATAPI_DMA || ( tf->flags & ATA_TFLAG_LBA48)) { - outl(0, atapi_reg); - outb(inb(clock) & ~sel66, clock); + 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) - outb(inb(clock) & ~sel66, clock); + iowrite8(ioread8(clock) & ~sel66, clock); ata_bmdma_stop(qc); } @@ -294,7 +294,7 @@ static struct ata_port_operations pdc2024x_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -326,7 +326,7 @@ static struct ata_port_operations pdc2026x_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 8a261a3daeda..b35fc29f4db5 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -83,7 +83,7 @@ static struct ata_port_operations pata_platform_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer_noirq, + .data_xfer = ata_data_xfer_noirq, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -134,7 +134,6 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) struct resource *io_res, *ctl_res; struct ata_probe_ent ae; unsigned int mmio; - int ret; /* * Simple resource validation .. @@ -188,48 +187,29 @@ static int __devinit pata_platform_probe(struct platform_device *pdev) * Handle the MMIO case */ if (mmio) { - ae.port_flags |= ATA_FLAG_MMIO; - - ae.port[0].cmd_addr = (unsigned long) - devm_ioremap(&pdev->dev, io_res->start, - io_res->end - io_res->start + 1); - if (unlikely(!ae.port[0].cmd_addr)) { - dev_err(&pdev->dev, "failed to remap IO base\n"); - return -ENXIO; - } - - ae.port[0].ctl_addr = (unsigned long) - devm_ioremap(&pdev->dev, ctl_res->start, - ctl_res->end - ctl_res->start + 1); - if (unlikely(!ae.port[0].ctl_addr)) { - dev_err(&pdev->dev, "failed to remap CTL base\n"); - ret = -ENXIO; - goto bad_remap; - } + ae.port[0].cmd_addr = devm_ioremap(&pdev->dev, io_res->start, + io_res->end - io_res->start + 1); + ae.port[0].ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start, + ctl_res->end - ctl_res->start + 1); } else { - ae.port[0].cmd_addr = io_res->start; - ae.port[0].ctl_addr = ctl_res->start; + ae.port[0].cmd_addr = devm_ioport_map(&pdev->dev, io_res->start, + io_res->end - io_res->start + 1); + ae.port[0].ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start, + ctl_res->end - ctl_res->start + 1); + } + if (!ae.port[0].cmd_addr || !ae.port[0].ctl_addr) { + dev_err(&pdev->dev, "failed to map IO/CTL base\n"); + return -ENOMEM; } ae.port[0].altstatus_addr = ae.port[0].ctl_addr; pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data); - if (unlikely(ata_device_add(&ae) == 0)) { - ret = -ENODEV; - goto add_failed; - } + if (unlikely(ata_device_add(&ae) == 0)) + return -ENODEV; return 0; - -add_failed: - if (ae.port[0].ctl_addr && mmio) - iounmap((void __iomem *)ae.port[0].ctl_addr); -bad_remap: - if (ae.port[0].cmd_addr && mmio) - iounmap((void __iomem *)ae.port[0].cmd_addr); - - return ret; } /** diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 4413960042a9..5b86effa0bbd 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -131,22 +131,24 @@ static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned if (ata_id_has_dword_io(adev->id)) { if (write_data) - outsl(ap->ioaddr.data_addr, buf, buflen >> 2); + iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); else - insl(ap->ioaddr.data_addr, buf, buflen >> 2); + ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); if (unlikely(slop)) { u32 pad; if (write_data) { memcpy(&pad, buf + buflen - slop, slop); - outl(le32_to_cpu(pad), ap->ioaddr.data_addr); + pad = le32_to_cpu(pad); + iowrite32(pad, ap->ioaddr.data_addr); } else { - pad = cpu_to_le32(inl(ap->ioaddr.data_addr)); + pad = ioread32(ap->ioaddr.data_addr); + pad = cpu_to_le32(pad); memcpy(buf + buflen - slop, &pad, slop); } } } else - ata_pio_data_xfer(adev, buf, buflen, write_data); + ata_data_xfer(adev, buf, buflen, write_data); } static struct scsi_host_template qdi_sht = { @@ -234,10 +236,9 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i { struct ata_probe_ent ae; struct platform_device *pdev; + void __iomem *io_addr, *ctl_addr; int ret; - unsigned long ctrl = io + 0x206; - /* * Fill in a probe structure first of all */ @@ -246,6 +247,12 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i if (IS_ERR(pdev)) return PTR_ERR(pdev); + ret = -ENOMEM; + io_addr = devm_ioport_map(&pdev->dev, io, 8); + ctl_addr = devm_ioport_map(&pdev->dev, io + 0x206, 1); + if (!io_addr || !ctl_addr) + goto fail; + memset(&ae, 0, sizeof(struct ata_probe_ent)); INIT_LIST_HEAD(&ae.node); ae.dev = &pdev->dev; @@ -263,9 +270,9 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i ae.irq = irq; ae.irq_flags = 0; ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; - ae.port[0].cmd_addr = io; - ae.port[0].altstatus_addr = ctrl; - ae.port[0].ctl_addr = ctrl; + ae.port[0].cmd_addr = io_addr; + ae.port[0].altstatus_addr = ctl_addr; + ae.port[0].ctl_addr = ctl_addr; ata_std_ports(&ae.port[0]); /* @@ -278,14 +285,17 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i qdi_data[nr_qdi_host].platform_dev = pdev; printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io); - ret = ata_device_add(&ae); - if (ret == 0) { - platform_device_unregister(pdev); - return -ENODEV; - } + + ret = -ENODEV; + if (!ata_device_add(&ae)) + goto fail; qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev); return 0; + + fail: + platform_device_unregister(pdev); + return ret; } /** diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index ca9c97056c1b..a391bd2fa8fe 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -255,7 +255,7 @@ static const struct ata_port_operations radisys_pata_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = radisys_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index c99331bbbdd9..4a4d2e5be09b 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -115,7 +115,7 @@ static struct ata_port_operations rz1000_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 75638ccc0183..8d3e7c57b22c 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -220,7 +220,7 @@ static struct ata_port_operations sc1200_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = sc1200_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 46ea1e8af4f4..c41a1d3b5b7d 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 = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -381,7 +381,7 @@ static struct ata_port_operations serverworks_csb_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 955c1d3a5739..992e22537023 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -252,7 +252,7 @@ static struct ata_port_operations sil680_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 88ed2aad4629..c82d75b96f60 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -603,7 +603,7 @@ static const struct ata_port_operations sis_133_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -634,7 +634,7 @@ static const struct ata_port_operations sis_133_early_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -666,7 +666,7 @@ static const struct ata_port_operations sis_100_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -697,7 +697,7 @@ static const struct ata_port_operations sis_66_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -728,7 +728,7 @@ static const struct ata_port_operations sis_old_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index d118a1822c45..c7770f8df8d3 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -262,7 +262,7 @@ static struct ata_port_operations sl82c105_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index 57385a2f8286..60f2eea3c838 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -221,7 +221,7 @@ static struct ata_port_operations triflex_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 2b262363b96a..236276d6ef3b 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -334,7 +334,7 @@ static struct ata_port_operations via_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, @@ -367,7 +367,7 @@ static struct ata_port_operations via_port_ops_noirq = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer_noirq, + .data_xfer = ata_data_xfer_noirq, .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index bba04a6e3708..d24488bf5644 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -100,22 +100,24 @@ static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsig if (ata_id_has_dword_io(adev->id)) { if (write_data) - outsl(ap->ioaddr.data_addr, buf, buflen >> 2); + iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); else - insl(ap->ioaddr.data_addr, buf, buflen >> 2); + ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); if (unlikely(slop)) { u32 pad; if (write_data) { memcpy(&pad, buf + buflen - slop, slop); - outl(le32_to_cpu(pad), ap->ioaddr.data_addr); + pad = le32_to_cpu(pad); + iowrite32(pad, ap->ioaddr.data_addr); } else { - pad = cpu_to_le16(inl(ap->ioaddr.data_addr)); + pad = ioread32(ap->ioaddr.data_addr); + pad = cpu_to_le16(pad); memcpy(buf + buflen - slop, &pad, slop); } } } else - ata_pio_data_xfer(adev, buf, buflen, write_data); + ata_data_xfer(adev, buf, buflen, write_data); } static struct scsi_host_template winbond_sht = { @@ -197,6 +199,8 @@ static __init int winbond_init_one(unsigned long port) return 0; for (i = 0; i < 2 ; i ++) { + unsigned long cmd_port = 0x1F0 - (0x80 * i); + void __iomem *cmd_addr, *ctl_addr; if (reg & (1 << i)) { /* @@ -207,6 +211,13 @@ static __init int winbond_init_one(unsigned long port) if (IS_ERR(pdev)) return PTR_ERR(pdev); + cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8); + ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1); + if (!cmd_addr || !ctl_addr) { + platform_device_unregister(pdev); + return -ENOMEM; + } + memset(&ae, 0, sizeof(struct ata_probe_ent)); INIT_LIST_HEAD(&ae.node); ae.dev = &pdev->dev; @@ -220,9 +231,9 @@ static __init int winbond_init_one(unsigned long port) ae.irq = 14 + i; ae.irq_flags = 0; ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; - ae.port[0].cmd_addr = 0x1F0 - (0x80 * i); - ae.port[0].altstatus_addr = ae.port[0].cmd_addr + 0x0206; - ae.port[0].ctl_addr = ae.port[0].altstatus_addr; + ae.port[0].cmd_addr = cmd_addr; + ae.port[0].altstatus_addr = ctl_addr; + ae.port[0].ctl_addr = ctl_addr; ata_std_ports(&ae.port[0]); /* * Hook in a private data structure per channel diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index a6bf7cbdfdc5..71e17df83f48 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -51,9 +51,15 @@ #define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40)) /* macro to calculate base address for ADMA regs */ -#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20)) +#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20)) + +/* macro to obtain addresses from ata_host */ +#define ADMA_HOST_REGS(host,port_no) \ + ADMA_REGS((host)->iomap[ADMA_MMIO_BAR], port_no) enum { + ADMA_MMIO_BAR = 4, + ADMA_PORTS = 2, ADMA_CPB_BYTES = 40, ADMA_PRD_BYTES = LIBATA_MAX_PRD * 16, @@ -166,7 +172,7 @@ static const struct ata_port_operations adma_ata_ops = { .qc_prep = adma_qc_prep, .qc_issue = adma_qc_issue, .eng_timeout = adma_eng_timeout, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = adma_intr, .irq_clear = adma_irq_clear, .port_start = adma_port_start, @@ -234,11 +240,10 @@ static void adma_reset_engine(void __iomem *chan) static void adma_reinit_engine(struct ata_port *ap) { struct adma_port_priv *pp = ap->private_data; - void __iomem *mmio_base = ap->host->mmio_base; - void __iomem *chan = ADMA_REGS(mmio_base, ap->port_no); + void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no); /* mask/clear ATA interrupts */ - writeb(ATA_NIEN, (void __iomem *)ap->ioaddr.ctl_addr); + writeb(ATA_NIEN, ap->ioaddr.ctl_addr); ata_check_status(ap); /* reset the ADMA engine */ @@ -262,7 +267,7 @@ static void adma_reinit_engine(struct ata_port *ap) static inline void adma_enter_reg_mode(struct ata_port *ap) { - void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no); + void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no); writew(aPIOMD4, chan + ADMA_CONTROL); readb(chan + ADMA_STATUS); /* flush */ @@ -409,7 +414,7 @@ static void adma_qc_prep(struct ata_queued_cmd *qc) static inline void adma_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no); + void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no); VPRINTK("ENTER, ap %p\n", ap); @@ -442,13 +447,12 @@ static unsigned int adma_qc_issue(struct ata_queued_cmd *qc) static inline unsigned int adma_intr_pkt(struct ata_host *host) { unsigned int handled = 0, port_no; - u8 __iomem *mmio_base = host->mmio_base; for (port_no = 0; port_no < host->n_ports; ++port_no) { struct ata_port *ap = host->ports[port_no]; struct adma_port_priv *pp; struct ata_queued_cmd *qc; - void __iomem *chan = ADMA_REGS(mmio_base, port_no); + void __iomem *chan = ADMA_HOST_REGS(host, port_no); u8 status = readb(chan + ADMA_STATUS); if (status == 0) @@ -522,7 +526,7 @@ static irqreturn_t adma_intr(int irq, void *dev_instance) return IRQ_RETVAL(handled); } -static void adma_ata_setup_port(struct ata_ioports *port, unsigned long base) +static void adma_ata_setup_port(struct ata_ioports *port, void __iomem *base) { port->cmd_addr = port->data_addr = base + 0x000; @@ -570,7 +574,7 @@ static int adma_port_start(struct ata_port *ap) static void adma_port_stop(struct ata_port *ap) { - adma_reset_engine(ADMA_REGS(ap->host->mmio_base, ap->port_no)); + adma_reset_engine(ADMA_HOST_REGS(ap->host, ap->port_no)); } static void adma_host_stop(struct ata_host *host) @@ -578,14 +582,14 @@ static void adma_host_stop(struct ata_host *host) unsigned int port_no; for (port_no = 0; port_no < ADMA_PORTS; ++port_no) - adma_reset_engine(ADMA_REGS(host->mmio_base, port_no)); + adma_reset_engine(ADMA_HOST_REGS(host, port_no)); } static void adma_host_init(unsigned int chip_id, struct ata_probe_ent *probe_ent) { unsigned int port_no; - void __iomem *mmio_base = probe_ent->mmio_base; + void __iomem *mmio_base = probe_ent->iomap[ADMA_MMIO_BAR]; /* enable/lock aGO operation */ writeb(7, mmio_base + ADMA_MODE_LOCK); @@ -615,7 +619,7 @@ static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) } static int adma_ata_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) + const struct pci_device_id *ent) { static int printed_version; struct ata_probe_ent *probe_ent = NULL; @@ -630,16 +634,13 @@ static int adma_ata_init_one(struct pci_dev *pdev, if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) - return rc; - if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) return -ENODEV; - mmio_base = pcim_iomap(pdev, 4, 0); - if (mmio_base == NULL) - return -ENOMEM; + rc = pcim_iomap_regions(pdev, 1 << ADMA_MMIO_BAR, DRV_NAME); + if (rc) + return rc; + mmio_base = pcim_iomap_table(pdev)[ADMA_MMIO_BAR]; rc = adma_set_dma_masks(pdev, mmio_base); if (rc) @@ -661,12 +662,12 @@ static int adma_ata_init_one(struct pci_dev *pdev, probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; probe_ent->n_ports = ADMA_PORTS; + probe_ent->iomap = pcim_iomap_table(pdev); for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) { adma_ata_setup_port(&probe_ent->port[port_no], - ADMA_ATA_REGS((unsigned long)mmio_base, port_no)); + ADMA_ATA_REGS(mmio_base, port_no)); } pci_set_master(pdev); diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index c98e0227a60c..b2a6f77b38d6 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -147,7 +147,7 @@ static const int scr_map[] = { static void __iomem * inic_port_base(struct ata_port *ap) { - return ap->host->mmio_base + ap->port_no * PORT_SIZE; + return ap->host->iomap[MMIO_BAR] + ap->port_no * PORT_SIZE; } static void __inic_set_pirq_mask(struct ata_port *ap, u8 mask) @@ -324,7 +324,7 @@ static void inic_host_intr(struct ata_port *ap) static irqreturn_t inic_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; - void __iomem *mmio_base = host->mmio_base; + void __iomem *mmio_base = host->iomap[MMIO_BAR]; u16 host_irq_stat; int i, handled = 0;; @@ -566,7 +566,7 @@ static struct ata_port_operations inic_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = inic_qc_issue, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = inic_freeze, .thaw = inic_thaw, @@ -638,7 +638,7 @@ static int inic_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); struct inic_host_priv *hpriv = host->private_data; - void __iomem *mmio_base = host->mmio_base; + void __iomem *mmio_base = host->iomap[MMIO_BAR]; int rc; ata_pci_device_do_resume(pdev); @@ -661,7 +661,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct ata_port_info *pinfo = &inic_port_info; struct ata_probe_ent *probe_ent; struct inic_host_priv *hpriv; - void __iomem *mmio_base; + void __iomem * const *iomap; int i, rc; if (!printed_version++) @@ -675,9 +675,10 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - mmio_base = pci_iomap(pdev, MMIO_BAR, 0); - if (!mmio_base) - return -ENOMEM; + rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME); + if (rc) + return rc; + iomap = pcim_iomap_table(pdev); /* Set dma_mask. This devices doesn't support 64bit addressing. */ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); @@ -713,26 +714,25 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = iomap; for (i = 0; i < NR_PORTS; i++) { struct ata_ioports *port = &probe_ent->port[i]; - unsigned long port_base = - (unsigned long)mmio_base + i * PORT_SIZE; + void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE; - port->cmd_addr = pci_resource_start(pdev, 2 * i); + port->cmd_addr = iomap[2 * i]; port->altstatus_addr = - port->ctl_addr = - pci_resource_start(pdev, 2 * i + 1) | ATA_PCI_CTL_OFS; + port->ctl_addr = (void __iomem *) + ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS); port->scr_addr = port_base + PORT_SCR; ata_std_ports(port); } probe_ent->private_data = hpriv; - hpriv->cached_hctl = readw(mmio_base + HOST_CTL); + hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL); - rc = init_controller(mmio_base, hpriv->cached_hctl); + rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl); if (rc) { dev_printk(KERN_ERR, &pdev->dev, "failed to initialize controller\n"); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index c073e453dcdd..7c578c275db0 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -404,7 +404,7 @@ static const struct ata_port_operations mv5_ops = { .qc_prep = mv_qc_prep, .qc_issue = mv_qc_issue, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .eng_timeout = mv_eng_timeout, @@ -431,7 +431,7 @@ static const struct ata_port_operations mv6_ops = { .qc_prep = mv_qc_prep, .qc_issue = mv_qc_issue, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .eng_timeout = mv_eng_timeout, @@ -458,7 +458,7 @@ static const struct ata_port_operations mv_iie_ops = { .qc_prep = mv_qc_prep_iie, .qc_issue = mv_qc_issue, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .eng_timeout = mv_eng_timeout, @@ -615,7 +615,7 @@ static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port) static inline void __iomem *mv_ap_base(struct ata_port *ap) { - return mv_port_base(ap->host->mmio_base, ap->port_no); + return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no); } static inline int mv_get_hc_count(unsigned long port_flags) @@ -1299,7 +1299,7 @@ static void mv_err_intr(struct ata_port *ap, int reset_allowed) */ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) { - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[MV_PRIMARY_BAR]; void __iomem *hc_mmio = mv_hc_base(mmio, hc); struct ata_queued_cmd *qc; u32 hc_irq_cause; @@ -1342,8 +1342,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc) } else { /* PIO: check for device (drive) interrupt */ if ((DEV_IRQ << hard_port) & hc_irq_cause) { - ata_status = readb((void __iomem *) - ap->ioaddr.status_addr); + ata_status = readb(ap->ioaddr.status_addr); handled = 1; /* ignore spurious intr if drive still BUSY */ if (ata_status & ATA_BUSY) { @@ -1403,7 +1402,7 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; unsigned int hc, handled = 0, n_hcs; - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[MV_PRIMARY_BAR]; struct mv_host_priv *hpriv; u32 irq_stat; @@ -1479,22 +1478,24 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in) static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in) { - void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no); + void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; + void __iomem *addr = mv5_phy_base(mmio, ap->port_no); unsigned int ofs = mv5_scr_offset(sc_reg_in); if (ofs != 0xffffffffU) - return readl(mmio + ofs); + return readl(addr + ofs); else return (u32) ofs; } static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) { - void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no); + void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; + void __iomem *addr = mv5_phy_base(mmio, ap->port_no); unsigned int ofs = mv5_scr_offset(sc_reg_in); if (ofs != 0xffffffffU) - writelfl(val, mmio + ofs); + writelfl(val, addr + ofs); } static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio) @@ -1856,7 +1857,7 @@ static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio, static void mv_stop_and_reset(struct ata_port *ap) { struct mv_host_priv *hpriv = ap->host->private_data; - void __iomem *mmio = ap->host->mmio_base; + void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; mv_stop_dma(ap); @@ -1954,10 +1955,10 @@ comreset_retry: break; } - tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr); - tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr); - tf.lbal = readb((void __iomem *) ap->ioaddr.lbal_addr); - tf.nsect = readb((void __iomem *) ap->ioaddr.nsect_addr); + tf.lbah = readb(ap->ioaddr.lbah_addr); + tf.lbam = readb(ap->ioaddr.lbam_addr); + tf.lbal = readb(ap->ioaddr.lbal_addr); + tf.nsect = readb(ap->ioaddr.nsect_addr); dev->class = ata_dev_classify(&tf); if (!ata_dev_enabled(dev)) { @@ -1989,17 +1990,17 @@ static void mv_phy_reset(struct ata_port *ap) */ static void mv_eng_timeout(struct ata_port *ap) { + void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR]; struct ata_queued_cmd *qc; unsigned long flags; ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n"); DPRINTK("All regs @ start of eng_timeout\n"); - mv_dump_all_regs(ap->host->mmio_base, ap->port_no, - to_pci_dev(ap->host->dev)); + mv_dump_all_regs(mmio, ap->port_no, to_pci_dev(ap->host->dev)); qc = ata_qc_from_tag(ap, ap->active_tag); printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n", - ap->host->mmio_base, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd); + mmio, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd); spin_lock_irqsave(&ap->host->lock, flags); mv_err_intr(ap, 0); @@ -2027,7 +2028,7 @@ static void mv_eng_timeout(struct ata_port *ap) */ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) { - unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS; + void __iomem *shd_base = port_mmio + SHD_BLK_OFS; unsigned serr_ofs; /* PIO related setup @@ -2175,7 +2176,7 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent, unsigned int board_idx) { int rc = 0, n_hc, port, hc; - void __iomem *mmio = probe_ent->mmio_base; + void __iomem *mmio = probe_ent->iomap[MV_PRIMARY_BAR]; struct mv_host_priv *hpriv = probe_ent->private_data; /* global interrupt mask */ @@ -2297,7 +2298,6 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct ata_probe_ent *probe_ent; struct mv_host_priv *hpriv; unsigned int board_idx = (unsigned int)ent->driver_data; - void __iomem *mmio_base; int rc; if (!printed_version++) @@ -2308,11 +2308,11 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return rc; pci_set_master(pdev); - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { + rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME); + if (rc == -EBUSY) pcim_pin_device(pdev); + if (rc) return rc; - } probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) @@ -2321,10 +2321,6 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pcim_iomap(pdev, MV_PRIMARY_BAR, 0); - if (mmio_base == NULL) - return -ENOMEM; - hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; @@ -2337,7 +2333,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); probe_ent->private_data = hpriv; /* initialize adapter */ diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 18361a38aee7..b9ef6f5f4024 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -54,6 +54,8 @@ #define NV_ADMA_DMA_BOUNDARY 0xffffffffUL enum { + NV_MMIO_BAR = 5, + NV_PORTS = 2, NV_PIO_MASK = 0x1f, NV_MWDMA_MASK = 0x07, @@ -357,7 +359,7 @@ static const struct ata_port_operations nv_generic_ops = { .thaw = ata_bmdma_thaw, .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = nv_generic_interrupt, .irq_clear = ata_bmdma_irq_clear, .scr_read = nv_scr_read, @@ -382,7 +384,7 @@ static const struct ata_port_operations nv_nf2_ops = { .thaw = nv_nf2_thaw, .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = nv_nf2_interrupt, .irq_clear = ata_bmdma_irq_clear, .scr_read = nv_scr_read, @@ -407,7 +409,7 @@ static const struct ata_port_operations nv_ck804_ops = { .thaw = nv_ck804_thaw, .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = nv_ck804_interrupt, .irq_clear = ata_bmdma_irq_clear, .scr_read = nv_scr_read, @@ -434,7 +436,7 @@ static const struct ata_port_operations nv_adma_ops = { .thaw = nv_ck804_thaw, .error_handler = nv_adma_error_handler, .post_internal_cmd = nv_adma_bmdma_stop, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = nv_adma_interrupt, .irq_clear = nv_adma_irq_clear, .scr_read = nv_scr_read, @@ -736,7 +738,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) /* if in ATA register mode, use standard ata interrupt handler */ if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) { - u8 irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804) + 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)) /** NV_INT_DEV indication seems unreliable at times @@ -827,7 +829,7 @@ static void nv_adma_irq_clear(struct ata_port *ap) u16 status = readw(mmio + NV_ADMA_STAT); u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); - unsigned long dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; + void __iomem *dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS; /* clear ADMA status */ writew(status, mmio + NV_ADMA_STAT); @@ -835,7 +837,7 @@ static void nv_adma_irq_clear(struct ata_port *ap) pp->notifier_clear_block); /** clear legacy status */ - outb(inb(dma_stat_addr), dma_stat_addr); + iowrite8(ioread8(dma_stat_addr), dma_stat_addr); } static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc) @@ -851,15 +853,15 @@ static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc) } /* load PRD table addr. */ - outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); + iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); /* specify data direction, triple-check start bit is clear */ - dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); if (!rw) dmactl |= ATA_DMA_WR; - outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); /* issue r/w command */ ata_exec_command(ap, &qc->tf); @@ -877,9 +879,9 @@ static void nv_adma_bmdma_start(struct ata_queued_cmd *qc) } /* start host DMA transaction */ - dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - outb(dmactl | ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + iowrite8(dmactl | ATA_DMA_START, + ap->ioaddr.bmdma_addr + ATA_DMA_CMD); } static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc) @@ -891,8 +893,8 @@ static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc) return; /* clear start/stop bit */ - outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); + iowrite8(ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, + ap->ioaddr.bmdma_addr + ATA_DMA_CMD); /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ ata_altstatus(ap); /* dummy read */ @@ -904,7 +906,7 @@ static u8 nv_adma_bmdma_status(struct ata_port *ap) WARN_ON(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)); - return inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); } static int nv_adma_port_start(struct ata_port *ap) @@ -927,10 +929,10 @@ static int nv_adma_port_start(struct ata_port *ap) if (!pp) return -ENOMEM; - mmio = ap->host->mmio_base + NV_ADMA_PORT + + mmio = ap->host->iomap[NV_MMIO_BAR] + NV_ADMA_PORT + ap->port_no * NV_ADMA_PORT_SIZE; pp->ctl_block = mmio; - pp->gen_block = ap->host->mmio_base + NV_ADMA_GEN; + pp->gen_block = ap->host->iomap[NV_MMIO_BAR] + NV_ADMA_GEN; pp->notifier_clear_block = pp->gen_block + NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no); @@ -1046,26 +1048,26 @@ static int nv_adma_port_resume(struct ata_port *ap) static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port) { - void __iomem *mmio = probe_ent->mmio_base; + void __iomem *mmio = probe_ent->iomap[NV_MMIO_BAR]; struct ata_ioports *ioport = &probe_ent->port[port]; VPRINTK("ENTER\n"); mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE; - ioport->cmd_addr = (unsigned long) mmio; - ioport->data_addr = (unsigned long) mmio + (ATA_REG_DATA * 4); + ioport->cmd_addr = mmio; + ioport->data_addr = mmio + (ATA_REG_DATA * 4); ioport->error_addr = - ioport->feature_addr = (unsigned long) mmio + (ATA_REG_ERR * 4); - ioport->nsect_addr = (unsigned long) mmio + (ATA_REG_NSECT * 4); - ioport->lbal_addr = (unsigned long) mmio + (ATA_REG_LBAL * 4); - ioport->lbam_addr = (unsigned long) mmio + (ATA_REG_LBAM * 4); - ioport->lbah_addr = (unsigned long) mmio + (ATA_REG_LBAH * 4); - ioport->device_addr = (unsigned long) mmio + (ATA_REG_DEVICE * 4); + ioport->feature_addr = mmio + (ATA_REG_ERR * 4); + ioport->nsect_addr = mmio + (ATA_REG_NSECT * 4); + ioport->lbal_addr = mmio + (ATA_REG_LBAL * 4); + ioport->lbam_addr = mmio + (ATA_REG_LBAM * 4); + ioport->lbah_addr = mmio + (ATA_REG_LBAH * 4); + ioport->device_addr = mmio + (ATA_REG_DEVICE * 4); ioport->status_addr = - ioport->command_addr = (unsigned long) mmio + (ATA_REG_STATUS * 4); + ioport->command_addr = mmio + (ATA_REG_STATUS * 4); ioport->altstatus_addr = - ioport->ctl_addr = (unsigned long) mmio + 0x20; + ioport->ctl_addr = mmio + 0x20; } static int nv_adma_host_init(struct ata_probe_ent *probe_ent) @@ -1252,7 +1254,7 @@ static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance) irqreturn_t ret; spin_lock(&host->lock); - irq_stat = inb(host->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); + irq_stat = ioread8(host->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); ret = nv_do_interrupt(host, irq_stat); spin_unlock(&host->lock); @@ -1266,7 +1268,7 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance) irqreturn_t ret; spin_lock(&host->lock); - irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804); + irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804); ret = nv_do_interrupt(host, irq_stat); spin_unlock(&host->lock); @@ -1278,7 +1280,7 @@ static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return ioread32((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); + return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); } static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) @@ -1286,36 +1288,36 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) if (sc_reg > SCR_CONTROL) return; - iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); + iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)); } static void nv_nf2_freeze(struct ata_port *ap) { - unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr; + void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr; int shift = ap->port_no * NV_INT_PORT_SHIFT; u8 mask; - mask = inb(scr_addr + NV_INT_ENABLE); + mask = ioread8(scr_addr + NV_INT_ENABLE); mask &= ~(NV_INT_ALL << shift); - outb(mask, scr_addr + NV_INT_ENABLE); + iowrite8(mask, scr_addr + NV_INT_ENABLE); } static void nv_nf2_thaw(struct ata_port *ap) { - unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr; + void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr; int shift = ap->port_no * NV_INT_PORT_SHIFT; u8 mask; - outb(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS); + iowrite8(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS); - mask = inb(scr_addr + NV_INT_ENABLE); + mask = ioread8(scr_addr + NV_INT_ENABLE); mask |= (NV_INT_MASK << shift); - outb(mask, scr_addr + NV_INT_ENABLE); + iowrite8(mask, scr_addr + NV_INT_ENABLE); } static void nv_ck804_freeze(struct ata_port *ap) { - void __iomem *mmio_base = ap->host->mmio_base; + void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR]; int shift = ap->port_no * NV_INT_PORT_SHIFT; u8 mask; @@ -1326,7 +1328,7 @@ static void nv_ck804_freeze(struct ata_port *ap) static void nv_ck804_thaw(struct ata_port *ap) { - void __iomem *mmio_base = ap->host->mmio_base; + void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR]; int shift = ap->port_no * NV_INT_PORT_SHIFT; u8 mask; @@ -1412,7 +1414,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) struct nv_host_priv *hpriv; int rc; u32 bar; - unsigned long base; + void __iomem *base; unsigned long type = ent->driver_data; int mask_set = 0; @@ -1464,15 +1466,14 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (!probe_ent) return -ENOMEM; - probe_ent->mmio_base = pcim_iomap(pdev, 5, 0); - if (!probe_ent->mmio_base) + if (!pcim_iomap(pdev, NV_MMIO_BAR, 0)) return -EIO; + probe_ent->iomap = pcim_iomap_table(pdev); probe_ent->private_data = hpriv; hpriv->type = type; - base = (unsigned long)probe_ent->mmio_base; - + base = probe_ent->iomap[NV_MMIO_BAR]; probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET; probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET; diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index e09c609d4961..4fb47cad8229 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -50,6 +50,8 @@ enum { + PDC_MMIO_BAR = 3, + /* register offsets */ PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */ PDC_SECTOR_COUNT = 0x08, /* Sector count reg (per port) */ @@ -167,7 +169,7 @@ static const struct ata_port_operations pdc_sata_ops = { .thaw = pdc_thaw, .error_handler = pdc_error_handler, .post_internal_cmd = pdc_post_internal_cmd, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, @@ -192,7 +194,7 @@ static const struct ata_port_operations pdc_old_sata_ops = { .thaw = pdc_thaw, .error_handler = pdc_error_handler, .post_internal_cmd = pdc_post_internal_cmd, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, @@ -214,7 +216,7 @@ static const struct ata_port_operations pdc_pata_ops = { .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, @@ -348,7 +350,7 @@ static int pdc_port_start(struct ata_port *ap) static void pdc_reset_port(struct ata_port *ap) { - void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT; + void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT; unsigned int i; u32 tmp; @@ -394,7 +396,7 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA) return 0xffffffffU; - return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -403,7 +405,7 @@ static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, { if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA) return; - writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); } static void pdc_atapi_pkt(struct ata_queued_cmd *qc) @@ -627,7 +629,7 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap, { unsigned int handled = 0; u32 tmp; - void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL; + void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL; tmp = readl(mmio); if (tmp & PDC_ERR_MASK) { @@ -656,7 +658,7 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap, static void pdc_irq_clear(struct ata_port *ap) { struct ata_host *host = ap->host; - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; readl(mmio + PDC_INT_SEQMASK); } @@ -672,12 +674,12 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance) VPRINTK("ENTER\n"); - if (!host || !host->mmio_base) { + if (!host || !host->iomap[PDC_MMIO_BAR]) { VPRINTK("QUICK EXIT\n"); return IRQ_NONE; } - mmio_base = host->mmio_base; + mmio_base = host->iomap[PDC_MMIO_BAR]; /* reading should also clear interrupts */ mask = readl(mmio_base + PDC_INT_SEQMASK); @@ -722,18 +724,19 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; + void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR]; unsigned int port_no = ap->port_no; u8 seq = (u8) (port_no + 1); VPRINTK("ENTER, ap %p\n", ap); - writel(0x00000001, ap->host->mmio_base + (seq * 4)); - readl(ap->host->mmio_base + (seq * 4)); /* flush */ + writel(0x00000001, mmio + (seq * 4)); + readl(mmio + (seq * 4)); /* flush */ pp->pkt[2] = seq; wmb(); /* flush PRD, pkt writes */ - writel(pp->pkt_dma, (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ + writel(pp->pkt_dma, ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ } static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc) @@ -808,7 +811,7 @@ static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc) return pdc_check_atapi_dma(qc); } -static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base) +static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base) { port->cmd_addr = base; port->data_addr = base; @@ -828,7 +831,7 @@ static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base) static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe) { - void __iomem *mmio = pe->mmio_base; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; struct pdc_host_priv *hp = pe->private_data; int hotplug_offset; u32 tmp; @@ -884,8 +887,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e static int printed_version; struct ata_probe_ent *probe_ent; struct pdc_host_priv *hp; - unsigned long base; - void __iomem *mmio_base; + void __iomem *base; unsigned int board_idx = (unsigned int) ent->driver_data; int rc; u8 tmp; @@ -897,11 +899,11 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { + rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME); + if (rc == -EBUSY) pcim_pin_device(pdev); + if (rc) return rc; - } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -917,11 +919,6 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pcim_iomap(pdev, 3, 0); - if (mmio_base == NULL) - return -ENOMEM; - base = (unsigned long) mmio_base; - hp = devm_kzalloc(&pdev->dev, sizeof(*hp), GFP_KERNEL); if (hp == NULL) return -ENOMEM; @@ -937,7 +934,9 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); + + base = probe_ent->iomap[PDC_MMIO_BAR]; pdc_ata_setup_port(&probe_ent->port[0], base + 0x200); pdc_ata_setup_port(&probe_ent->port[1], base + 0x280); @@ -964,7 +963,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e /* Fall through */ case board_2037x: /* TX2plus boards also have a PATA port */ - tmp = readb(mmio_base + PDC_FLASH_CTL+1); + tmp = readb(base + PDC_FLASH_CTL+1); if (!(tmp & 0x80)) { probe_ent->n_ports = 3; pdc_ata_setup_port(&probe_ent->port[2], base + 0x300); diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 339f61648af6..cd579b180274 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -43,6 +43,8 @@ #define DRV_VERSION "0.06" enum { + QS_MMIO_BAR = 4, + QS_PORTS = 4, QS_MAX_PRD = LIBATA_MAX_PRD, QS_CPB_ORDER = 6, @@ -155,7 +157,7 @@ static const struct ata_port_operations qs_ata_ops = { .phy_reset = qs_phy_reset, .qc_prep = qs_qc_prep, .qc_issue = qs_qc_issue, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .eng_timeout = qs_eng_timeout, .irq_handler = qs_intr, .irq_clear = qs_irq_clear, @@ -194,6 +196,11 @@ static struct pci_driver qs_ata_pci_driver = { .remove = ata_pci_remove_one, }; +static void __iomem *qs_mmio_base(struct ata_host *host) +{ + return host->iomap[QS_MMIO_BAR]; +} + static int qs_check_atapi_dma(struct ata_queued_cmd *qc) { return 1; /* ATAPI DMA not supported */ @@ -216,7 +223,7 @@ static void qs_irq_clear(struct ata_port *ap) static inline void qs_enter_reg_mode(struct ata_port *ap) { - u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000); + u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); readb(chan + QS_CCT_CTR0); /* flush */ @@ -224,7 +231,7 @@ static inline void qs_enter_reg_mode(struct ata_port *ap) static inline void qs_reset_channel_logic(struct ata_port *ap) { - u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000); + u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1); readb(chan + QS_CCT_CTR0); /* flush */ @@ -254,14 +261,14 @@ static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) return ~0U; - return readl((void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8))); + return readl(ap->ioaddr.scr_addr + (sc_reg * 8)); } static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) return; - writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8))); + writel(val, ap->ioaddr.scr_addr + (sc_reg * 8)); } static unsigned int qs_fill_sg(struct ata_queued_cmd *qc) @@ -338,7 +345,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc) static inline void qs_packet_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000); + u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); VPRINTK("ENTER, ap %p\n", ap); @@ -375,7 +382,7 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host) { unsigned int handled = 0; u8 sFFE; - u8 __iomem *mmio_base = host->mmio_base; + u8 __iomem *mmio_base = qs_mmio_base(host); do { u32 sff0 = readl(mmio_base + QS_HST_SFF); @@ -467,7 +474,7 @@ static irqreturn_t qs_intr(int irq, void *dev_instance) return IRQ_RETVAL(handled); } -static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base) +static void qs_ata_setup_port(struct ata_ioports *port, void __iomem *base) { port->cmd_addr = port->data_addr = base + 0x400; @@ -489,7 +496,7 @@ static int qs_port_start(struct ata_port *ap) { struct device *dev = ap->host->dev; struct qs_port_priv *pp; - void __iomem *mmio_base = ap->host->mmio_base; + void __iomem *mmio_base = qs_mmio_base(ap->host); void __iomem *chan = mmio_base + (ap->port_no * 0x4000); u64 addr; int rc; @@ -516,7 +523,7 @@ static int qs_port_start(struct ata_port *ap) static void qs_host_stop(struct ata_host *host) { - void __iomem *mmio_base = host->mmio_base; + void __iomem *mmio_base = qs_mmio_base(host); writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ @@ -524,7 +531,7 @@ static void qs_host_stop(struct ata_host *host) static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe) { - void __iomem *mmio_base = pe->mmio_base; + void __iomem *mmio_base = pe->iomap[QS_MMIO_BAR]; unsigned int port_no; writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ @@ -599,8 +606,8 @@ static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_probe_ent *probe_ent = NULL; - void __iomem *mmio_base; + struct ata_probe_ent *probe_ent; + void __iomem * const *iomap; unsigned int board_idx = (unsigned int) ent->driver_data; int rc, port_no; @@ -611,18 +618,15 @@ static int qs_ata_init_one(struct pci_dev *pdev, if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) - return rc; - - if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) + if ((pci_resource_flags(pdev, QS_MMIO_BAR) & IORESOURCE_MEM) == 0) return -ENODEV; - mmio_base = pcim_iomap(pdev, 4, 0); - if (mmio_base == NULL) - return -ENOMEM; + rc = pcim_iomap_regions(pdev, 1 << QS_MMIO_BAR, DRV_NAME); + if (rc) + return rc; + iomap = pcim_iomap_table(pdev); - rc = qs_set_dma_masks(pdev, mmio_base); + rc = qs_set_dma_masks(pdev, iomap[QS_MMIO_BAR]); if (rc) return rc; @@ -642,12 +646,12 @@ static int qs_ata_init_one(struct pci_dev *pdev, probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = iomap; probe_ent->n_ports = QS_PORTS; for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) { - unsigned long chan = (unsigned long)mmio_base + - (port_no * 0x4000); + void __iomem *chan = + probe_ent->iomap[QS_MMIO_BAR] + (port_no * 0x4000); qs_ata_setup_port(&probe_ent->port[port_no], chan); } diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 00f2465dcdce..4a25093b2dda 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -49,6 +49,8 @@ #define DRV_VERSION "2.0" enum { + SIL_MMIO_BAR = 5, + /* * host flags */ @@ -200,7 +202,7 @@ static const struct ata_port_operations sil_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = sil_freeze, .thaw = sil_thaw, .error_handler = ata_bmdma_error_handler, @@ -295,7 +297,8 @@ static void sil_post_set_mode (struct ata_port *ap) { struct ata_host *host = ap->host; struct ata_device *dev; - void __iomem *addr = host->mmio_base + sil_port[ap->port_no].xfer_mode; + 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; @@ -318,9 +321,9 @@ static void sil_post_set_mode (struct ata_port *ap) readl(addr); /* flush */ } -static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_reg) +static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_reg) { - unsigned long offset = ap->ioaddr.scr_addr; + void __iomem *offset = ap->ioaddr.scr_addr; switch (sc_reg) { case SCR_STATUS: @@ -339,7 +342,7 @@ static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_re static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg) { - void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); + void __iomem *mmio = sil_scr_addr(ap, sc_reg); if (mmio) return readl(mmio); return 0xffffffffU; @@ -347,7 +350,7 @@ static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg) static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { - void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); + void __iomem *mmio = sil_scr_addr(ap, sc_reg); if (mmio) writel(val, mmio); } @@ -442,7 +445,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) static irqreturn_t sil_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; - void __iomem *mmio_base = host->mmio_base; + void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR]; int handled = 0; int i; @@ -474,7 +477,7 @@ static irqreturn_t sil_interrupt(int irq, void *dev_instance) static void sil_freeze(struct ata_port *ap) { - void __iomem *mmio_base = ap->host->mmio_base; + void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR]; u32 tmp; /* global IRQ mask doesn't block SATA IRQ, turn off explicitly */ @@ -489,7 +492,7 @@ static void sil_freeze(struct ata_port *ap) static void sil_thaw(struct ata_port *ap) { - void __iomem *mmio_base = ap->host->mmio_base; + void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR]; u32 tmp; /* clear IRQ */ @@ -621,7 +624,6 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) static int printed_version; struct device *dev = &pdev->dev; struct ata_probe_ent *probe_ent; - unsigned long base; void __iomem *mmio_base; int rc; unsigned int i; @@ -633,11 +635,11 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { + rc = pcim_iomap_regions(pdev, 1 << SIL_MMIO_BAR, DRV_NAME); + if (rc == -EBUSY) pcim_pin_device(pdev); + if (rc) return rc; - } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -662,20 +664,16 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->irq_flags = IRQF_SHARED; probe_ent->port_flags = sil_port_info[ent->driver_data].flags; - mmio_base = pcim_iomap(pdev, 5, 0); - if (mmio_base == NULL) - return -ENOMEM; - - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); - base = (unsigned long) mmio_base; + mmio_base = probe_ent->iomap[SIL_MMIO_BAR]; for (i = 0; i < probe_ent->n_ports; i++) { - probe_ent->port[i].cmd_addr = base + sil_port[i].tf; + probe_ent->port[i].cmd_addr = mmio_base + sil_port[i].tf; probe_ent->port[i].altstatus_addr = - probe_ent->port[i].ctl_addr = base + sil_port[i].ctl; - probe_ent->port[i].bmdma_addr = base + sil_port[i].bmdma; - probe_ent->port[i].scr_addr = base + sil_port[i].scr; + probe_ent->port[i].ctl_addr = mmio_base + sil_port[i].ctl; + probe_ent->port[i].bmdma_addr = mmio_base + sil_port[i].bmdma; + probe_ent->port[i].scr_addr = mmio_base + sil_port[i].scr; ata_std_ports(&probe_ent->port[i]); } @@ -702,7 +700,7 @@ static int sil_pci_device_resume(struct pci_dev *pdev) return rc; sil_init_controller(pdev, host->n_ports, host->ports[0]->flags, - host->mmio_base); + host->iomap[SIL_MMIO_BAR]); ata_host_resume(host); return 0; diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index c7a3c0275bee..9dcf11e2c7b3 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -60,6 +60,9 @@ struct sil24_port_multiplier { }; enum { + SIL24_HOST_BAR = 0, + SIL24_PORT_BAR = 2, + /* * Global controller registers (128 bytes @ BAR0) */ @@ -320,12 +323,6 @@ struct sil24_port_priv { struct ata_taskfile tf; /* Cached taskfile registers */ }; -/* ap->host->private_data */ -struct sil24_host_priv { - void __iomem *host_base; /* global controller control (128 bytes @BAR0) */ - void __iomem *port_base; /* port registers (4 * 8192 bytes @BAR2) */ -}; - static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev); static u8 sil24_check_status(struct ata_port *ap); static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg); @@ -462,7 +459,7 @@ static int sil24_tag(int tag) static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; if (dev->cdb_len == 16) writel(PORT_CS_CDB16, port + PORT_CTRL_STAT); @@ -473,7 +470,7 @@ static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev) static inline void sil24_update_tf(struct ata_port *ap) { struct sil24_port_priv *pp = ap->private_data; - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; struct sil24_prb __iomem *prb = port; u8 fis[6 * 4]; @@ -496,7 +493,7 @@ static int sil24_scr_map[] = { static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg) { - void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr; + void __iomem *scr_addr = ap->ioaddr.scr_addr; if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { void __iomem *addr; addr = scr_addr + sil24_scr_map[sc_reg] * 4; @@ -507,7 +504,7 @@ static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg) static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) { - void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr; + void __iomem *scr_addr = ap->ioaddr.scr_addr; if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { void __iomem *addr; addr = scr_addr + sil24_scr_map[sc_reg] * 4; @@ -523,7 +520,7 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf) static int sil24_init_port(struct ata_port *ap) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; u32 tmp; writel(PORT_CS_INIT, port + PORT_CTRL_STAT); @@ -539,7 +536,7 @@ static int sil24_init_port(struct ata_port *ap) static int sil24_softreset(struct ata_port *ap, unsigned int *class) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; struct sil24_port_priv *pp = ap->private_data; struct sil24_prb *prb = &pp->cmd_block[0].ata.prb; dma_addr_t paddr = pp->cmd_block_dma; @@ -599,7 +596,7 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) static int sil24_hardreset(struct ata_port *ap, unsigned int *class) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; const char *reason; int tout_msec, rc; u32 tmp; @@ -716,7 +713,7 @@ static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct sil24_port_priv *pp = ap->private_data; - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; unsigned int tag = sil24_tag(qc->tag); dma_addr_t paddr; void __iomem *activate; @@ -737,7 +734,7 @@ static void sil24_irq_clear(struct ata_port *ap) static void sil24_freeze(struct ata_port *ap) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; /* Port-wide IRQ mask in HOST_CTRL doesn't really work, clear * PORT_IRQ_ENABLE instead. @@ -747,7 +744,7 @@ static void sil24_freeze(struct ata_port *ap) static void sil24_thaw(struct ata_port *ap) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; u32 tmp; /* clear IRQ */ @@ -760,7 +757,7 @@ static void sil24_thaw(struct ata_port *ap) static void sil24_error_intr(struct ata_port *ap) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; struct ata_eh_info *ehi = &ap->eh_info; int freeze = 0; u32 irq_stat; @@ -838,7 +835,7 @@ static void sil24_finish_qc(struct ata_queued_cmd *qc) static inline void sil24_host_intr(struct ata_port *ap) { - void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + void __iomem *port = ap->ioaddr.cmd_addr; u32 slot_stat, qc_active; int rc; @@ -873,12 +870,12 @@ static inline void sil24_host_intr(struct ata_port *ap) static irqreturn_t sil24_interrupt(int irq, void *dev_instance) { struct ata_host *host = dev_instance; - struct sil24_host_priv *hpriv = host->private_data; + void __iomem *host_base = host->iomap[SIL24_HOST_BAR]; unsigned handled = 0; u32 status; int i; - status = readl(hpriv->host_base + HOST_IRQ_STAT); + status = readl(host_base + HOST_IRQ_STAT); if (status == 0xffffffff) { printk(KERN_ERR DRV_NAME ": IRQ status == 0xffffffff, " @@ -1031,7 +1028,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) unsigned int board_id = (unsigned int)ent->driver_data; struct ata_port_info *pinfo = &sil24_port_info[board_id]; struct ata_probe_ent *probe_ent; - struct sil24_host_priv *hpriv; void __iomem *host_base; void __iomem *port_base; int i, rc; @@ -1044,20 +1040,15 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); + rc = pcim_iomap_regions(pdev, + (1 << SIL24_HOST_BAR) | (1 << SIL24_PORT_BAR), + DRV_NAME); if (rc) return rc; - /* map mmio registers */ - host_base = pcim_iomap(pdev, 0, 0); - port_base = pcim_iomap(pdev, 2, 0); - if (!host_base || !port_base) - return -ENOMEM; - - /* allocate & init probe_ent and hpriv */ + /* allocate & init probe_ent */ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); - hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); - if (!probe_ent || !hpriv) + if (!probe_ent) return -ENOMEM; probe_ent->dev = pci_dev_to_dev(pdev); @@ -1073,10 +1064,10 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->private_data = hpriv; + probe_ent->iomap = pcim_iomap_table(pdev); - hpriv->host_base = host_base; - hpriv->port_base = port_base; + host_base = probe_ent->iomap[SIL24_HOST_BAR]; + port_base = probe_ent->iomap[SIL24_PORT_BAR]; /* * Configure the device @@ -1118,11 +1109,10 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } for (i = 0; i < probe_ent->n_ports; i++) { - unsigned long portu = - (unsigned long)port_base + i * PORT_REGS_SIZE; + void __iomem *port = port_base + i * PORT_REGS_SIZE; - probe_ent->port[i].cmd_addr = portu; - probe_ent->port[i].scr_addr = portu + PORT_SCONTROL; + probe_ent->port[i].cmd_addr = port; + probe_ent->port[i].scr_addr = port + PORT_SCONTROL; ata_std_ports(&probe_ent->port[i]); } @@ -1143,7 +1133,8 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) static int sil24_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); - struct sil24_host_priv *hpriv = host->private_data; + void __iomem *host_base = host->iomap[SIL24_HOST_BAR]; + void __iomem *port_base = host->iomap[SIL24_PORT_BAR]; int rc; rc = ata_pci_device_do_resume(pdev); @@ -1151,10 +1142,10 @@ static int sil24_pci_device_resume(struct pci_dev *pdev) return rc; if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) - writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL); + writel(HOST_CTRL_GLOBAL_RST, host_base + HOST_CTRL); sil24_init_controller(pdev, host->n_ports, host->ports[0]->flags, - hpriv->host_base, hpriv->port_base); + host_base, port_base); ata_host_resume(host); diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 4bcb94866333..eee2097c10c0 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -117,7 +117,7 @@ static const struct ata_port_operations sis_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, @@ -223,11 +223,11 @@ static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg) pci_read_config_byte(pdev, SIS_PMR, &pmr); - val = inl(ap->ioaddr.scr_addr + (sc_reg * 4)); + val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) || (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED)) - val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10); + val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10); return (val | val2) & 0xfffffffb; } @@ -245,10 +245,10 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) if (ap->flags & SIS_FLAG_CFGSCR) sis_scr_cfg_write(ap, sc_reg, val); else { - outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); + iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)); if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) || (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED)) - outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10); + iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10); } } @@ -353,10 +353,14 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) return -ENOMEM; if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) { - probe_ent->port[0].scr_addr = - pci_resource_start(pdev, SIS_SCR_PCI_BAR); - probe_ent->port[1].scr_addr = - pci_resource_start(pdev, SIS_SCR_PCI_BAR) + port2_start; + void *mmio; + + mmio = pcim_iomap(pdev, SIS_SCR_PCI_BAR, 0); + if (!mmio) + return -ENOMEM; + + probe_ent->port[0].scr_addr = mmio; + probe_ent->port[1].scr_addr = mmio + port2_start; } pci_set_master(pdev); diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 9c48b418ad7f..5ce4f593687d 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -135,31 +135,31 @@ static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; if (tf->ctl != ap->last_ctl) { - writeb(tf->ctl, (void __iomem *) ioaddr->ctl_addr); + writeb(tf->ctl, ioaddr->ctl_addr); ap->last_ctl = tf->ctl; ata_wait_idle(ap); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { writew(tf->feature | (((u16)tf->hob_feature) << 8), - (void __iomem *) ioaddr->feature_addr); + ioaddr->feature_addr); writew(tf->nsect | (((u16)tf->hob_nsect) << 8), - (void __iomem *) ioaddr->nsect_addr); + ioaddr->nsect_addr); writew(tf->lbal | (((u16)tf->hob_lbal) << 8), - (void __iomem *) ioaddr->lbal_addr); + ioaddr->lbal_addr); writew(tf->lbam | (((u16)tf->hob_lbam) << 8), - (void __iomem *) ioaddr->lbam_addr); + ioaddr->lbam_addr); writew(tf->lbah | (((u16)tf->hob_lbah) << 8), - (void __iomem *) ioaddr->lbah_addr); + ioaddr->lbah_addr); } else if (is_addr) { - writew(tf->feature, (void __iomem *) ioaddr->feature_addr); - writew(tf->nsect, (void __iomem *) ioaddr->nsect_addr); - writew(tf->lbal, (void __iomem *) ioaddr->lbal_addr); - writew(tf->lbam, (void __iomem *) ioaddr->lbam_addr); - writew(tf->lbah, (void __iomem *) ioaddr->lbah_addr); + writew(tf->feature, ioaddr->feature_addr); + writew(tf->nsect, ioaddr->nsect_addr); + writew(tf->lbal, ioaddr->lbal_addr); + writew(tf->lbam, ioaddr->lbam_addr); + writew(tf->lbah, ioaddr->lbah_addr); } if (tf->flags & ATA_TFLAG_DEVICE) - writeb(tf->device, (void __iomem *) ioaddr->device_addr); + writeb(tf->device, ioaddr->device_addr); ata_wait_idle(ap); } @@ -171,12 +171,12 @@ static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) u16 nsect, lbal, lbam, lbah, feature; tf->command = k2_stat_check_status(ap); - tf->device = readw((void __iomem *)ioaddr->device_addr); - feature = readw((void __iomem *)ioaddr->error_addr); - nsect = readw((void __iomem *)ioaddr->nsect_addr); - lbal = readw((void __iomem *)ioaddr->lbal_addr); - lbam = readw((void __iomem *)ioaddr->lbam_addr); - lbah = readw((void __iomem *)ioaddr->lbah_addr); + tf->device = readw(ioaddr->device_addr); + feature = readw(ioaddr->error_addr); + nsect = readw(ioaddr->nsect_addr); + lbal = readw(ioaddr->lbal_addr); + lbam = readw(ioaddr->lbam_addr); + lbah = readw(ioaddr->lbah_addr); tf->feature = feature; tf->nsect = nsect; @@ -349,7 +349,7 @@ static const struct ata_port_operations k2_sata_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, @@ -361,7 +361,7 @@ static const struct ata_port_operations k2_sata_ops = { .port_start = ata_port_start, }; -static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base) +static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base) { port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET; port->data_addr = base + K2_SATA_TF_DATA_OFFSET; @@ -386,7 +386,6 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e static int printed_version; struct device *dev = &pdev->dev; struct ata_probe_ent *probe_ent; - unsigned long base; void __iomem *mmio_base; const struct k2_board_info *board_info = &k2_board_info[ent->driver_data]; @@ -410,12 +409,12 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e if (pci_resource_len(pdev, 5) == 0) return -ENODEV; - /* Request PCI regions */ - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { + /* Request and iomap PCI regions */ + rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME); + if (rc == -EBUSY) pcim_pin_device(pdev); + if (rc) return rc; - } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -431,22 +430,6 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pcim_iomap(pdev, 5, 0); - if (mmio_base == NULL) - return -ENOMEM; - base = (unsigned long) mmio_base; - - /* Clear a magic bit in SCR1 according to Darwin, those help - * some funky seagate drives (though so far, those were already - * set by the firmware on the machines I had access to) - */ - writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000, - mmio_base + K2_SATA_SICR1_OFFSET); - - /* Clear SATA error & interrupts we don't use */ - writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET); - writel(0x0, mmio_base + K2_SATA_SIM_OFFSET); - probe_ent->sht = &k2_sata_sht; probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | board_info->port_flags; @@ -454,7 +437,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e probe_ent->n_ports = 4; probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); /* We don't care much about the PIO/UDMA masks, but the core won't like us * if we don't fill these @@ -463,11 +446,25 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e probe_ent->mwdma_mask = 0x7; probe_ent->udma_mask = 0x7f; + mmio_base = probe_ent->iomap[5]; + /* 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 < board_info->n_ports; i++) - k2_sata_setup_port(&probe_ent->port[i], base + i * K2_SATA_PORT_OFFSET); + k2_sata_setup_port(&probe_ent->port[i], + mmio_base + i * K2_SATA_PORT_OFFSET); + + /* Clear a magic bit in SCR1 according to Darwin, those help + * some funky seagate drives (though so far, those were already + * set by the firmware on the machines I had access to) + */ + writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000, + mmio_base + K2_SATA_SICR1_OFFSET); + + /* Clear SATA error & interrupts we don't use */ + writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET); + writel(0x0, mmio_base + K2_SATA_SIM_OFFSET); pci_set_master(pdev); diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index d9838dcb4b01..f83038cf1b35 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -49,6 +49,9 @@ enum { + PDC_MMIO_BAR = 3, + PDC_DIMM_BAR = 4, + PDC_PRD_TBL = 0x44, /* Direct command DMA table addr */ PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */ @@ -137,8 +140,6 @@ struct pdc_port_priv { }; struct pdc_host_priv { - void __iomem *dimm_mmio; - unsigned int doing_hdma; unsigned int hdma_prod; unsigned int hdma_cons; @@ -202,7 +203,7 @@ static const struct ata_port_operations pdc_20621_ops = { .phy_reset = pdc_20621_phy_reset, .qc_prep = pdc20621_qc_prep, .qc_issue = pdc20621_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc20621_interrupt, .irq_clear = pdc20621_irq_clear, @@ -411,9 +412,8 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc) struct scatterlist *sg; struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; - void __iomem *mmio = ap->host->mmio_base; - struct pdc_host_priv *hpriv = ap->host->private_data; - void __iomem *dimm_mmio = hpriv->dimm_mmio; + void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR]; + void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR]; unsigned int portno = ap->port_no; unsigned int i, idx, total_len = 0, sgt_len; u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ]; @@ -472,9 +472,8 @@ static void pdc20621_nodata_prep(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; - void __iomem *mmio = ap->host->mmio_base; - struct pdc_host_priv *hpriv = ap->host->private_data; - void __iomem *dimm_mmio = hpriv->dimm_mmio; + void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR]; + void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR]; unsigned int portno = ap->port_no; unsigned int i; @@ -524,7 +523,7 @@ static void __pdc20621_push_hdma(struct ata_queued_cmd *qc, { struct ata_port *ap = qc->ap; struct ata_host *host = ap->host; - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -578,8 +577,7 @@ static void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; unsigned int port_no = ap->port_no; - struct pdc_host_priv *hpriv = ap->host->private_data; - void *dimm_mmio = hpriv->dimm_mmio; + void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR]; dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP); dimm_mmio += PDC_DIMM_HOST_PKT; @@ -598,7 +596,7 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; struct ata_host *host = ap->host; unsigned int port_no = ap->port_no; - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 seq = (u8) (port_no + 1); unsigned int port_ofs; @@ -627,8 +625,8 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc) readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */ writel(port_ofs + PDC_DIMM_ATA_PKT, - (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); VPRINTK("submitted ofs 0x%x (%u), seq %u\n", port_ofs + PDC_DIMM_ATA_PKT, port_ofs + PDC_DIMM_ATA_PKT, @@ -706,8 +704,8 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); readl(mmio + PDC_20621_SEQCTL + (seq * 4)); writel(port_ofs + PDC_DIMM_ATA_PKT, - (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); } /* step two - execute ATA command */ @@ -740,7 +738,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, static void pdc20621_irq_clear(struct ata_port *ap) { struct ata_host *host = ap->host; - void __iomem *mmio = host->mmio_base; + void __iomem *mmio = host->iomap[PDC_MMIO_BAR]; mmio += PDC_CHIP0_OFS; @@ -758,12 +756,12 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance) VPRINTK("ENTER\n"); - if (!host || !host->mmio_base) { + if (!host || !host->iomap[PDC_MMIO_BAR]) { VPRINTK("QUICK EXIT\n"); return IRQ_NONE; } - mmio_base = host->mmio_base; + mmio_base = host->iomap[PDC_MMIO_BAR]; /* reading should also clear interrupts */ mmio_base += PDC_CHIP0_OFS; @@ -864,7 +862,7 @@ static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile } -static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base) +static void pdc_sata_setup_port(struct ata_ioports *port, void __iomem *base) { port->cmd_addr = base; port->data_addr = base; @@ -890,9 +888,8 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, u16 idx; u8 page_mask; long dist; - void __iomem *mmio = pe->mmio_base; - struct pdc_host_priv *hpriv = pe->private_data; - void __iomem *dimm_mmio = hpriv->dimm_mmio; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; + void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -946,9 +943,8 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, u16 idx; u8 page_mask; long dist; - void __iomem *mmio = pe->mmio_base; - struct pdc_host_priv *hpriv = pe->private_data; - void __iomem *dimm_mmio = hpriv->dimm_mmio; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; + void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -993,7 +989,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, u32 subaddr, u32 *pdata) { - void __iomem *mmio = pe->mmio_base; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; u32 i2creg = 0; u32 status; u32 count =0; @@ -1052,7 +1048,7 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe) u32 data = 0; int size, i; u8 bdimmsize; - void __iomem *mmio = pe->mmio_base; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; static const struct { unsigned int reg; unsigned int ofs; @@ -1114,8 +1110,8 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe) static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe) { u32 data, spd0; - int error, i; - void __iomem *mmio = pe->mmio_base; + int error, i; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -1169,7 +1165,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe) u32 ticks=0; u32 clock=0; u32 fparam=0; - void __iomem *mmio = pe->mmio_base; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -1293,7 +1289,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe) static void pdc_20621_init(struct ata_probe_ent *pe) { u32 tmp; - void __iomem *mmio = pe->mmio_base; + void __iomem *mmio = pe->iomap[PDC_MMIO_BAR]; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -1325,9 +1321,7 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * { static int printed_version; struct ata_probe_ent *probe_ent; - unsigned long base; - void __iomem *mmio_base; - void __iomem *dimm_mmio; + void __iomem *base; struct pdc_host_priv *hpriv; unsigned int board_idx = (unsigned int) ent->driver_data; int rc; @@ -1339,11 +1333,12 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { + rc = pcim_iomap_regions(pdev, (1 << PDC_MMIO_BAR) | (1 << PDC_DIMM_BAR), + DRV_NAME); + if (rc == -EBUSY) pcim_pin_device(pdev); + if (rc) return rc; - } rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) @@ -1359,21 +1354,10 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pcim_iomap(pdev, 3, 0); - if (mmio_base == NULL) - return -ENOMEM; - base = (unsigned long) mmio_base; - hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; - dimm_mmio = pcim_iomap(pdev, 4, 0); - if (!dimm_mmio) - return -ENOMEM; - - hpriv->dimm_mmio = dimm_mmio; - probe_ent->sht = pdc_port_info[board_idx].sht; probe_ent->port_flags = pdc_port_info[board_idx].flags; probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask; @@ -1383,10 +1367,10 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id * probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); probe_ent->private_data = hpriv; - base += PDC_CHIP0_OFS; + base = probe_ent->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS; probe_ent->n_ports = 4; pdc_sata_setup_port(&probe_ent->port[0], base + 0x200); diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index 22eed6d07495..77de7cbbe1ae 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -108,7 +108,7 @@ static const struct ata_port_operations uli_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -188,6 +188,7 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) int rc; unsigned int board_idx = (unsigned int) ent->driver_data; struct uli_priv *hpriv; + void __iomem * const *iomap; if (!printed_version++) dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); @@ -220,24 +221,26 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->private_data = hpriv; + iomap = pcim_iomap_table(pdev); + switch (board_idx) { case uli_5287: hpriv->scr_cfg_addr[0] = ULI5287_BASE; hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS; probe_ent->n_ports = 4; - probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8; + probe_ent->port[2].cmd_addr = iomap[0] + 8; probe_ent->port[2].altstatus_addr = - probe_ent->port[2].ctl_addr = - (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4; - probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16; + probe_ent->port[2].ctl_addr = (void __iomem *) + ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS) + 4; + probe_ent->port[2].bmdma_addr = iomap[4] + 16; hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4; - probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8; + probe_ent->port[3].cmd_addr = iomap[2] + 8; probe_ent->port[3].altstatus_addr = - probe_ent->port[3].ctl_addr = - (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4; - probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24; + probe_ent->port[3].ctl_addr = (void __iomem *) + ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS) + 4; + probe_ent->port[3].bmdma_addr = iomap[4] + 24; hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5; ata_std_ports(&probe_ent->port[2]); diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index c7f527578d11..6b558195a76f 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -134,7 +134,7 @@ static const struct ata_port_operations vt6420_sata_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = svia_noop_freeze, .thaw = ata_bmdma_thaw, @@ -166,7 +166,7 @@ static const struct ata_port_operations vt6421_pata_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -195,7 +195,7 @@ static const struct ata_port_operations vt6421_sata_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, @@ -230,14 +230,14 @@ static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return inl(ap->ioaddr.scr_addr + (4 * sc_reg)); + return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg)); } static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { if (sc_reg > SCR_CONTROL) return; - outl(val, ap->ioaddr.scr_addr + (4 * sc_reg)); + iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg)); } static void svia_noop_freeze(struct ata_port *ap) @@ -387,31 +387,28 @@ static const unsigned int vt6421_bar_sizes[] = { 16, 16, 16, 16, 32, 128 }; -static unsigned long svia_scr_addr(unsigned long addr, unsigned int port) +static void __iomem * svia_scr_addr(void __iomem *addr, unsigned int port) { return addr + (port * 128); } -static unsigned long vt6421_scr_addr(unsigned long addr, unsigned int port) +static void __iomem * vt6421_scr_addr(void __iomem *addr, unsigned int port) { return addr + (port * 64); } static void vt6421_init_addrs(struct ata_probe_ent *probe_ent, - struct pci_dev *pdev, - unsigned int port) + void __iomem * const *iomap, unsigned int port) { - unsigned long reg_addr = pci_resource_start(pdev, port); - unsigned long bmdma_addr = pci_resource_start(pdev, 4) + (port * 8); - unsigned long scr_addr; + void __iomem *reg_addr = iomap[port]; + void __iomem *bmdma_addr = iomap[4] + (port * 8); probe_ent->port[port].cmd_addr = reg_addr; probe_ent->port[port].altstatus_addr = - probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS; + probe_ent->port[port].ctl_addr = (void __iomem *) + ((unsigned long)(reg_addr + 8) | ATA_PCI_CTL_OFS); probe_ent->port[port].bmdma_addr = bmdma_addr; - - scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port); - probe_ent->port[port].scr_addr = scr_addr; + probe_ent->port[port].scr_addr = vt6421_scr_addr(iomap[5], port); ata_std_ports(&probe_ent->port[port]); } @@ -420,16 +417,16 @@ static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev) { struct ata_probe_ent *probe_ent; struct ata_port_info *ppi[2]; + void __iomem * const *iomap; ppi[0] = ppi[1] = &vt6420_port_info; probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) return NULL; - probe_ent->port[0].scr_addr = - svia_scr_addr(pci_resource_start(pdev, 5), 0); - probe_ent->port[1].scr_addr = - svia_scr_addr(pci_resource_start(pdev, 5), 1); + iomap = pcim_iomap_table(pdev); + probe_ent->port[0].scr_addr = svia_scr_addr(iomap[5], 0); + probe_ent->port[1].scr_addr = svia_scr_addr(iomap[5], 1); return probe_ent; } @@ -458,7 +455,7 @@ static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev) probe_ent->udma_mask = 0x7f; for (i = 0; i < N_PORTS; i++) - vt6421_init_addrs(probe_ent, pdev, i); + vt6421_init_addrs(probe_ent, pcim_iomap_table(pdev), i); return probe_ent; } @@ -519,7 +516,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - rc = pci_request_regions(pdev, DRV_NAME); + rc = pcim_iomap_regions(pdev, 0x1f, DRV_NAME); if (rc) { pcim_pin_device(pdev); return rc; diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index af77f71bdaa5..7596e9ace50b 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -50,6 +50,8 @@ #define DRV_VERSION "2.0" enum { + VSC_MMIO_BAR = 0, + /* Interrupt register offsets (from chip base address) */ VSC_SATA_INT_STAT_OFFSET = 0x00, VSC_SATA_INT_MASK_OFFSET = 0x04, @@ -104,7 +106,7 @@ static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl(ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -113,7 +115,7 @@ static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, { if (sc_reg > SCR_CONTROL) return; - writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -122,7 +124,7 @@ static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) void __iomem *mask_addr; u8 mask; - mask_addr = ap->host->mmio_base + + mask_addr = ap->host->iomap[VSC_MMIO_BAR] + VSC_SATA_INT_MASK_OFFSET + ap->port_no; mask = readb(mask_addr); if (ctl & ATA_NIEN) @@ -149,25 +151,25 @@ static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { writew(tf->feature | (((u16)tf->hob_feature) << 8), - (void __iomem *) ioaddr->feature_addr); + ioaddr->feature_addr); writew(tf->nsect | (((u16)tf->hob_nsect) << 8), - (void __iomem *) ioaddr->nsect_addr); + ioaddr->nsect_addr); writew(tf->lbal | (((u16)tf->hob_lbal) << 8), - (void __iomem *) ioaddr->lbal_addr); + ioaddr->lbal_addr); writew(tf->lbam | (((u16)tf->hob_lbam) << 8), - (void __iomem *) ioaddr->lbam_addr); + ioaddr->lbam_addr); writew(tf->lbah | (((u16)tf->hob_lbah) << 8), - (void __iomem *) ioaddr->lbah_addr); + ioaddr->lbah_addr); } else if (is_addr) { - writew(tf->feature, (void __iomem *) ioaddr->feature_addr); - writew(tf->nsect, (void __iomem *) ioaddr->nsect_addr); - writew(tf->lbal, (void __iomem *) ioaddr->lbal_addr); - writew(tf->lbam, (void __iomem *) ioaddr->lbam_addr); - writew(tf->lbah, (void __iomem *) ioaddr->lbah_addr); + writew(tf->feature, ioaddr->feature_addr); + writew(tf->nsect, ioaddr->nsect_addr); + writew(tf->lbal, ioaddr->lbal_addr); + writew(tf->lbam, ioaddr->lbam_addr); + writew(tf->lbah, ioaddr->lbah_addr); } if (tf->flags & ATA_TFLAG_DEVICE) - writeb(tf->device, (void __iomem *) ioaddr->device_addr); + writeb(tf->device, ioaddr->device_addr); ata_wait_idle(ap); } @@ -179,12 +181,12 @@ static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) u16 nsect, lbal, lbam, lbah, feature; tf->command = ata_check_status(ap); - tf->device = readw((void __iomem *) ioaddr->device_addr); - feature = readw((void __iomem *) ioaddr->error_addr); - nsect = readw((void __iomem *) ioaddr->nsect_addr); - lbal = readw((void __iomem *) ioaddr->lbal_addr); - lbam = readw((void __iomem *) ioaddr->lbam_addr); - lbah = readw((void __iomem *) ioaddr->lbah_addr); + tf->device = readw(ioaddr->device_addr); + feature = readw(ioaddr->error_addr); + nsect = readw(ioaddr->nsect_addr); + lbal = readw(ioaddr->lbal_addr); + lbam = readw(ioaddr->lbam_addr); + lbah = readw(ioaddr->lbah_addr); tf->feature = feature; tf->nsect = nsect; @@ -216,7 +218,8 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance) spin_lock(&host->lock); - int_status = readl(host->mmio_base + VSC_SATA_INT_STAT_OFFSET); + int_status = readl(host->iomap[VSC_MMIO_BAR] + + VSC_SATA_INT_STAT_OFFSET); for (i = 0; i < host->n_ports; i++) { if (int_status & ((u32) 0xFF << (8 * i))) { @@ -300,7 +303,7 @@ static const struct ata_port_operations vsc_sata_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_mmio_data_xfer, + .data_xfer = ata_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, @@ -312,7 +315,8 @@ static const struct ata_port_operations vsc_sata_ops = { .port_start = ata_port_start, }; -static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base) +static void __devinit vsc_sata_setup_port(struct ata_ioports *port, + void __iomem *base) { port->cmd_addr = base + VSC_SATA_TF_CMD_OFFSET; port->data_addr = base + VSC_SATA_TF_DATA_OFFSET; @@ -329,16 +333,15 @@ static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned lon port->ctl_addr = base + VSC_SATA_TF_CTL_OFFSET; port->bmdma_addr = base + VSC_SATA_DMA_CMD_OFFSET; port->scr_addr = base + VSC_SATA_SCR_STATUS_OFFSET; - writel(0, (void __iomem *) base + VSC_SATA_UP_DESCRIPTOR_OFFSET); - writel(0, (void __iomem *) base + VSC_SATA_UP_DATA_BUFFER_OFFSET); + writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET); + writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET); } static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_probe_ent *probe_ent = NULL; - unsigned long base; + struct ata_probe_ent *probe_ent; void __iomem *mmio_base; int rc; @@ -355,11 +358,11 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d if (pci_resource_len(pdev, 0) == 0) return -ENODEV; - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) { + rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME); + if (rc == -EBUSY) pcim_pin_device(pdev); + if (rc) return rc; - } /* * Use 32 bit DMA mask, because 64 bit address support is poor. @@ -377,11 +380,6 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = pcim_iomap(pdev, 0, 0); - if (mmio_base == NULL) - return -ENOMEM; - base = (unsigned long) mmio_base; - /* * Due to a bug in the chip, the default cache line size can't be used */ @@ -398,7 +396,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d probe_ent->port_ops = &vsc_sata_ops; probe_ent->n_ports = 4; probe_ent->irq = pdev->irq; - probe_ent->mmio_base = mmio_base; + probe_ent->iomap = pcim_iomap_table(pdev); /* We don't care much about the PIO/UDMA masks, but the core won't like us * if we don't fill these @@ -407,11 +405,13 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d probe_ent->mwdma_mask = 0x07; probe_ent->udma_mask = 0x7f; + mmio_base = probe_ent->iomap[VSC_MMIO_BAR]; + /* We have 4 ports per PCI function */ - vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET); - vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET); - vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET); - vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[0], mmio_base + 1 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[1], mmio_base + 2 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[2], mmio_base + 3 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[3], mmio_base + 4 * VSC_SATA_PORT_OFFSET); pci_set_master(pdev); diff --git a/include/linux/libata.h b/include/linux/libata.h index cebbcc8d45fd..308bb8cbe50f 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -348,21 +348,21 @@ typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes); typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes); struct ata_ioports { - unsigned long cmd_addr; - unsigned long data_addr; - unsigned long error_addr; - unsigned long feature_addr; - unsigned long nsect_addr; - unsigned long lbal_addr; - unsigned long lbam_addr; - unsigned long lbah_addr; - unsigned long device_addr; - unsigned long status_addr; - unsigned long command_addr; - unsigned long altstatus_addr; - unsigned long ctl_addr; - unsigned long bmdma_addr; - unsigned long scr_addr; + void __iomem *cmd_addr; + void __iomem *data_addr; + void __iomem *error_addr; + void __iomem *feature_addr; + void __iomem *nsect_addr; + void __iomem *lbal_addr; + void __iomem *lbam_addr; + void __iomem *lbah_addr; + void __iomem *device_addr; + void __iomem *status_addr; + void __iomem *command_addr; + void __iomem *altstatus_addr; + void __iomem *ctl_addr; + void __iomem *bmdma_addr; + void __iomem *scr_addr; }; struct ata_probe_ent { @@ -381,7 +381,7 @@ struct ata_probe_ent { unsigned int irq_flags; unsigned long port_flags; unsigned long _host_flags; - void __iomem *mmio_base; + void __iomem * const *iomap; void *private_data; /* port_info for the secondary port. Together with irq2, it's @@ -398,7 +398,7 @@ struct ata_host { struct device *dev; unsigned long irq; unsigned long irq2; - void __iomem *mmio_base; + void __iomem * const *iomap; unsigned int n_ports; void *private_data; const struct ata_port_operations *ops; @@ -768,12 +768,10 @@ extern u8 ata_altstatus(struct ata_port *ap); extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); extern int ata_port_start (struct ata_port *ap); extern irqreturn_t ata_interrupt (int irq, void *dev_instance); -extern void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data); -extern void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data); -extern void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data); +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 void ata_qc_prep(struct ata_queued_cmd *qc); extern void ata_noop_qc_prep(struct ata_queued_cmd *qc); extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); @@ -1084,10 +1082,9 @@ static inline u8 ata_wait_idle(struct ata_port *ap) u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); if (status != 0xff && (status & (ATA_BUSY | ATA_DRQ))) { - unsigned long l = ap->ioaddr.status_addr; if (ata_msg_warn(ap)) - printk(KERN_WARNING "ATA: abnormal status 0x%X on port 0x%lX\n", - status, l); + printk(KERN_WARNING "ATA: abnormal status 0x%X on port 0x%p\n", + status, ap->ioaddr.status_addr); } return status; @@ -1172,20 +1169,11 @@ static inline u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq) printk(KERN_ERR "abnormal status 0x%X\n", status); /* get controller status; clear intr, err bits */ - if (ap->flags & ATA_FLAG_MMIO) { - void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; - host_stat = readb(mmio + ATA_DMA_STATUS); - writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - mmio + ATA_DMA_STATUS); - - post_stat = readb(mmio + ATA_DMA_STATUS); - } else { - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR, - ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - - post_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - } + 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", -- cgit v1.2.3 From 7f25377043925554cb9f3f9d8ada3390f71a5d10 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 2 Feb 2007 18:07:15 -0800 Subject: git-libata-all: forward declare struct device In file included from drivers/infiniband/hw/ipath/ipath_diag.c:44: include/linux/io.h:35: warning: 'struct device' declared inside parameter list include/linux/io.h:35: warning: its scope is only this definition or declaration Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- include/linux/io.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/io.h b/include/linux/io.h index 45a9c944cb0a..9e419ebfc98b 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -22,6 +22,8 @@ #include #include +struct device; + void __iowrite32_copy(void __iomem *to, const void *from, size_t count); void __iowrite64_copy(void __iomem *to, const void *from, size_t count); -- cgit v1.2.3 From 836250069fc0eeebe8b6aed772281535cc6e34f9 Mon Sep 17 00:00:00 2001 From: Akira Iguchi Date: Fri, 26 Jan 2007 16:27:32 +0900 Subject: libata: add another IRQ calls (core and headers) This patch is against the libata core and headers. Two IRQ calls are added in ata_port_operations. - irq_on() is used to enable interrupts. - irq_ack() is used to acknowledge a device interrupt. In most drivers, ata_irq_on() and ata_irq_ack() are used for irq_on and irq_ack respectively. In some drivers (ex: ahci, sata_sil24) which cannot use them as is, ata_dummy_irq_on() and ata_dummy_irq_ack() are used. Signed-off-by: Kou Ishizaki Signed-off-by: Akira Iguchi Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 20 ++++++++++---------- drivers/ata/libata-sff.c | 43 +++++++++++++++++++++++++++++++++++++++++-- include/linux/libata.h | 42 ++++++------------------------------------ 3 files changed, 57 insertions(+), 48 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f210dbd4cbe6..2e8ca652c0d9 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2664,8 +2664,7 @@ void ata_bus_reset(struct ata_port *ap) ap->device[1].class = ata_dev_try_classify(ap, 1, &err); /* re-enable interrupts */ - if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ - ata_irq_on(ap); + ap->ops->irq_on(ap); /* is double-select really necessary? */ if (ap->device[1].class != ATA_DEV_NONE) @@ -3054,11 +3053,8 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes) sata_scr_write(ap, SCR_ERROR, serror); /* re-enable interrupts */ - if (!ap->ops->error_handler) { - /* FIXME: hack. create a hook instead */ - if (ap->ioaddr.ctl_addr) - ata_irq_on(ap); - } + if (!ap->ops->error_handler) + ap->ops->irq_on(ap); /* is double-select really necessary? */ if (classes[0] != ATA_DEV_NONE) @@ -4169,7 +4165,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) qc = ata_qc_from_tag(ap, qc->tag); if (qc) { if (likely(!(qc->err_mask & AC_ERR_HSM))) { - ata_irq_on(ap); + ap->ops->irq_on(ap); ata_qc_complete(qc); } else ata_port_freeze(ap); @@ -4185,7 +4181,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) } else { if (in_wq) { spin_lock_irqsave(ap->lock, flags); - ata_irq_on(ap); + ap->ops->irq_on(ap); ata_qc_complete(qc); spin_unlock_irqrestore(ap->lock, flags); } else @@ -5010,7 +5006,7 @@ idle_irq: #ifdef ATA_IRQ_TRAP if ((ap->stats.idle_irq % 1000) == 0) { - ata_irq_ack(ap, 0); /* debug trap */ + ap->ops->irq_ack(ap, 0); /* debug trap */ ata_port_printk(ap, KERN_WARNING, "irq trap\n"); return 1; } @@ -6271,3 +6267,7 @@ EXPORT_SYMBOL_GPL(ata_eh_thaw_port); 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); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index c561b3be4a97..16bc3e35bdd4 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -64,6 +64,46 @@ 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, 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 = 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 @@ -370,8 +410,7 @@ void ata_bmdma_thaw(struct ata_port *ap) /* clear & re-enable interrupts */ ata_chk_status(ap); ap->ops->irq_clear(ap); - if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ - ata_irq_on(ap); + ap->ops->irq_on(ap); } /** diff --git a/include/linux/libata.h b/include/linux/libata.h index 308bb8cbe50f..bdfe6ea8edf7 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -632,6 +632,8 @@ 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); u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg); void (*scr_write) (struct ata_port *ap, unsigned int sc_reg, @@ -813,6 +815,10 @@ 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 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); /* * Timing helpers @@ -1147,42 +1153,6 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) qc->result_tf.feature = 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: - */ - -static inline 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, 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 = 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; -} - static inline int ata_try_flush_cache(const struct ata_device *dev) { return ata_id_wcache_enabled(dev->id) || -- cgit v1.2.3 From 49554c19569c91d0943b67ca731c9abfc857883f Mon Sep 17 00:00:00 2001 From: Alan Date: Mon, 5 Feb 2007 16:17:19 +0000 Subject: ata: Add defines for the iordy bits IORDY and IORDY enable/disable flags. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- include/linux/ata.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/ata.h b/include/linux/ata.h index 3a50739e25a6..18e401ff7eaf 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -299,6 +299,8 @@ 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_iordy_disable(id) ((id)[49] & (1 << 10)) +#define ata_id_has_iordy(id) ((id)[49] & (1 << 9)) #define ata_id_u32(id,n) \ (((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)])) #define ata_id_u64(id,n) \ -- cgit v1.2.3 From 66efc5a7e3061c3597ac43a8bb1026488d57e66b Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 6 Feb 2007 22:19:10 -0500 Subject: libata: kill ATA_ENABLE_PATA The ATA_ENABLE_PATA define was never meant to be permanent, and in recent kernels, it's already been unconditionally enabled. Remove. Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 2 -- include/linux/libata.h | 2 -- 2 files changed, 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index c528d42ee106..4d716c7347e7 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -164,7 +164,6 @@ static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev); static unsigned int in_module_init = 1; static const struct pci_device_id piix_pci_tbl[] = { -#ifdef ATA_ENABLE_PATA /* Intel PIIX3 for the 430HX etc */ { 0x8086, 0x7010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_mwdma }, /* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */ @@ -204,7 +203,6 @@ static const struct pci_device_id piix_pci_tbl[] = { /* ICH7/7-R (i945, i975) UDMA 100*/ { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 }, { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, -#endif /* NOTE: The following PCI ids must be kept in sync with the * list in drivers/pci/quirks.c. diff --git a/include/linux/libata.h b/include/linux/libata.h index bdfe6ea8edf7..596e0c18887d 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -54,8 +54,6 @@ #undef ATA_VERBOSE_DEBUG /* yet more debugging output */ #undef ATA_IRQ_TRAP /* define to ack screaming irqs */ #undef ATA_NDEBUG /* define to disable quick runtime checks */ -#define ATA_ENABLE_PATA /* define to enable PATA support in some - * low-level drivers */ /* note: prints function name for you */ -- cgit v1.2.3