diff --git a/Documentation/HOWTO b/Documentation/HOWTO index 8d51c148f721..48123dba5e6a 100644 --- a/Documentation/HOWTO +++ b/Documentation/HOWTO @@ -30,6 +30,7 @@ are not a good substitute for a solid C education and/or years of experience, the following books are good for, if anything, reference: - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall] - "Practical C Programming" by Steve Oualline [O'Reilly] + - "C: A Reference Manual" by Harbison and Steele [Prentice Hall] The kernel is written using GNU C and the GNU toolchain. While it adheres to the ISO C89 standard, it uses a number of extensions that are diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 0ba6af02cdaf..2dc5e5da8f88 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -274,6 +274,7 @@ Who: Venkatesh Pallipadi --------------------------- +<<<<<<< test:Documentation/feature-removal-schedule.txt What: ACPI hotkey driver (CONFIG_ACPI_HOTKEY) When: 2.6.21 Why: hotkey.c was an attempt to consolidate multiple drivers that use @@ -306,11 +307,18 @@ Why: The ACPI namespace is effectively the symbol list for the BIOS can be extracted and disassembled with acpidump and iasl as documented in the pmtools package here: http://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/utils - Who: Len Brown --------------------------- +What: ACPI procfs interface +When: July 2007 +Why: After ACPI sysfs conversion, ACPI attributes will be duplicated + in sysfs and the ACPI procfs interface should be removed. +Who: Zhang Rui + +--------------------------- + What: /proc/acpi/button When: August 2007 Why: /proc/acpi/button has been replaced by events to the input layer @@ -325,3 +333,10 @@ Why: Unmaintained for years, superceded by JFFS2 for years. Who: Jeff Garzik --------------------------- + +What: sk98lin network driver +When: July 2007 +Why: In kernel tree version of driver is unmaintained. Sk98lin driver + replaced by the skge driver. +Who: Stephen Hemminger + diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt index 3f9ddbc23b27..0993969609cf 100644 --- a/Documentation/s390/Debugging390.txt +++ b/Documentation/s390/Debugging390.txt @@ -480,7 +480,7 @@ r2 argument 0 / return value 0 call-clobbered r3 argument 1 / return value 1 (if long long) call-clobbered r4 argument 2 call-clobbered r5 argument 3 call-clobbered -r6 argument 5 saved +r6 argument 4 saved r7 pointer-to arguments 5 to ... saved r8 this & that saved r9 this & that saved diff --git a/Documentation/usb/proc_usb_info.txt b/Documentation/usb/proc_usb_info.txt index 22c5331260ca..077e9032d0cd 100644 --- a/Documentation/usb/proc_usb_info.txt +++ b/Documentation/usb/proc_usb_info.txt @@ -213,15 +213,16 @@ C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA Interface descriptor info (can be multiple per Config): -I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss -| | | | | | | |__Driver name -| | | | | | | or "(none)" -| | | | | | |__InterfaceProtocol -| | | | | |__InterfaceSubClass -| | | | |__InterfaceClass -| | | |__NumberOfEndpoints -| | |__AlternateSettingNumber -| |__InterfaceNumber +I:* If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss +| | | | | | | | |__Driver name +| | | | | | | | or "(none)" +| | | | | | | |__InterfaceProtocol +| | | | | | |__InterfaceSubClass +| | | | | |__InterfaceClass +| | | | |__NumberOfEndpoints +| | | |__AlternateSettingNumber +| | |__InterfaceNumber +| |__ "*" indicates the active altsetting (others are " ") |__Interface info tag A given interface may have one or more "alternate" settings. @@ -277,7 +278,7 @@ of the USB devices on a system's root hub. (See more below on how to do this.) The Interface lines can be used to determine what driver is -being used for each device. +being used for each device, and which altsetting it activated. The Configuration lines could be used to list maximum power (in milliamps) that a system's USB devices are using. diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index e65ec828d7aa..0f6808abd612 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt @@ -77,7 +77,7 @@ that the file size is not excessive for your favourite editor. The '1t' type data consists of a stream of events, such as URB submission, URB callback, submission error. Every event is a text line, which consists -of whitespace separated words. The number of position of words may depend +of whitespace separated words. The number or position of words may depend on the event type, but there is a set of words, common for all types. Here is the list of words, from left to right: @@ -170,4 +170,152 @@ dd65f0e8 4128379808 C Bo:005:02 0 31 > * Raw binary format and API -TBD +The overall architecture of the API is about the same as the one above, +only the events are delivered in binary format. Each event is sent in +the following structure (its name is made up, so that we can refer to it): + +struct usbmon_packet { + u64 id; /* 0: URB ID - from submission to callback */ + unsigned char type; /* 8: Same as text; extensible. */ + unsigned char xfer_type; /* ISO (0), Intr, Control, Bulk (3) */ + unsigned char epnum; /* Endpoint number and transfer direction */ + unsigned char devnum; /* Device address */ + u16 busnum; /* 12: Bus number */ + char flag_setup; /* 14: Same as text */ + char flag_data; /* 15: Same as text; Binary zero is OK. */ + s64 ts_sec; /* 16: gettimeofday */ + s32 ts_usec; /* 24: gettimeofday */ + int status; /* 28: */ + unsigned int length; /* 32: Length of data (submitted or actual) */ + unsigned int len_cap; /* 36: Delivered length */ + unsigned char setup[8]; /* 40: Only for Control 'S' */ +}; /* 48 bytes total */ + +These events can be received from a character device by reading with read(2), +with an ioctl(2), or by accessing the buffer with mmap. + +The character device is usually called /dev/usbmonN, where N is the USB bus +number. Number zero (/dev/usbmon0) is special and means "all buses". +However, this feature is not implemented yet. Note that specific naming +policy is set by your Linux distribution. + +If you create /dev/usbmon0 by hand, make sure that it is owned by root +and has mode 0600. Otherwise, unpriviledged users will be able to snoop +keyboard traffic. + +The following ioctl calls are available, with MON_IOC_MAGIC 0x92: + + MON_IOCQ_URB_LEN, defined as _IO(MON_IOC_MAGIC, 1) + +This call returns the length of data in the next event. Note that majority of +events contain no data, so if this call returns zero, it does not mean that +no events are available. + + MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) + +The argument is a pointer to the following structure: + +struct mon_bin_stats { + u32 queued; + u32 dropped; +}; + +The member "queued" refers to the number of events currently queued in the +buffer (and not to the number of events processed since the last reset). + +The member "dropped" is the number of events lost since the last call +to MON_IOCG_STATS. + + MON_IOCT_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 4) + +This call sets the buffer size. The argument is the size in bytes. +The size may be rounded down to the next chunk (or page). If the requested +size is out of [unspecified] bounds for this kernel, the call fails with +-EINVAL. + + MON_IOCQ_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 5) + +This call returns the current size of the buffer in bytes. + + MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg) + +This call waits for events to arrive if none were in the kernel buffer, +then returns the first event. Its argument is a pointer to the following +structure: + +struct mon_get_arg { + struct usbmon_packet *hdr; + void *data; + size_t alloc; /* Length of data (can be zero) */ +}; + +Before the call, hdr, data, and alloc should be filled. Upon return, the area +pointed by hdr contains the next event structure, and the data buffer contains +the data, if any. The event is removed from the kernel buffer. + + MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg) + +This ioctl is primarily used when the application accesses the buffer +with mmap(2). Its argument is a pointer to the following structure: + +struct mon_mfetch_arg { + uint32_t *offvec; /* Vector of events fetched */ + uint32_t nfetch; /* Number of events to fetch (out: fetched) */ + uint32_t nflush; /* Number of events to flush */ +}; + +The ioctl operates in 3 stages. + +First, it removes and discards up to nflush events from the kernel buffer. +The actual number of events discarded is returned in nflush. + +Second, it waits for an event to be present in the buffer, unless the pseudo- +device is open with O_NONBLOCK. + +Third, it extracts up to nfetch offsets into the mmap buffer, and stores +them into the offvec. The actual number of event offsets is stored into +the nfetch. + + MON_IOCH_MFLUSH, defined as _IO(MON_IOC_MAGIC, 8) + +This call removes a number of events from the kernel buffer. Its argument +is the number of events to remove. If the buffer contains fewer events +than requested, all events present are removed, and no error is reported. +This works when no events are available too. + + FIONBIO + +The ioctl FIONBIO may be implemented in the future, if there's a need. + +In addition to ioctl(2) and read(2), the special file of binary API can +be polled with select(2) and poll(2). But lseek(2) does not work. + +* Memory-mapped access of the kernel buffer for the binary API + +The basic idea is simple: + +To prepare, map the buffer by getting the current size, then using mmap(2). +Then, execute a loop similar to the one written in pseudo-code below: + + struct mon_mfetch_arg fetch; + struct usbmon_packet *hdr; + int nflush = 0; + for (;;) { + fetch.offvec = vec; // Has N 32-bit words + fetch.nfetch = N; // Or less than N + fetch.nflush = nflush; + ioctl(fd, MON_IOCX_MFETCH, &fetch); // Process errors, too + nflush = fetch.nfetch; // This many packets to flush when done + for (i = 0; i < nflush; i++) { + hdr = (struct ubsmon_packet *) &mmap_area[vec[i]]; + if (hdr->type == '@') // Filler packet + continue; + caddr_t data = &mmap_area[vec[i]] + 64; + process_packet(hdr, data); + } + } + +Thus, the main idea is to execute only one ioctl per N events. + +Although the buffer is circular, the returned headers and data do not cross +the end of the buffer, so the above pseudo-code does not need any gathering. diff --git a/Documentation/video-output.txt b/Documentation/video-output.txt new file mode 100644 index 000000000000..e517011be4f9 --- /dev/null +++ b/Documentation/video-output.txt @@ -0,0 +1,34 @@ + + Video Output Switcher Control + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 2006 luming.yu@intel.com + +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. For example, on my IBM ThinkPad T42 +laptop, The ACPI video driver registered its output devices and read/write +method for 'state' with output sysfs class. The user interface under sysfs is: + +linux:/sys/class/video_output # tree . +. +|-- CRT0 +| |-- device -> ../../../devices/pci0000:00/0000:00:01.0 +| |-- state +| |-- subsystem -> ../../../class/video_output +| `-- uevent +|-- DVI0 +| |-- device -> ../../../devices/pci0000:00/0000:00:01.0 +| |-- state +| |-- subsystem -> ../../../class/video_output +| `-- uevent +|-- LCD0 +| |-- device -> ../../../devices/pci0000:00/0000:00:01.0 +| |-- state +| |-- subsystem -> ../../../class/video_output +| `-- uevent +`-- TV0 + |-- device -> ../../../devices/pci0000:00/0000:00:01.0 + |-- state + |-- subsystem -> ../../../class/video_output + `-- uevent + diff --git a/MAINTAINERS b/MAINTAINERS index 0ad8803a0c75..fe35f3ac4cd3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -584,12 +584,30 @@ W: http://sourceforge.net/projects/acpi4asus W: http://xf.iksaif.net/acpi4asus S: Maintained +ASUS LAPTOP EXTRAS DRIVER +P: Corentin Chary +M: corentincj@iksaif.net +L: acpi4asus-user@lists.sourceforge.net +W: http://sourceforge.net/projects/acpi4asus +W: http://xf.iksaif.net/acpi4asus +S: Maintained + ATA OVER ETHERNET DRIVER P: Ed L. Cashin M: ecashin@coraid.com W: http://www.coraid.com/support/linux S: Supported +ATL1 ETHERNET DRIVER +P: Jay Cliburn +M: jcliburn@gmail.com +P: Chris Snook +M: csnook@redhat.com +L: atl1-devel@lists.sourceforge.net +W: http://sourceforge.net/projects/atl1 +W: http://atl1.sourceforge.net +S: Maintained + ATM P: Chas Williams M: chas@cmf.nrl.navy.mil @@ -2477,6 +2495,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 @@ -2646,7 +2670,7 @@ S: Supported PRISM54 WIRELESS DRIVER P: Prism54 Development Team -M: prism54-private@prism54.org +M: developers@islsm.org L: netdev@vger.kernel.org W: http://prism54.org S: Maintained @@ -2791,7 +2815,7 @@ M: schwidefsky@de.ibm.com P: Heiko Carstens M: heiko.carstens@de.ibm.com M: linux390@de.ibm.com -L: linux-390@vm.marist.edu +L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported @@ -2799,7 +2823,7 @@ S390 NETWORK DRIVERS P: Frank Pavlic M: fpavlic@de.ibm.com M: linux390@de.ibm.com -L: linux-390@vm.marist.edu +L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported @@ -2807,7 +2831,7 @@ S390 ZFCP DRIVER P: Swen Schillig M: swen@vnet.ibm.com M: linux390@de.ibm.com -L: linux-390@vm.marist.edu +L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported @@ -3647,7 +3671,7 @@ S: Maintained W83L51xD SD/MMC CARD INTERFACE DRIVER P: Pierre Ossman M: drzeus-wbsd@drzeus.cx -L: wbsd-devel@list.drzeus.cx +L: linux-kernel@vger.kernel.org W: http://projects.drzeus.cx/wbsd S: Maintained diff --git a/Makefile b/Makefile index 7e2750f4ca70..cdeda68cf2aa 100644 --- a/Makefile +++ b/Makefile @@ -776,7 +776,7 @@ $(vmlinux-dirs): prepare scripts # $(EXTRAVERSION) eg, -rc6 # $(localver-full) # $(localver) -# localversion* (all localversion* files) +# localversion* (files without backups, containing '~') # $(CONFIG_LOCALVERSION) (from kernel config setting) # $(localver-auto) (only if CONFIG_LOCALVERSION_AUTO is set) # ./scripts/setlocalversion (SCM tag, if one exists) @@ -787,17 +787,12 @@ $(vmlinux-dirs): prepare scripts # moment, only git is supported but other SCMs can edit the script # scripts/setlocalversion and add the appropriate checks as needed. -nullstring := -space := $(nullstring) # end of line +pattern = ".*/localversion[^~]*" +string = $(shell cat /dev/null \ + `find $(objtree) $(srctree) -maxdepth 1 -regex $(pattern) | sort`) -___localver = $(objtree)/localversion* $(srctree)/localversion* -__localver = $(sort $(wildcard $(___localver))) -# skip backup files (containing '~') -_localver = $(foreach f, $(__localver), $(if $(findstring ~, $(f)),,$(f))) - -localver = $(subst $(space),, \ - $(shell cat /dev/null $(_localver)) \ - $(patsubst "%",%,$(CONFIG_LOCALVERSION))) +localver = $(subst $(space),, $(string) \ + $(patsubst "%",%,$(CONFIG_LOCALVERSION))) # If CONFIG_LOCALVERSION_AUTO is set scripts/setlocalversion is called # and if the SCM is know a tag from the SCM is appended. 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/arch/i386/defconfig b/arch/i386/defconfig index 5d80edfc61b7..bb0c376b62b3 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -466,7 +466,8 @@ CONFIG_FW_LOADER=y # # Plug and Play support # -# CONFIG_PNP is not set +CONFIG_PNP=y +CONFIG_PNPACPI=y # # Block devices diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index cbcb2c27f48b..e94aff6888ca 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; @@ -92,11 +92,6 @@ static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; #warning ACPI uses CMPXCHG, i486 and later hardware #endif -#define MAX_MADT_ENTRIES 256 -u8 x86_acpiid_to_apicid[MAX_MADT_ENTRIES] = - {[0 ... MAX_MADT_ENTRIES - 1] = 0xff }; -EXPORT_SYMBOL(x86_acpiid_to_apicid); - /* -------------------------------------------------------------------------- Boot-time Configuration -------------------------------------------------------------------------- */ @@ -166,30 +161,26 @@ 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(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); - if (!mcfg) { - printk(KERN_WARNING PREFIX "Unable to map MCFG\n"); - return -ENODEV; - } + mcfg = (struct acpi_table_mcfg *)header; /* how many config structures do we have */ pci_mmcfg_config_num = 0; - i = size - sizeof(struct acpi_table_mcfg); - while (i >= sizeof(struct acpi_table_mcfg_config)) { + i = header->length - sizeof(struct acpi_table_mcfg); + 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"); @@ -204,9 +195,9 @@ int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) 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].address > 0xFFFFFFFF) { printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n"); kfree(pci_mmcfg_config); @@ -220,24 +211,24 @@ 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 *table) { struct acpi_table_madt *madt = NULL; - if (!phys_addr || !size || !cpu_has_apic) + if (!cpu_has_apic) return -EINVAL; - madt = (struct acpi_table_madt *)__acpi_map_table(phys_addr, size); + madt = (struct acpi_table_madt *)table; if (!madt) { printk(KERN_WARNING PREFIX "Unable to map MADT\n"); 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); @@ -246,21 +237,17 @@ static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size) } 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; 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; - /* * We need to register disabled CPU as well to permit * counting disabled CPUs. This allows us to size @@ -269,18 +256,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 +278,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 +300,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 +329,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 @@ -357,51 +344,52 @@ static void __init acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger) /* * stash over-ride to indicate we've been here - * and for later update of acpi_fadt + * and for later update of acpi_gbl_FADT */ acpi_sci_override_gsi = gsi; return; } 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_fadt.sci_int) { + 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 +405,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 +499,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 +517,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 +532,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 @@ -566,14 +554,6 @@ EXPORT_SYMBOL(acpi_map_lsapic); int acpi_unmap_lsapic(int cpu) { - int i; - - for_each_possible_cpu(i) { - if (x86_acpiid_to_apicid[i] == x86_cpu_to_apicid[cpu]) { - x86_acpiid_to_apicid[i] = -1; - break; - } - } x86_cpu_to_apicid[cpu] = -1; cpu_clear(cpu, cpu_present_map); num_processors--; @@ -619,42 +599,36 @@ 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 *table) { - struct acpi_table_sbf *sb; + struct acpi_table_boot *sb; - if (!phys_addr || !size) - return -EINVAL; - - sb = (struct acpi_table_sbf *)__acpi_map_table(phys_addr, size); + 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(unsigned long phys, unsigned long size) +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 (!phys || !size) - return -EINVAL; - - hpet_tbl = (struct acpi_table_hpet *)__acpi_map_table(phys, size); + hpet_tbl = (struct acpi_table_hpet *)table; if (!hpet_tbl) { printk(KERN_WARNING PREFIX "Unable to map HPET\n"); 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 +641,28 @@ static int __init acpi_parse_hpet(unsigned long phys, unsigned long size) 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; @@ -707,42 +680,28 @@ 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 *table) { - struct fadt_descriptor *fadt = NULL; - - fadt = (struct fadt_descriptor *)__acpi_map_table(phys, size); - if (!fadt) { - 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 (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) { /* FADT rev. 2 */ - if (fadt->xpm_tmr_blk.address_space_id != + if (acpi_gbl_FADT.xpm_timer_block.space_id != ACPI_ADR_SPACE_SYSTEM_IO) return 0; - pmtmr_ioport = fadt->xpm_tmr_blk.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->V1_pm_tmr_blk; + pmtmr_ioport = acpi_gbl_FADT.pm_timer_block; } else { /* FADT rev. 1 */ - pmtmr_ioport = fadt->V1_pm_tmr_blk; + pmtmr_ioport = acpi_gbl_FADT.pm_timer_block; } if (pmtmr_ioport) printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", @@ -784,13 +743,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 @@ -800,7 +759,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"); @@ -813,7 +772,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 */ @@ -842,7 +801,7 @@ static int __init acpi_parse_madt_ioapic_entries(void) return -ENODEV; } - if (!cpu_has_apic) + if (!cpu_has_apic) return -ENODEV; /* @@ -855,7 +814,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"); @@ -866,7 +825,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 @@ -880,13 +839,13 @@ static int __init acpi_parse_madt_ioapic_entries(void) * pretend we got one so we can set the SCI flags. */ if (!acpi_sci_override_gsi) - acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0); + acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0); /* Fill in identity legacy mapings where no override */ 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"); @@ -908,7 +867,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(ACPI_SIG_MADT, acpi_parse_madt); if (count >= 1) { /* @@ -1195,7 +1154,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(); @@ -1204,7 +1163,7 @@ int __init acpi_boot_table_init(void) return error; } - acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); + acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf); /* * blacklist may disable ACPI entirely @@ -1232,19 +1191,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(ACPI_SIG_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(ACPI_SIG_HPET, acpi_parse_hpet); return 0; } @@ -1315,13 +1274,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/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c index 4b60af7f91dd..bf86f7662d8b 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(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/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index e940e00b96c9..a3db9332d652 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -190,7 +190,7 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index) /* Invoke C3 */ inb(cx_address); /* Dummy op - must do something useless after P_LVL3 read */ - t = inl(acpi_fadt.xpm_tmr_blk.address); + t = inl(acpi_gbl_FADT.xpm_timer_block.address); } /* Disable bus ratio bit */ local_irq_disable(); @@ -250,8 +250,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index) outb(3, 0x22); } else if ((pr != NULL) && pr->flags.bm_control) { /* Disable bus master arbitration */ - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1); } switch (longhaul_version) { @@ -281,8 +280,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index) case TYPE_POWERSAVER: if (longhaul_flags & USE_ACPI_C3) { /* Don't allow wakeup */ - acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0); do_powersaver(cx->address, clock_ratio_index); } else { do_powersaver(0, clock_ratio_index); @@ -295,8 +293,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index) outb(0, 0x22); } else if ((pr != NULL) && pr->flags.bm_control) { /* Enable bus master arbitration */ - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); } outb(pic2_mask,0xA1); /* restore mask */ outb(pic1_mask,0x21); @@ -414,7 +411,7 @@ static int __init longhaul_get_ranges(void) highest_speed = calc_speed(maxmult); lowest_speed = calc_speed(minmult); dprintk ("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb, - print_speed(lowest_speed/1000), + print_speed(lowest_speed/1000), print_speed(highest_speed/1000)); if (lowest_speed == highest_speed) { @@ -498,7 +495,7 @@ static void __init longhaul_setup_voltagescaling(void) maxvid.mV/1000, maxvid.mV%1000, minvid.mV/1000, minvid.mV%1000, numvscales); - + j = 0; while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) { speed = longhaul_table[j].frequency; 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/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c index 49bff3596bff..4f5983c98669 100644 --- a/arch/i386/kernel/mpparse.c +++ b/arch/i386/kernel/mpparse.c @@ -1057,7 +1057,7 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity) static int gsi_to_irq[MAX_GSI_NUM]; /* Don't set up the ACPI SCI because it's already set up */ - if (acpi_fadt.sci_int == gsi) + if (acpi_gbl_FADT.sci_interrupt == gsi) return gsi; ioapic = mp_find_ioapic(gsi); @@ -1114,7 +1114,7 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity) /* * Don't assign IRQ used by ACPI SCI */ - if (gsi == acpi_fadt.sci_int) + if (gsi == acpi_gbl_FADT.sci_interrupt) gsi = pci_irq++; gsi_to_irq[irq] = gsi; } else { diff --git a/arch/i386/kernel/srat.c b/arch/i386/kernel/srat.c index f7e735c077c3..2a8713ec0f9a 100644 --- a/arch/i386/kernel/srat.c +++ b/arch/i386/kernel/srat.c @@ -62,19 +62,19 @@ extern void * boot_ioremap(unsigned long, unsigned long); /* Identify CPU proximity domains */ static void __init parse_cpu_affinity_structure(char *p) { - struct acpi_table_processor_affinity *cpu_affinity = - (struct acpi_table_processor_affinity *) p; + struct acpi_srat_cpu_affinity *cpu_affinity = + (struct acpi_srat_cpu_affinity *) p; - if (!cpu_affinity->flags.enabled) + if ((cpu_affinity->flags & ACPI_SRAT_CPU_ENABLED) == 0) return; /* empty entry */ /* mark this node as "seen" in node bitmap */ - BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain); + BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain_lo); - apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain; + apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain_lo; printk("CPU 0x%02X in proximity domain 0x%02X\n", - cpu_affinity->apic_id, cpu_affinity->proximity_domain); + cpu_affinity->apic_id, cpu_affinity->proximity_domain_lo); } /* @@ -84,28 +84,27 @@ static void __init parse_cpu_affinity_structure(char *p) static void __init parse_memory_affinity_structure (char *sratp) { unsigned long long paddr, size; - unsigned long start_pfn, end_pfn; + unsigned long start_pfn, end_pfn; u8 pxm; struct node_memory_chunk_s *p, *q, *pend; - struct acpi_table_memory_affinity *memory_affinity = - (struct acpi_table_memory_affinity *) sratp; + struct acpi_srat_mem_affinity *memory_affinity = + (struct acpi_srat_mem_affinity *) sratp; - if (!memory_affinity->flags.enabled) + if ((memory_affinity->flags & ACPI_SRAT_MEM_ENABLED) == 0) return; /* empty entry */ + pxm = memory_affinity->proximity_domain & 0xff; + /* mark this node as "seen" in node bitmap */ - BMAP_SET(pxm_bitmap, memory_affinity->proximity_domain); + BMAP_SET(pxm_bitmap, pxm); /* calculate info for memory chunk structure */ - paddr = memory_affinity->base_addr_hi; - paddr = (paddr << 32) | memory_affinity->base_addr_lo; - size = memory_affinity->length_hi; - size = (size << 32) | memory_affinity->length_lo; - + paddr = memory_affinity->base_address; + size = memory_affinity->length; + start_pfn = paddr >> PAGE_SHIFT; end_pfn = (paddr + size) >> PAGE_SHIFT; - - pxm = memory_affinity->proximity_domain; + if (num_memory_chunks >= MAXCHUNKS) { printk("Too many mem chunks in SRAT. Ignoring %lld MBytes at %llx\n", @@ -132,8 +131,8 @@ static void __init parse_memory_affinity_structure (char *sratp) printk("Memory range 0x%lX to 0x%lX (type 0x%X) in proximity domain 0x%02X %s\n", start_pfn, end_pfn, memory_affinity->memory_type, - memory_affinity->proximity_domain, - (memory_affinity->flags.hot_pluggable ? + pxm, + ((memory_affinity->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ? "enabled and removable" : "enabled" ) ); } @@ -185,10 +184,10 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp) num_memory_chunks = 0; while (p < end) { switch (*p) { - case ACPI_SRAT_PROCESSOR_AFFINITY: + case ACPI_SRAT_TYPE_CPU_AFFINITY: parse_cpu_affinity_structure(p); break; - case ACPI_SRAT_MEMORY_AFFINITY: + case ACPI_SRAT_TYPE_MEMORY_AFFINITY: parse_memory_affinity_structure(p); break; default: @@ -262,31 +261,30 @@ out_fail: return 0; } +struct acpi_static_rsdt { + struct acpi_table_rsdt table; + u32 padding[7]; /* Allow for 7 more table entries */ +}; + int __init get_memcfg_from_srat(void) { struct acpi_table_header *header = NULL; struct acpi_table_rsdp *rsdp = NULL; struct acpi_table_rsdt *rsdt = NULL; - struct acpi_pointer *rsdp_address = NULL; - struct acpi_table_rsdt saved_rsdt; + acpi_native_uint rsdp_address = 0; + struct acpi_static_rsdt saved_rsdt; int tables = 0; int i = 0; - if (ACPI_FAILURE(acpi_find_root_pointer(ACPI_PHYSICAL_ADDRESSING, - rsdp_address))) { + rsdp_address = acpi_find_rsdp(); + if (!rsdp_address) { printk("%s: System description tables not found\n", __FUNCTION__); goto out_err; } - if (rsdp_address->pointer_type == ACPI_PHYSICAL_POINTER) { - printk("%s: assigning address to rsdp\n", __FUNCTION__); - rsdp = (struct acpi_table_rsdp *) - (u32)rsdp_address->pointer.physical; - } else { - printk("%s: rsdp_address is not a physical pointer\n", __FUNCTION__); - goto out_err; - } + printk("%s: assigning address to rsdp\n", __FUNCTION__); + rsdp = (struct acpi_table_rsdp *)(u32)rsdp_address; if (!rsdp) { printk("%s: Didn't find ACPI root!\n", __FUNCTION__); goto out_err; @@ -295,13 +293,13 @@ int __init get_memcfg_from_srat(void) printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision, rsdp->oem_id); - if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) { + if (strncmp(rsdp->signature, ACPI_SIG_RSDP,strlen(ACPI_SIG_RSDP))) { printk(KERN_WARNING "%s: RSDP table signature incorrect\n", __FUNCTION__); goto out_err; } rsdt = (struct acpi_table_rsdt *) - boot_ioremap(rsdp->rsdt_address, sizeof(struct acpi_table_rsdt)); + boot_ioremap(rsdp->rsdt_physical_address, sizeof(struct acpi_table_rsdt)); if (!rsdt) { printk(KERN_WARNING @@ -310,9 +308,9 @@ int __init get_memcfg_from_srat(void) goto out_err; } - header = & rsdt->header; + header = &rsdt->header; - if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) { + if (strncmp(header->signature, ACPI_SIG_RSDT, strlen(ACPI_SIG_RSDT))) { printk(KERN_WARNING "ACPI: RSDT signature incorrect\n"); goto out_err; } @@ -330,9 +328,9 @@ int __init get_memcfg_from_srat(void) memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt)); - if (saved_rsdt.header.length > sizeof(saved_rsdt)) { + if (saved_rsdt.table.header.length > sizeof(saved_rsdt)) { printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n", - saved_rsdt.header.length); + saved_rsdt.table.header.length); goto out_err; } @@ -341,15 +339,15 @@ int __init get_memcfg_from_srat(void) for (i = 0; i < tables; i++) { /* Map in header, then map in full table length. */ header = (struct acpi_table_header *) - boot_ioremap(saved_rsdt.entry[i], sizeof(struct acpi_table_header)); + boot_ioremap(saved_rsdt.table.table_offset_entry[i], sizeof(struct acpi_table_header)); if (!header) break; header = (struct acpi_table_header *) - boot_ioremap(saved_rsdt.entry[i], header->length); + boot_ioremap(saved_rsdt.table.table_offset_entry[i], header->length); if (!header) break; - if (strncmp((char *) &header->signature, "SRAT", 4)) + if (strncmp((char *) &header->signature, ACPI_SIG_SRAT, 4)) continue; /* we've found the srat table. don't need to look at any more tables */ 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..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(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; } diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index fcacfe291b9b..f1d2899e9a62 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -11,6 +11,8 @@ menu "Processor type and features" config IA64 bool + select PCI if (!IA64_HP_SIM) + select ACPI if (!IA64_HP_SIM) default y help The Itanium Processor Family is Intel's 64-bit successor to @@ -28,7 +30,6 @@ config MMU config SWIOTLB bool - default y config RWSEM_XCHGADD_ALGORITHM bool @@ -84,10 +85,9 @@ choice config IA64_GENERIC bool "generic" - select ACPI - select PCI select NUMA select ACPI_NUMA + select SWIOTLB help This selects the system type of your hardware. A "generic" kernel will run on any supported IA-64 system. However, if you configure @@ -104,6 +104,7 @@ config IA64_GENERIC config IA64_DIG bool "DIG-compliant" + select SWIOTLB config IA64_HP_ZX1 bool "HP-zx1/sx1000" @@ -113,6 +114,7 @@ config IA64_HP_ZX1 config IA64_HP_ZX1_SWIOTLB bool "HP-zx1/sx1000 with software I/O TLB" + select SWIOTLB help Build a kernel that runs on HP zx1 and sx1000 systems even when they have broken PCI devices which cannot DMA to full 32 bits. Apart @@ -131,6 +133,7 @@ config IA64_SGI_SN2 config IA64_HP_SIM bool "Ski-simulator" + select SWIOTLB endchoice diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c index a5a5637507be..2153bcacbe6c 100644 --- a/arch/ia64/hp/common/hwsw_iommu.c +++ b/arch/ia64/hp/common/hwsw_iommu.c @@ -192,3 +192,7 @@ EXPORT_SYMBOL(hwsw_unmap_sg); EXPORT_SYMBOL(hwsw_dma_supported); EXPORT_SYMBOL(hwsw_alloc_coherent); EXPORT_SYMBOL(hwsw_free_coherent); +EXPORT_SYMBOL(hwsw_sync_single_for_cpu); +EXPORT_SYMBOL(hwsw_sync_single_for_device); +EXPORT_SYMBOL(hwsw_sync_sg_for_cpu); +EXPORT_SYMBOL(hwsw_sync_sg_for_device); diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 29f05d4b68cd..9197d7b361b3 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: " @@ -67,16 +67,11 @@ EXPORT_SYMBOL(pm_power_off); unsigned int acpi_cpei_override; unsigned int acpi_cpei_phys_cpuid; -#define MAX_SAPICS 256 -u16 ia64_acpiid_to_sapicid[MAX_SAPICS] = {[0 ... MAX_SAPICS - 1] = -1 }; - -EXPORT_SYMBOL(ia64_acpiid_to_sapicid); - 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,16 +82,16 @@ 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"; } - 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, 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"; @@ -169,12 +164,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,22 +182,19 @@ 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] = - (lsapic->id << 8) | lsapic->eid; ++available_cpus; } @@ -211,11 +203,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 +217,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 +232,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 +249,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 +316,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 +365,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 +378,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 +407,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; + if (!ia64_platform_is("sn2")) + pxm &= 0xff; + return pxm; } @@ -442,7 +437,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 +449,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 +462,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 +478,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 +553,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]; } } @@ -617,21 +610,21 @@ 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 fadt_descriptor *fadt; + 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 */ - fadt = (struct fadt_descriptor *)fadt_header; + fadt = (struct acpi_table_fadt *)fadt_header; - acpi_register_gsi(fadt->sci_int, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW); + acpi_register_gsi(fadt->sci_interrupt, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW); return 0; } @@ -658,7 +651,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; } @@ -666,40 +659,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: @@ -709,7 +702,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 @@ -842,7 +835,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; @@ -854,16 +847,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; } @@ -883,7 +876,6 @@ 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]; *pcpu = cpu; return (0); @@ -893,14 +885,6 @@ EXPORT_SYMBOL(acpi_map_lsapic); int acpi_unmap_lsapic(int cpu) { - int i; - - for (i = 0; i < MAX_SAPICS; i++) { - if (ia64_acpiid_to_sapicid[i] == ia64_cpu_to_sapicid[cpu]) { - ia64_acpiid_to_sapicid[i] = -1; - break; - } - } ia64_cpu_to_sapicid[cpu] = -1; cpu_clear(cpu, cpu_present_map); @@ -920,7 +904,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; @@ -938,9 +922,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/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c index bc2f64d72244..9d92097ce96d 100644 --- a/arch/ia64/kernel/crash.c +++ b/arch/ia64/kernel/crash.c @@ -79,6 +79,7 @@ crash_save_this_cpu() final_note(buf); } +#ifdef CONFIG_SMP static int kdump_wait_cpu_freeze(void) { @@ -91,6 +92,7 @@ kdump_wait_cpu_freeze(void) } return 1; } +#endif void machine_crash_shutdown(struct pt_regs *pt) @@ -116,6 +118,11 @@ machine_crash_shutdown(struct pt_regs *pt) static void machine_kdump_on_init(void) { + if (!ia64_kimage) { + printk(KERN_NOTICE "machine_kdump_on_init(): " + "kdump not configured\n"); + return; + } local_irq_disable(); kexec_disable_iosapic(); machine_kexec(ia64_kimage); @@ -132,11 +139,12 @@ kdump_cpu_freeze(struct unw_frame_info *info, void *arg) atomic_inc(&kdump_cpu_freezed); kdump_status[cpuid] = 1; mb(); - if (cpuid == 0) { - for (;;) - cpu_relax(); - } else +#ifdef CONFIG_HOTPLUG_CPU + if (cpuid != 0) ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]); +#endif + for (;;) + cpu_relax(); } static int diff --git a/arch/ia64/kernel/crash_dump.c b/arch/ia64/kernel/crash_dump.c index 83b8c91c1408..da60e90eeeb1 100644 --- a/arch/ia64/kernel/crash_dump.c +++ b/arch/ia64/kernel/crash_dump.c @@ -9,7 +9,8 @@ #include #include -#include +#include +#include /** * copy_oldmem_page - copy one page from "oldmem" diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 0b25a7d4e1e4..6c03928544c2 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c @@ -380,7 +380,7 @@ efi_get_pal_addr (void) #endif return __va(md->phys_addr); } - printk(KERN_WARNING "%s: no PAL-code memory-descriptor found", + printk(KERN_WARNING "%s: no PAL-code memory-descriptor found\n", __FUNCTION__); return NULL; } diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 15234ed3a341..e7873eeae448 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1610,5 +1610,7 @@ sys_call_table: data8 sys_sync_file_range // 1300 data8 sys_tee data8 sys_vmsplice + data8 sys_ni_syscall // reserved for move_pages + data8 sys_getcpu .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 0fc5fb7865cf..d6aab40c6416 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -925,6 +925,11 @@ iosapic_unregister_intr (unsigned int gsi) /* Clear the interrupt controller descriptor */ idesc->chip = &no_irq_type; +#ifdef CONFIG_SMP + /* Clear affinity */ + cpus_setall(idesc->affinity); +#endif + /* Clear the interrupt information */ memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c index e2ccc9f660c5..4f0f3b8c1ee2 100644 --- a/arch/ia64/kernel/machine_kexec.c +++ b/arch/ia64/kernel/machine_kexec.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -68,22 +69,10 @@ void machine_kexec_cleanup(struct kimage *image) { } -void machine_shutdown(void) -{ - int cpu; - - for_each_online_cpu(cpu) { - if (cpu != smp_processor_id()) - cpu_down(cpu); - } - kexec_disable_iosapic(); -} - /* * Do not allocate memory (or fail in any way) in machine_kexec(). * We are past the point of no return, committed to rebooting now. */ -extern void *efi_get_pal_addr(void); static void ia64_machine_kexec(struct unw_frame_info *info, void *arg) { struct kimage *image = arg; @@ -93,6 +82,7 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg) unsigned long vector; int ii; + BUG_ON(!image); if (image->type == KEXEC_TYPE_CRASH) { crash_save_this_cpu(); current->thread.ksp = (__u64)info->sw - 16; @@ -131,6 +121,7 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg) void machine_kexec(struct kimage *image) { + BUG_ON(!image); unw_init_running(ia64_machine_kexec, image); for(;;); } 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/kernel/process.c b/arch/ia64/kernel/process.c index 17685abaf496..ae96d4176995 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -803,6 +804,21 @@ cpu_halt (void) ia64_pal_halt(min_power_state); } +void machine_shutdown(void) +{ +#ifdef CONFIG_HOTPLUG_CPU + int cpu; + + for_each_online_cpu(cpu) { + if (cpu != smp_processor_id()) + cpu_down(cpu); + } +#endif +#ifdef CONFIG_KEXEC + kexec_disable_iosapic(); +#endif +} + void machine_restart (char *restart_cmd) { diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index aa705e46b974..3f8918782e0c 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -607,7 +607,7 @@ find_thread_for_addr (struct task_struct *child, unsigned long addr) */ list_for_each_safe(this, next, ¤t->children) { p = list_entry(this, struct task_struct, sibling); - if (p->mm != mm) + if (p->tgid != child->tgid) continue; if (thread_matches(p, addr)) { child = p; @@ -1405,6 +1405,7 @@ ptrace_disable (struct task_struct *child) struct ia64_psr *child_psr = ia64_psr(task_pt_regs(child)); /* make sure the single step/taken-branch trap bits are not set: */ + clear_tsk_thread_flag(child, TIF_SINGLESTEP); child_psr->ss = 0; child_psr->tb = 0; } @@ -1525,6 +1526,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data) * Make sure the single step/taken-branch trap bits * are not set: */ + clear_tsk_thread_flag(child, TIF_SINGLESTEP); ia64_psr(pt)->ss = 0; ia64_psr(pt)->tb = 0; @@ -1556,6 +1558,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data) goto out_tsk; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + set_tsk_thread_flag(child, TIF_SINGLESTEP); if (request == PTRACE_SINGLESTEP) { ia64_psr(pt)->ss = 1; } else { @@ -1595,13 +1598,9 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data) } -void +static void syscall_trace (void) { - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; - if (!(current->ptrace & PT_PTRACED)) - return; /* * The 0x80 provides a way for the tracing parent to * distinguish between a syscall stop and SIGTRAP delivery. @@ -1664,7 +1663,8 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3, audit_syscall_exit(success, result); } - if (test_thread_flag(TIF_SYSCALL_TRACE) + if ((test_thread_flag(TIF_SYSCALL_TRACE) + || test_thread_flag(TIF_SINGLESTEP)) && (current->ptrace & PT_PTRACED)) syscall_trace(); } diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index ad567b8d432e..83c2629e1c4c 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -569,34 +569,31 @@ show_cpuinfo (struct seq_file *m, void *v) { 1UL << 1, "spontaneous deferral"}, { 1UL << 2, "16-byte atomic ops" } }; - char features[128], *cp, sep; + char features[128], *cp, *sep; struct cpuinfo_ia64 *c = v; unsigned long mask; unsigned long proc_freq; - int i; + int i, size; mask = c->features; /* build the feature string: */ - memcpy(features, " standard", 10); + memcpy(features, "standard", 9); cp = features; - sep = 0; - for (i = 0; i < (int) ARRAY_SIZE(feature_bits); ++i) { + size = sizeof(features); + sep = ""; + for (i = 0; i < ARRAY_SIZE(feature_bits) && size > 1; ++i) { if (mask & feature_bits[i].mask) { - if (sep) - *cp++ = sep; - sep = ','; - *cp++ = ' '; - strcpy(cp, feature_bits[i].feature_name); - cp += strlen(feature_bits[i].feature_name); + cp += snprintf(cp, size, "%s%s", sep, + feature_bits[i].feature_name), + sep = ", "; mask &= ~feature_bits[i].mask; + size = sizeof(features) - (cp - features); } } - if (mask) { - /* print unknown features as a hex value: */ - if (sep) - *cp++ = sep; - sprintf(cp, " 0x%lx", mask); + if (mask && size > 1) { + /* print unknown features as a hex value */ + snprintf(cp, size, "%s0x%lx", sep, mask); } proc_freq = cpufreq_quick_get(cpunum); @@ -612,7 +609,7 @@ show_cpuinfo (struct seq_file *m, void *v) "model name : %s\n" "revision : %u\n" "archrev : %u\n" - "features :%s\n" /* don't change this---it _is_ right! */ + "features : %s\n" "cpu number : %lu\n" "cpu regs : %u\n" "cpu MHz : %lu.%06lu\n" diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index d6083a0936f4..8f3d0066f446 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -157,6 +157,7 @@ SECTIONS } #endif + . = ALIGN(8); __con_initcall_start = .; .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { *(.con_initcall.init) } diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c index 1e79551231b9..63e6d49c5813 100644 --- a/arch/ia64/mm/contig.c +++ b/arch/ia64/mm/contig.c @@ -30,47 +30,69 @@ static unsigned long max_gap; #endif /** - * show_mem - display a memory statistics summary + * show_mem - give short summary of memory stats * - * Just walks the pages in the system and describes where they're allocated. + * Shows a simple page count of reserved and used pages in the system. + * For discontig machines, it does this on a per-pgdat basis. */ -void -show_mem (void) +void show_mem(void) { - int i, total = 0, reserved = 0; - int shared = 0, cached = 0; + int i, total_reserved = 0; + int total_shared = 0, total_cached = 0; + unsigned long total_present = 0; + pg_data_t *pgdat; printk(KERN_INFO "Mem-info:\n"); show_free_areas(); - printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - i = max_mapnr; - for (i = 0; i < max_mapnr; i++) { - if (!pfn_valid(i)) { + printk(KERN_INFO "Node memory in pages:\n"); + for_each_online_pgdat(pgdat) { + unsigned long present; + unsigned long flags; + int shared = 0, cached = 0, reserved = 0; + + pgdat_resize_lock(pgdat, &flags); + present = pgdat->node_present_pages; + for(i = 0; i < pgdat->node_spanned_pages; i++) { + struct page *page; + if (pfn_valid(pgdat->node_start_pfn + i)) + page = pfn_to_page(pgdat->node_start_pfn + i); + else { #ifdef CONFIG_VIRTUAL_MEM_MAP - if (max_gap < LARGE_GAP) - continue; - i = vmemmap_find_next_valid_pfn(0, i) - 1; + if (max_gap < LARGE_GAP) + continue; #endif - continue; + i = vmemmap_find_next_valid_pfn(pgdat->node_id, + i) - 1; + continue; + } + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (page_count(page)) + shared += page_count(page)-1; } - total++; - if (PageReserved(mem_map+i)) - reserved++; - else if (PageSwapCache(mem_map+i)) - cached++; - else if (page_count(mem_map + i)) - shared += page_count(mem_map + i) - 1; + pgdat_resize_unlock(pgdat, &flags); + total_present += present; + total_reserved += reserved; + total_cached += cached; + total_shared += shared; + printk(KERN_INFO "Node %4d: RAM: %11ld, rsvd: %8d, " + "shrd: %10d, swpd: %10d\n", pgdat->node_id, + present, reserved, shared, cached); } - printk(KERN_INFO "%d pages of RAM\n", total); - printk(KERN_INFO "%d reserved pages\n", reserved); - printk(KERN_INFO "%d pages shared\n", shared); - printk(KERN_INFO "%d pages swap cached\n", cached); - printk(KERN_INFO "%ld pages in page table cache\n", + printk(KERN_INFO "%ld pages of RAM\n", total_present); + printk(KERN_INFO "%d reserved pages\n", total_reserved); + printk(KERN_INFO "%d pages shared\n", total_shared); + printk(KERN_INFO "%d pages swap cached\n", total_cached); + printk(KERN_INFO "Total of %ld pages in page table cache\n", pgtable_quicklist_total_size()); + printk(KERN_INFO "%d free buffer pages\n", nr_free_buffer_pages()); } + /* physical address where the bootmem map is located */ unsigned long bootmap_start; @@ -177,7 +199,7 @@ find_memory (void) #ifdef CONFIG_CRASH_DUMP /* If we are doing a crash dump, we still need to know the real mem - * size before original memory map is * reset. */ + * size before original memory map is reset. */ saved_max_pfn = max_pfn; #endif } diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index 96722cb1b49d..6eae596c509d 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c @@ -412,37 +412,6 @@ static void __init memory_less_nodes(void) return; } -#ifdef CONFIG_SPARSEMEM -/** - * register_sparse_mem - notify SPARSEMEM that this memory range exists. - * @start: physical start of range - * @end: physical end of range - * @arg: unused - * - * Simply calls SPARSEMEM to register memory section(s). - */ -static int __init register_sparse_mem(unsigned long start, unsigned long end, - void *arg) -{ - int nid; - - start = __pa(start) >> PAGE_SHIFT; - end = __pa(end) >> PAGE_SHIFT; - nid = early_pfn_to_nid(start); - memory_present(nid, start, end); - - return 0; -} - -static void __init arch_sparse_init(void) -{ - efi_memmap_walk(register_sparse_mem, NULL); - sparse_init(); -} -#else -#define arch_sparse_init() do {} while (0) -#endif - /** * find_memory - walk the EFI memory map and setup the bootmem allocator * @@ -473,6 +442,9 @@ void __init find_memory(void) node_clear(node, memory_less_mask); mem_data[node].min_pfn = ~0UL; } + + efi_memmap_walk(register_active_ranges, NULL); + /* * Initialize the boot memory maps in reverse order since that's * what the bootmem allocator expects @@ -506,6 +478,12 @@ void __init find_memory(void) max_pfn = max_low_pfn; find_initrd(); + +#ifdef CONFIG_CRASH_DUMP + /* If we are doing a crash dump, we still need to know the real mem + * size before original memory map is reset. */ + saved_max_pfn = max_pfn; +#endif } #ifdef CONFIG_SMP @@ -654,7 +632,6 @@ static __init int count_node_pages(unsigned long start, unsigned long len, int n { unsigned long end = start + len; - add_active_range(node, start >> PAGE_SHIFT, end >> PAGE_SHIFT); mem_data[node].num_physpages += len >> PAGE_SHIFT; if (start <= __pa(MAX_DMA_ADDRESS)) mem_data[node].num_dma_physpages += @@ -686,10 +663,11 @@ void __init paging_init(void) max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; - arch_sparse_init(); - efi_memmap_walk(filter_rsvd_memory, count_node_pages); + sparse_memory_present_with_active_regions(MAX_NUMNODES); + sparse_init(); + #ifdef CONFIG_VIRTUAL_MEM_MAP vmalloc_end -= PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) * sizeof(struct page)); diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 1373fae7657f..faaca21a3718 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -128,6 +129,25 @@ lazy_mmu_prot_update (pte_t pte) set_bit(PG_arch_1, &page->flags); /* mark page as clean */ } +/* + * Since DMA is i-cache coherent, any (complete) pages that were written via + * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to + * flush them when they get mapped into an executable vm-area. + */ +void +dma_mark_clean(void *addr, size_t size) +{ + unsigned long pg_addr, end; + + pg_addr = PAGE_ALIGN((unsigned long) addr); + end = (unsigned long) addr + size; + while (pg_addr + PAGE_SIZE <= end) { + struct page *page = virt_to_page(pg_addr); + set_bit(PG_arch_1, &page->flags); + pg_addr += PAGE_SIZE; + } +} + inline void ia64_set_rbs_bot (void) { @@ -595,13 +615,27 @@ find_largest_hole (u64 start, u64 end, void *arg) return 0; } +#endif /* CONFIG_VIRTUAL_MEM_MAP */ + int __init register_active_ranges(u64 start, u64 end, void *arg) { - add_active_range(0, __pa(start) >> PAGE_SHIFT, __pa(end) >> PAGE_SHIFT); + int nid = paddr_to_nid(__pa(start)); + + if (nid < 0) + nid = 0; +#ifdef CONFIG_KEXEC + if (start > crashk_res.start && start < crashk_res.end) + start = crashk_res.end; + if (end > crashk_res.start && end < crashk_res.end) + end = crashk_res.start; +#endif + + if (start < end) + add_active_range(nid, __pa(start) >> PAGE_SHIFT, + __pa(end) >> PAGE_SHIFT); return 0; } -#endif /* CONFIG_VIRTUAL_MEM_MAP */ static int __init count_reserved_pages (u64 start, u64 end, void *arg) diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c index abca6bd7962f..fcf7f93c4b61 100644 --- a/arch/ia64/sn/kernel/huberror.c +++ b/arch/ia64/sn/kernel/huberror.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000,2002-2005 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000,2002-2007 Silicon Graphics, Inc. All rights reserved. */ #include @@ -38,12 +38,20 @@ static irqreturn_t hub_eint_handler(int irq, void *arg) (u64) nasid, 0, 0, 0, 0, 0, 0); if ((int)ret_stuff.v0) - panic("hubii_eint_handler(): Fatal TIO Error"); + panic("%s: Fatal %s Error", __FUNCTION__, + ((nasid & 1) ? "TIO" : "HUBII")); if (!(nasid & 1)) /* Not a TIO, handle CRB errors */ (void)hubiio_crb_error_handler(hubdev_info); - } else - bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid))); + } else + if (nasid & 1) { /* TIO errors */ + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT, + (u64) nasid, 0, 0, 0, 0, 0, 0); + + if ((int)ret_stuff.v0) + panic("%s: Fatal TIO Error", __FUNCTION__); + } else + bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid))); return IRQ_HANDLED; } diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c index cb96b4ea7df6..8c331ca6e5c9 100644 --- a/arch/ia64/sn/kernel/io_acpi_init.c +++ b/arch/ia64/sn/kernel/io_acpi_init.c @@ -13,6 +13,7 @@ #include #include "xtalk/hubdev.h" #include +#include /* @@ -31,6 +32,12 @@ struct acpi_vendor_uuid sn_uuid = { 0xa2, 0x7c, 0x08, 0x00, 0x69, 0x13, 0xea, 0x51 }, }; +struct sn_pcidev_match { + u8 bus; + unsigned int devfn; + acpi_handle handle; +}; + /* * Perform the early IO init in PROM. */ @@ -119,9 +126,11 @@ sn_get_bussoft_ptr(struct pci_bus *bus) status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, &sn_uuid, &buffer); if (ACPI_FAILURE(status)) { - printk(KERN_ERR "get_acpi_pcibus_ptr: " - "get_acpi_bussoft_info() failed: %d\n", - status); + printk(KERN_ERR "%s: " + "acpi_get_vendor_resource() failed (0x%x) for: ", + __FUNCTION__, status); + acpi_ns_print_node_pathname(handle, NULL); + printk("\n"); return NULL; } resource = buffer.pointer; @@ -130,8 +139,8 @@ sn_get_bussoft_ptr(struct pci_bus *bus) if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != sizeof(struct pcibus_bussoft *)) { printk(KERN_ERR - "get_acpi_bussoft_ptr: Invalid vendor data " - "length %d\n", vendor->byte_length); + "%s: Invalid vendor data length %d\n", + __FUNCTION__, vendor->byte_length); kfree(buffer.pointer); return NULL; } @@ -143,34 +152,254 @@ sn_get_bussoft_ptr(struct pci_bus *bus) } /* - * sn_acpi_bus_fixup + * sn_extract_device_info - Extract the pcidev_info and the sn_irq_info + * pointers from the vendor resource using the + * provided acpi handle, and copy the structures + * into the argument buffers. */ -void -sn_acpi_bus_fixup(struct pci_bus *bus) +static int +sn_extract_device_info(acpi_handle handle, struct pcidev_info **pcidev_info, + struct sn_irq_info **sn_irq_info) { - struct pci_dev *pci_dev = NULL; - struct pcibus_bussoft *prom_bussoft_ptr; - extern void sn_common_bus_fixup(struct pci_bus *, - struct pcibus_bussoft *); + u64 addr; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct sn_irq_info *irq_info, *irq_info_prom; + struct pcidev_info *pcidev_ptr, *pcidev_prom_ptr; + struct acpi_resource *resource; + int ret = 0; + acpi_status status; + struct acpi_resource_vendor_typed *vendor; - if (!bus->parent) { /* If root bus */ - prom_bussoft_ptr = sn_get_bussoft_ptr(bus); - if (prom_bussoft_ptr == NULL) { - printk(KERN_ERR - "sn_pci_fixup_bus: 0x%04x:0x%02x Unable to " - "obtain prom_bussoft_ptr\n", - pci_domain_nr(bus), bus->number); - return; + /* + * The pointer to this device's pcidev_info structure in + * the PROM, is in the vendor resource. + */ + status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS, + &sn_uuid, &buffer); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR + "%s: acpi_get_vendor_resource() failed (0x%x) for: ", + __FUNCTION__, status); + acpi_ns_print_node_pathname(handle, NULL); + printk("\n"); + return 1; + } + + resource = buffer.pointer; + vendor = &resource->data.vendor_typed; + if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) != + sizeof(struct pci_devdev_info *)) { + printk(KERN_ERR + "%s: Invalid vendor data length: %d for: ", + __FUNCTION__, vendor->byte_length); + acpi_ns_print_node_pathname(handle, NULL); + printk("\n"); + ret = 1; + goto exit; + } + + pcidev_ptr = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL); + if (!pcidev_ptr) + panic("%s: Unable to alloc memory for pcidev_info", __FUNCTION__); + + memcpy(&addr, vendor->byte_data, sizeof(struct pcidev_info *)); + pcidev_prom_ptr = __va(addr); + memcpy(pcidev_ptr, pcidev_prom_ptr, sizeof(struct pcidev_info)); + + /* Get the IRQ info */ + irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); + if (!irq_info) + panic("%s: Unable to alloc memory for sn_irq_info", __FUNCTION__); + + if (pcidev_ptr->pdi_sn_irq_info) { + irq_info_prom = __va(pcidev_ptr->pdi_sn_irq_info); + memcpy(irq_info, irq_info_prom, sizeof(struct sn_irq_info)); + } + + *pcidev_info = pcidev_ptr; + *sn_irq_info = irq_info; + +exit: + kfree(buffer.pointer); + return ret; +} + +static unsigned int +get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle) +{ + unsigned long adr; + acpi_handle child; + unsigned int devfn; + int function; + acpi_handle parent; + int slot; + acpi_status status; + + /* + * Do an upward search to find the root bus device, and + * obtain the host devfn from the previous child device. + */ + child = device_handle; + while (child) { + status = acpi_get_parent(child, &parent); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR "%s: acpi_get_parent() failed " + "(0x%x) for: ", __FUNCTION__, status); + acpi_ns_print_node_pathname(child, NULL); + printk("\n"); + panic("%s: Unable to find host devfn\n", __FUNCTION__); } - sn_common_bus_fixup(bus, prom_bussoft_ptr); + if (parent == rootbus_handle) + break; + child = parent; } - list_for_each_entry(pci_dev, &bus->devices, bus_list) { - sn_pci_fixup_slot(pci_dev); + if (!child) { + printk(KERN_ERR "%s: Unable to find root bus for: ", + __FUNCTION__); + acpi_ns_print_node_pathname(device_handle, NULL); + printk("\n"); + BUG(); } + + status = acpi_evaluate_integer(child, METHOD_NAME__ADR, NULL, &adr); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR "%s: Unable to get _ADR (0x%x) for: ", + __FUNCTION__, status); + acpi_ns_print_node_pathname(child, NULL); + printk("\n"); + panic("%s: Unable to find host devfn\n", __FUNCTION__); + } + + slot = (adr >> 16) & 0xffff; + function = adr & 0xffff; + devfn = PCI_DEVFN(slot, function); + return devfn; } /* - * sn_acpi_slot_fixup - Perform any SN specific slot fixup. + * find_matching_device - Callback routine to find the ACPI device + * that matches up with our pci_dev device. + * Matching is done on bus number and devfn. + * To find the bus number for a particular + * ACPI device, we must look at the _BBN method + * of its parent. + */ +static acpi_status +find_matching_device(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + unsigned long bbn = -1; + unsigned long adr; + acpi_handle parent = NULL; + acpi_status status; + unsigned int devfn; + int function; + int slot; + struct sn_pcidev_match *info = context; + + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, + &adr); + if (ACPI_SUCCESS(status)) { + status = acpi_get_parent(handle, &parent); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR + "%s: acpi_get_parent() failed (0x%x) for: ", + __FUNCTION__, status); + acpi_ns_print_node_pathname(handle, NULL); + printk("\n"); + return AE_OK; + } + status = acpi_evaluate_integer(parent, METHOD_NAME__BBN, + NULL, &bbn); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR + "%s: Failed to find _BBN in parent of: ", + __FUNCTION__); + acpi_ns_print_node_pathname(handle, NULL); + printk("\n"); + return AE_OK; + } + + slot = (adr >> 16) & 0xffff; + function = adr & 0xffff; + devfn = PCI_DEVFN(slot, function); + if ((info->devfn == devfn) && (info->bus == bbn)) { + /* We have a match! */ + info->handle = handle; + return 1; + } + } + return AE_OK; +} + +/* + * sn_acpi_get_pcidev_info - Search ACPI namespace for the acpi + * device matching the specified pci_dev, + * and return the pcidev info and irq info. + */ +int +sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info, + struct sn_irq_info **sn_irq_info) +{ + unsigned int host_devfn; + struct sn_pcidev_match pcidev_match; + acpi_handle rootbus_handle; + unsigned long segment; + acpi_status status; + + rootbus_handle = PCI_CONTROLLER(dev)->acpi_handle; + status = acpi_evaluate_integer(rootbus_handle, METHOD_NAME__SEG, NULL, + &segment); + if (ACPI_SUCCESS(status)) { + if (segment != pci_domain_nr(dev)) { + printk(KERN_ERR + "%s: Segment number mismatch, 0x%lx vs 0x%x for: ", + __FUNCTION__, segment, pci_domain_nr(dev)); + acpi_ns_print_node_pathname(rootbus_handle, NULL); + printk("\n"); + return 1; + } + } else { + printk(KERN_ERR "%s: Unable to get __SEG from: ", + __FUNCTION__); + acpi_ns_print_node_pathname(rootbus_handle, NULL); + printk("\n"); + return 1; + } + + /* + * We want to search all devices in this segment/domain + * of the ACPI namespace for the matching ACPI device, + * which holds the pcidev_info pointer in its vendor resource. + */ + pcidev_match.bus = dev->bus->number; + pcidev_match.devfn = dev->devfn; + pcidev_match.handle = NULL; + + acpi_walk_namespace(ACPI_TYPE_DEVICE, rootbus_handle, ACPI_UINT32_MAX, + find_matching_device, &pcidev_match, NULL); + + if (!pcidev_match.handle) { + printk(KERN_ERR + "%s: Could not find matching ACPI device for %s.\n", + __FUNCTION__, pci_name(dev)); + return 1; + } + + if (sn_extract_device_info(pcidev_match.handle, pcidev_info, sn_irq_info)) + return 1; + + /* Build up the pcidev_info.pdi_slot_host_handle */ + host_devfn = get_host_devfn(pcidev_match.handle, rootbus_handle); + (*pcidev_info)->pdi_slot_host_handle = + ((unsigned long) pci_domain_nr(dev) << 40) | + /* bus == 0 */ + host_devfn; + return 0; +} + +/* + * sn_acpi_slot_fixup - Obtain the pcidev_info and sn_irq_info. + * Perform any SN specific slot fixup. * At present there does not appear to be * any generic way to handle a ROM image * that has been shadowed by the PROM, so @@ -179,11 +408,18 @@ sn_acpi_bus_fixup(struct pci_bus *bus) */ void -sn_acpi_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info) +sn_acpi_slot_fixup(struct pci_dev *dev) { void __iomem *addr; + struct pcidev_info *pcidev_info = NULL; + struct sn_irq_info *sn_irq_info = NULL; size_t size; + if (sn_acpi_get_pcidev_info(dev, &pcidev_info, &sn_irq_info)) { + panic("%s: Failure obtaining pcidev_info for %s\n", + __FUNCTION__, pci_name(dev)); + } + if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) { /* * A valid ROM image exists and has been shadowed by the @@ -200,8 +436,11 @@ sn_acpi_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info) (unsigned long) addr + size; dev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_BIOS_COPY; } + sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info); } +EXPORT_SYMBOL(sn_acpi_slot_fixup); + static struct acpi_driver acpi_sn_hubdev_driver = { .name = "SGI HUBDEV Driver", .ids = "SGIHUB,SGITIO", @@ -211,6 +450,33 @@ static struct acpi_driver acpi_sn_hubdev_driver = { }; +/* + * sn_acpi_bus_fixup - Perform SN specific setup of software structs + * (pcibus_bussoft, pcidev_info) and hardware + * registers, for the specified bus and devices under it. + */ +void +sn_acpi_bus_fixup(struct pci_bus *bus) +{ + struct pci_dev *pci_dev = NULL; + struct pcibus_bussoft *prom_bussoft_ptr; + + if (!bus->parent) { /* If root bus */ + prom_bussoft_ptr = sn_get_bussoft_ptr(bus); + if (prom_bussoft_ptr == NULL) { + printk(KERN_ERR + "%s: 0x%04x:0x%02x Unable to " + "obtain prom_bussoft_ptr\n", + __FUNCTION__, pci_domain_nr(bus), bus->number); + return; + } + sn_common_bus_fixup(bus, prom_bussoft_ptr); + } + list_for_each_entry(pci_dev, &bus->devices, bus_list) { + sn_acpi_slot_fixup(pci_dev); + } +} + /* * sn_io_acpi_init - PROM has ACPI support for IO, defining at a minimum the * nodes and root buses in the DSDT. As a result, bus scanning diff --git a/arch/ia64/sn/kernel/io_common.c b/arch/ia64/sn/kernel/io_common.c index d4dd8f4b6b8d..d48bcd83253c 100644 --- a/arch/ia64/sn/kernel/io_common.c +++ b/arch/ia64/sn/kernel/io_common.c @@ -26,14 +26,10 @@ #include #include #include +#include "acpi/acglobal.h" extern void sn_init_cpei_timer(void); extern void register_sn_procfs(void); -extern void sn_acpi_bus_fixup(struct pci_bus *); -extern void sn_bus_fixup(struct pci_bus *); -extern void sn_acpi_slot_fixup(struct pci_dev *, struct pcidev_info *); -extern void sn_more_slot_fixup(struct pci_dev *, struct pcidev_info *); -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); @@ -48,6 +44,9 @@ struct sysdata_el { int sn_ioif_inited; /* SN I/O infrastructure initialized? */ +int sn_acpi_rev; /* SN ACPI revision */ +EXPORT_SYMBOL_GPL(sn_acpi_rev); + struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES]; /* indexed by asic type */ /* @@ -98,25 +97,6 @@ sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num, return ret_stuff.status; } -/* - * Retrieve the pci device information given the bus and device|function number. - */ -static inline u64 -sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, - u64 sn_irq_info) -{ - struct ia64_sal_retval ret_stuff; - ret_stuff.status = 0; - ret_stuff.v0 = 0; - - SAL_CALL_NOLOCK(ret_stuff, - (u64) SN_SAL_IOIF_GET_PCIDEV_INFO, - (u64) segment, (u64) bus_number, (u64) devfn, - (u64) pci_dev, - sn_irq_info, 0, 0); - return ret_stuff.v0; -} - /* * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified * device. @@ -249,50 +229,25 @@ void sn_pci_unfixup_slot(struct pci_dev *dev) } /* - * sn_pci_fixup_slot() - This routine sets up a slot's resources consistent - * with the Linux PCI abstraction layer. Resources - * acquired from our PCI provider include PIO maps - * to BAR space and interrupt objects. + * sn_pci_fixup_slot() */ -void sn_pci_fixup_slot(struct pci_dev *dev) +void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *pcidev_info, + struct sn_irq_info *sn_irq_info) { int segment = pci_domain_nr(dev->bus); - int status = 0; struct pcibus_bussoft *bs; - struct pci_bus *host_pci_bus; - struct pci_dev *host_pci_dev; - struct pcidev_info *pcidev_info; - struct sn_irq_info *sn_irq_info; - unsigned int bus_no, devfn; + struct pci_bus *host_pci_bus; + struct pci_dev *host_pci_dev; + unsigned int bus_no, devfn; pci_dev_get(dev); /* for the sysdata pointer */ - pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL); - if (!pcidev_info) - BUG(); /* Cannot afford to run out of memory */ - - sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); - if (!sn_irq_info) - BUG(); /* Cannot afford to run out of memory */ - - /* Call to retrieve pci device information needed by kernel. */ - status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number, - dev->devfn, - (u64) __pa(pcidev_info), - (u64) __pa(sn_irq_info)); - if (status) - BUG(); /* Cannot get platform pci device information */ /* Add pcidev_info to list in pci_controller.platform_data */ list_add_tail(&pcidev_info->pdi_list, &(SN_PLATFORM_DATA(dev->bus)->pcidev_info)); - - if (SN_ACPI_BASE_SUPPORT()) - sn_acpi_slot_fixup(dev, pcidev_info); - else - sn_more_slot_fixup(dev, pcidev_info); /* * Using the PROMs values for the PCI host bus, get the Linux - * PCI host_pci_dev struct and set up host bus linkages + * PCI host_pci_dev struct and set up host bus linkages */ bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff; @@ -489,11 +444,6 @@ void sn_generate_path(struct pci_bus *pci_bus, char *address) sprintf(address, "%s^%d", address, geo_slot(geoid)); } -/* - * sn_pci_fixup_bus() - Perform SN specific setup of software structs - * (pcibus_bussoft, pcidev_info) and hardware - * registers, for the specified bus and devices under it. - */ void __devinit sn_pci_fixup_bus(struct pci_bus *bus) { @@ -519,6 +469,15 @@ sn_io_early_init(void) if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM()) return 0; + /* we set the acpi revision to that of the DSDT table OEM rev. */ + { + struct acpi_table_header *header = NULL; + + acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header); + BUG_ON(header == NULL); + sn_acpi_rev = header->oem_revision; + } + /* * prime sn_pci_provider[]. Individial provider init routines will * override their respective default entries. @@ -544,8 +503,12 @@ sn_io_early_init(void) register_sn_procfs(); #endif - printk(KERN_INFO "ACPI DSDT OEM Rev 0x%x\n", - acpi_gbl_DSDT->oem_revision); + { + struct acpi_table_header *header; + (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header); + printk(KERN_INFO "ACPI DSDT OEM Rev 0x%x\n", + header->oem_revision); + } if (SN_ACPI_BASE_SUPPORT()) sn_io_acpi_init(); else @@ -605,7 +568,6 @@ sn_io_late_init(void) fs_initcall(sn_io_late_init); -EXPORT_SYMBOL(sn_pci_fixup_slot); EXPORT_SYMBOL(sn_pci_unfixup_slot); EXPORT_SYMBOL(sn_bus_store_sysdata); EXPORT_SYMBOL(sn_bus_free_sysdata); diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 9ad843e0383b..600be3ebae05 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -56,6 +56,25 @@ static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address) return ret_stuff.v0; } +/* + * Retrieve the pci device information given the bus and device|function number. + */ +static inline u64 +sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, + u64 sn_irq_info) +{ + struct ia64_sal_retval ret_stuff; + ret_stuff.status = 0; + ret_stuff.v0 = 0; + + SAL_CALL_NOLOCK(ret_stuff, + (u64) SN_SAL_IOIF_GET_PCIDEV_INFO, + (u64) segment, (u64) bus_number, (u64) devfn, + (u64) pci_dev, + sn_irq_info, 0, 0); + return ret_stuff.v0; +} + /* * sn_fixup_ionodes() - This routine initializes the HUB data structure for @@ -172,18 +191,40 @@ sn_pci_window_fixup(struct pci_dev *dev, unsigned int count, } /* - * sn_more_slot_fixup() - We are not running with an ACPI capable PROM, + * sn_io_slot_fixup() - We are not running with an ACPI capable PROM, * and need to convert the pci_dev->resource * 'start' and 'end' addresses to mapped addresses, * and setup the pci_controller->window array entries. */ void -sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info) +sn_io_slot_fixup(struct pci_dev *dev) { unsigned int count = 0; int idx; s64 pci_addrs[PCI_ROM_RESOURCE + 1]; unsigned long addr, end, size, start; + struct pcidev_info *pcidev_info; + struct sn_irq_info *sn_irq_info; + int status; + + pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL); + if (!pcidev_info) + panic("%s: Unable to alloc memory for pcidev_info", __FUNCTION__); + + sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); + if (!sn_irq_info) + panic("%s: Unable to alloc memory for sn_irq_info", __FUNCTION__); + + /* Call to retrieve pci device information needed by kernel. */ + status = sal_get_pcidev_info((u64) pci_domain_nr(dev), + (u64) dev->bus->number, + dev->devfn, + (u64) __pa(pcidev_info), + (u64) __pa(sn_irq_info)); + + if (status) + BUG(); /* Cannot get platform pci device information */ + /* Copy over PIO Mapped Addresses */ for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { @@ -219,8 +260,12 @@ sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info) */ if (count > 0) sn_pci_window_fixup(dev, count, pci_addrs); + + sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info); } +EXPORT_SYMBOL(sn_io_slot_fixup); + /* * sn_pci_controller_fixup() - This routine sets up a bus's resources * consistent with the Linux PCI abstraction layer. @@ -272,9 +317,6 @@ sn_bus_fixup(struct pci_bus *bus) { struct pci_dev *pci_dev = NULL; struct pcibus_bussoft *prom_bussoft_ptr; - extern void sn_common_bus_fixup(struct pci_bus *, - struct pcibus_bussoft *); - if (!bus->parent) { /* If root bus */ prom_bussoft_ptr = PCI_CONTROLLER(bus)->platform_data; @@ -291,7 +333,7 @@ sn_bus_fixup(struct pci_bus *bus) prom_bussoft_ptr->bs_legacy_mem); } list_for_each_entry(pci_dev, &bus->devices, bus_list) { - sn_pci_fixup_slot(pci_dev); + sn_io_slot_fixup(pci_dev); } } diff --git a/arch/ia64/sn/kernel/iomv.c b/arch/ia64/sn/kernel/iomv.c index 4aa4f301d56d..ab7e2fd40798 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. @@ -26,9 +26,10 @@ * @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*(). */ + void *sn_io_addr(unsigned long port) { if (!IS_RUNNING_ON_SIMULATOR()) { diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c index b3a435fd70fb..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_data(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/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c index 6846dc9b432d..04a8256017eb 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c @@ -20,7 +20,8 @@ #include "xtalk/hubdev.h" int -sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp) +sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp, + char **ssdt) { struct ia64_sal_retval ret_stuff; u64 busnum; @@ -32,7 +33,8 @@ sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp) segment = soft->pbi_buscommon.bs_persist_segment; busnum = soft->pbi_buscommon.bs_persist_busnum; SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, segment, - busnum, (u64) device, (u64) resp, 0, 0, 0); + busnum, (u64) device, (u64) resp, (u64)ia64_tpa(ssdt), + 0, 0); return (int)ret_stuff.v0; } diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index bbd386f572d9..44a0224c32dd 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -575,6 +575,7 @@ config SGI_IP27 select DMA_IP27 select EARLY_PRINTK select HW_HAS_PCI + select NR_CPUS_DEFAULT_64 select PCI_DOMAINS select SYS_HAS_CPU_R10000 select SYS_SUPPORTS_64BIT_KERNEL @@ -612,6 +613,7 @@ config SIBYTE_BIGSUR bool "Sibyte BCM91480B-BigSur" select BOOT_ELF32 select DMA_COHERENT + select NR_CPUS_DEFAULT_4 select PCI_DOMAINS select SIBYTE_BCM1x80 select SWAP_IO_SPACE @@ -623,6 +625,7 @@ config SIBYTE_SWARM bool "Sibyte BCM91250A-SWARM" select BOOT_ELF32 select DMA_COHERENT + select NR_CPUS_DEFAULT_2 select SIBYTE_SB1250 select SWAP_IO_SPACE select SYS_HAS_CPU_SB1 @@ -635,6 +638,7 @@ config SIBYTE_SENTOSA depends on EXPERIMENTAL select BOOT_ELF32 select DMA_COHERENT + select NR_CPUS_DEFAULT_2 select SIBYTE_SB1250 select SWAP_IO_SPACE select SYS_HAS_CPU_SB1 @@ -668,6 +672,7 @@ config SIBYTE_PTSWARM depends on EXPERIMENTAL select BOOT_ELF32 select DMA_COHERENT + select NR_CPUS_DEFAULT_2 select SIBYTE_SB1250 select SWAP_IO_SPACE select SYS_HAS_CPU_SB1 @@ -680,6 +685,7 @@ config SIBYTE_LITTLESUR depends on EXPERIMENTAL select BOOT_ELF32 select DMA_COHERENT + select NR_CPUS_DEFAULT_2 select SIBYTE_SB1250 select SWAP_IO_SPACE select SYS_HAS_CPU_SB1 @@ -790,23 +796,6 @@ config TOSHIBA_RBTX4938 endchoice -config KEXEC - bool "Kexec system call (EXPERIMENTAL)" - depends on EXPERIMENTAL - help - kexec is a system call that implements the ability to shutdown your - current kernel, and to start another kernel. It is like a reboot - but it is indepedent of the system firmware. And like a reboot - you can start any kernel with it, not just Linux. - - The name comes from the similiarity to the exec system call. - - It is an ongoing process to be certain the hardware in a machine - is properly shutdown, so do not be surprised if this code does not - initially work for you. It may help to enable device hotplugging - support. As of this writing the exact hardware interface is - strongly in flux, so no good recommendation can be made. - source "arch/mips/ddb5xxx/Kconfig" source "arch/mips/gt64120/ev64120/Kconfig" source "arch/mips/jazz/Kconfig" @@ -1541,6 +1530,8 @@ config MIPS_MT_SMTC select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_SRS select MIPS_MT + select NR_CPUS_DEFAULT_2 + select NR_CPUS_DEFAULT_8 select SMP select SYS_SUPPORTS_SMP help @@ -1756,13 +1747,34 @@ config SMP config SYS_SUPPORTS_SMP bool +config NR_CPUS_DEFAULT_2 + bool + +config NR_CPUS_DEFAULT_4 + bool + +config NR_CPUS_DEFAULT_8 + bool + +config NR_CPUS_DEFAULT_16 + bool + +config NR_CPUS_DEFAULT_32 + bool + +config NR_CPUS_DEFAULT_64 + bool + config NR_CPUS int "Maximum number of CPUs (2-64)" range 2 64 depends on SMP - default "64" if SGI_IP27 - default "2" - default "8" if MIPS_MT_SMTC + default "2" if NR_CPUS_DEFAULT_2 + default "4" if NR_CPUS_DEFAULT_4 + default "8" if NR_CPUS_DEFAULT_8 + default "16" if NR_CPUS_DEFAULT_16 + default "32" if NR_CPUS_DEFAULT_32 + default "64" if NR_CPUS_DEFAULT_64 help This allows you to specify the maximum number of CPUs which this kernel will support. The maximum supported value is 32 for 32-bit @@ -1859,6 +1871,40 @@ config MIPS_INSANE_LARGE This will result in additional memory usage, so it is not recommended for normal users. +config KEXEC + bool "Kexec system call (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + kexec is a system call that implements the ability to shutdown your + current kernel, and to start another kernel. It is like a reboot + but it is indepedent of the system firmware. And like a reboot + you can start any kernel with it, not just Linux. + + The name comes from the similiarity to the exec system call. + + It is an ongoing process to be certain the hardware in a machine + is properly shutdown, so do not be surprised if this code does not + initially work for you. It may help to enable device hotplugging + support. As of this writing the exact hardware interface is + strongly in flux, so no good recommendation can be made. + +config SECCOMP + bool "Enable seccomp to safely compute untrusted bytecode" + depends on PROC_FS && BROKEN + default y + help + This kernel feature is useful for number crunching applications + that may need to compute untrusted bytecode during their + execution. By using pipes or other transports made available to + the process as file descriptors supporting the read/write + syscalls, it's possible to isolate those applications in + their own address space using seccomp. Once seccomp is + enabled via /proc//seccomp, it cannot be disabled + and the task is only allowed to execute a few safe syscalls + defined by each seccomp mode. + + If unsure, say Y. Only embedded should say N here. + endmenu config RWSEM_GENERIC_SPINLOCK @@ -2025,23 +2071,6 @@ config BINFMT_ELF32 bool default y if MIPS32_O32 || MIPS32_N32 -config SECCOMP - bool "Enable seccomp to safely compute untrusted bytecode" - depends on PROC_FS && BROKEN - default y - help - This kernel feature is useful for number crunching applications - that may need to compute untrusted bytecode during their - execution. By using pipes or other transports made available to - the process as file descriptors supporting the read/write - syscalls, it's possible to isolate those applications in - their own address space using seccomp. Once seccomp is - enabled via /proc//seccomp, it cannot be disabled - and the task is only allowed to execute a few safe syscalls - defined by each seccomp mode. - - If unsure, say Y. Only embedded should say N here. - config PM bool "Power Management support (EXPERIMENTAL)" depends on EXPERIMENTAL && SOC_AU1X00 diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug index 5d6afb52d904..9351f1c04a9d 100644 --- a/arch/mips/Kconfig.debug +++ b/arch/mips/Kconfig.debug @@ -22,10 +22,10 @@ config CMDLINE string "Default kernel command string" default "" help - On some platforms, there is currently no way for the boot loader to - pass arguments to the kernel. For these platforms, you can supply - some command-line options at build time by entering them here. In - other cases you can specify kernel args so that you don't have + On some platforms, there is currently no way for the boot loader to + pass arguments to the kernel. For these platforms, you can supply + some command-line options at build time by entering them here. In + other cases you can specify kernel args so that you don't have to set them up in board prom initialization routines. config DEBUG_STACK_USAGE diff --git a/arch/mips/arc/identify.c b/arch/mips/arc/identify.c index 3ba7c47f9f23..4b907369b0f9 100644 --- a/arch/mips/arc/identify.c +++ b/arch/mips/arc/identify.c @@ -77,7 +77,7 @@ static struct smatch * __init string_to_mach(const char *s) { int i; - for (i = 0; i < (sizeof(mach_table) / sizeof (mach_table[0])); i++) { + for (i = 0; i < ARRAY_SIZE(mach_table); i++) { if (!strcmp(s, mach_table[i].arcname)) return &mach_table[i]; } diff --git a/arch/mips/arc/memory.c b/arch/mips/arc/memory.c index 8a9ef58cc399..456cb81a32d9 100644 --- a/arch/mips/arc/memory.c +++ b/arch/mips/arc/memory.c @@ -141,30 +141,20 @@ void __init prom_meminit(void) } } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - unsigned long freed = 0; unsigned long addr; int i; if (prom_flags & PROM_FLAG_DONT_FREE_TEMP) - return 0; + return; for (i = 0; i < boot_mem_map.nr_map; i++) { if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) continue; addr = boot_mem_map.map[i].addr; - while (addr < boot_mem_map.map[i].addr - + boot_mem_map.map[i].size) { - ClearPageReserved(virt_to_page(__va(addr))); - init_page_count(virt_to_page(__va(addr))); - free_page((unsigned long)__va(addr)); - addr += PAGE_SIZE; - freed += PAGE_SIZE; - } + free_init_pages("prom memory", + addr, addr + boot_mem_map.map[i].size); } - printk(KERN_INFO "Freeing prom memory: %ldkb freed\n", freed >> 10); - - return freed; } diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c index 9cf7b6715836..ea6e99fbe2f7 100644 --- a/arch/mips/au1000/common/irq.c +++ b/arch/mips/au1000/common/irq.c @@ -233,7 +233,7 @@ void restore_local_and_enable(int controller, unsigned long mask) static struct irq_chip rise_edge_irq_type = { - .typename = "Au1000 Rise Edge", + .name = "Au1000 Rise Edge", .ack = mask_and_ack_rise_edge_irq, .mask = local_disable_irq, .mask_ack = mask_and_ack_rise_edge_irq, @@ -242,7 +242,7 @@ static struct irq_chip rise_edge_irq_type = { }; static struct irq_chip fall_edge_irq_type = { - .typename = "Au1000 Fall Edge", + .name = "Au1000 Fall Edge", .ack = mask_and_ack_fall_edge_irq, .mask = local_disable_irq, .mask_ack = mask_and_ack_fall_edge_irq, @@ -251,7 +251,7 @@ static struct irq_chip fall_edge_irq_type = { }; static struct irq_chip either_edge_irq_type = { - .typename = "Au1000 Rise or Fall Edge", + .name = "Au1000 Rise or Fall Edge", .ack = mask_and_ack_either_edge_irq, .mask = local_disable_irq, .mask_ack = mask_and_ack_either_edge_irq, @@ -260,7 +260,7 @@ static struct irq_chip either_edge_irq_type = { }; static struct irq_chip level_irq_type = { - .typename = "Au1000 Level", + .name = "Au1000 Level", .ack = mask_and_ack_level_irq, .mask = local_disable_irq, .mask_ack = mask_and_ack_level_irq, diff --git a/arch/mips/au1000/common/pci.c b/arch/mips/au1000/common/pci.c index 9f8ce08e173b..6c25e6c09f78 100644 --- a/arch/mips/au1000/common/pci.c +++ b/arch/mips/au1000/common/pci.c @@ -76,13 +76,17 @@ static int __init au1x_pci_setup(void) } #ifdef CONFIG_DMA_NONCOHERENT - /* - * Set the NC bit in controller for Au1500 pre-AC silicon - */ - u32 prid = read_c0_prid(); - if ( (prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) { - au_writel( 1<<16 | au_readl(Au1500_PCI_CFG), Au1500_PCI_CFG); - printk("Non-coherent PCI accesses enabled\n"); + { + /* + * Set the NC bit in controller for Au1500 pre-AC silicon + */ + u32 prid = read_c0_prid(); + + if ((prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) { + au_writel((1 << 16) | au_readl(Au1500_PCI_CFG), + Au1500_PCI_CFG); + printk("Non-coherent PCI accesses enabled\n"); + } } #endif diff --git a/arch/mips/au1000/common/prom.c b/arch/mips/au1000/common/prom.c index 6fce60af005d..a8637cdb5b4b 100644 --- a/arch/mips/au1000/common/prom.c +++ b/arch/mips/au1000/common/prom.c @@ -149,9 +149,8 @@ int get_ethernet_addr(char *ethernet_addr) return 0; } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } EXPORT_SYMBOL(prom_getcmdline); diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c index 919172db560c..13fe187f35d6 100644 --- a/arch/mips/au1000/common/setup.c +++ b/arch/mips/au1000/common/setup.c @@ -141,17 +141,20 @@ void __init plat_mem_setup(void) /* This routine should be valid for all Au1x based boards */ phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size) { - u32 start, end; - /* Don't fixup 36 bit addresses */ - if ((phys_addr >> 32) != 0) return phys_addr; + if ((phys_addr >> 32) != 0) + return phys_addr; #ifdef CONFIG_PCI - start = (u32)Au1500_PCI_MEM_START; - end = (u32)Au1500_PCI_MEM_END; - /* check for pci memory window */ - if ((phys_addr >= start) && ((phys_addr + size) < end)) { - return (phys_t)((phys_addr - start) + Au1500_PCI_MEM_START); + { + u32 start, end; + + start = (u32)Au1500_PCI_MEM_START; + end = (u32)Au1500_PCI_MEM_END; + /* check for pci memory window */ + if ((phys_addr >= start) && ((phys_addr + size) < end)) + return (phys_t) + ((phys_addr - start) + Au1500_PCI_MEM_START); } #endif diff --git a/arch/mips/au1000/pb1100/board_setup.c b/arch/mips/au1000/pb1100/board_setup.c index 2d1533f116c0..6bc1f8e1b608 100644 --- a/arch/mips/au1000/pb1100/board_setup.c +++ b/arch/mips/au1000/pb1100/board_setup.c @@ -47,8 +47,7 @@ void board_reset (void) void __init board_setup(void) { - u32 pin_func; - u32 sys_freqctrl, sys_clksrc; + volatile void __iomem * base = (volatile void __iomem *) 0xac000000UL; // set AUX clock to 12MHz * 8 = 96 MHz au_writel(8, SYS_AUXPLL); @@ -56,58 +55,62 @@ void __init board_setup(void) udelay(100); #ifdef CONFIG_USB_OHCI - // configure pins GPIO[14:9] as GPIO - pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80); + { + u32 pin_func, sys_freqctrl, sys_clksrc; - /* zero and disable FREQ2 */ - sys_freqctrl = au_readl(SYS_FREQCTRL0); - sys_freqctrl &= ~0xFFF00000; - au_writel(sys_freqctrl, SYS_FREQCTRL0); + // configure pins GPIO[14:9] as GPIO + pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80); - /* zero and disable USBH/USBD/IrDA clock */ - sys_clksrc = au_readl(SYS_CLKSRC); - sys_clksrc &= ~0x0000001F; - au_writel(sys_clksrc, SYS_CLKSRC); + /* zero and disable FREQ2 */ + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; + au_writel(sys_freqctrl, SYS_FREQCTRL0); - sys_freqctrl = au_readl(SYS_FREQCTRL0); - sys_freqctrl &= ~0xFFF00000; + /* zero and disable USBH/USBD/IrDA clock */ + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x0000001F; + au_writel(sys_clksrc, SYS_CLKSRC); - sys_clksrc = au_readl(SYS_CLKSRC); - sys_clksrc &= ~0x0000001F; + sys_freqctrl = au_readl(SYS_FREQCTRL0); + sys_freqctrl &= ~0xFFF00000; - // FREQ2 = aux/2 = 48 MHz - sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20)); - au_writel(sys_freqctrl, SYS_FREQCTRL0); + sys_clksrc = au_readl(SYS_CLKSRC); + sys_clksrc &= ~0x0000001F; - /* - * Route 48MHz FREQ2 into USBH/USBD/IrDA - */ - sys_clksrc |= ((4<<2) | (0<<1) | 0 ); - au_writel(sys_clksrc, SYS_CLKSRC); + // FREQ2 = aux/2 = 48 MHz + sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20)); + au_writel(sys_freqctrl, SYS_FREQCTRL0); - /* setup the static bus controller */ - au_writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */ - au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */ - au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */ + /* + * Route 48MHz FREQ2 into USBH/USBD/IrDA + */ + sys_clksrc |= ((4<<2) | (0<<1) | 0 ); + au_writel(sys_clksrc, SYS_CLKSRC); - // get USB Functionality pin state (device vs host drive pins) - pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000); - // 2nd USB port is USB host - pin_func |= 0x8000; - au_writel(pin_func, SYS_PINFUNC); + /* setup the static bus controller */ + au_writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */ + au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */ + au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */ + + // get USB Functionality pin state (device vs host drive pins) + pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000); + // 2nd USB port is USB host + pin_func |= 0x8000; + au_writel(pin_func, SYS_PINFUNC); + } #endif // defined (CONFIG_USB_OHCI) /* Enable sys bus clock divider when IDLE state or no bus activity. */ au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL); // Enable the RTC if not already enabled - if (!(readb(0xac000028) & 0x20)) { - writeb(readb(0xac000028) | 0x20, 0xac000028); + if (!(readb(base + 0x28) & 0x20)) { + writeb(readb(base + 0x28) | 0x20, base + 0x28); au_sync(); } // Put the clock in BCD mode - if (readb(0xac00002C) & 0x4) { /* reg B */ - writeb(readb(0xac00002c) & ~0x4, 0xac00002c); + if (readb(base + 0x2C) & 0x4) { /* reg B */ + writeb(readb(base + 0x2c) & ~0x4, base + 0x2c); au_sync(); } } diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c index 91983ba407c4..b73b2d18bf56 100644 --- a/arch/mips/au1000/pb1200/irqmap.c +++ b/arch/mips/au1000/pb1200/irqmap.c @@ -137,33 +137,20 @@ static void pb1200_shutdown_irq( unsigned int irq_nr ) return; } -static inline void pb1200_mask_and_ack_irq(unsigned int irq_nr) -{ - pb1200_disable_irq( irq_nr ); -} - -static void pb1200_end_irq(unsigned int irq_nr) -{ - if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { - pb1200_enable_irq(irq_nr); - } -} - static struct irq_chip external_irq_type = { #ifdef CONFIG_MIPS_PB1200 - "Pb1200 Ext", + .name = "Pb1200 Ext", #endif #ifdef CONFIG_MIPS_DB1200 - "Db1200 Ext", + .name = "Db1200 Ext", #endif - pb1200_startup_irq, - pb1200_shutdown_irq, - pb1200_enable_irq, - pb1200_disable_irq, - pb1200_mask_and_ack_irq, - pb1200_end_irq, - NULL + .startup = pb1200_startup_irq, + .shutdown = pb1200_shutdown_irq, + .ack = pb1200_disable_irq, + .mask = pb1200_disable_irq, + .mask_ack = pb1200_disable_irq, + .unmask = pb1200_enable_irq, }; void _board_init_irq(void) @@ -172,7 +159,8 @@ void _board_init_irq(void) for (irq_nr = PB1200_INT_BEGIN; irq_nr <= PB1200_INT_END; irq_nr++) { - irq_desc[irq_nr].chip = &external_irq_type; + set_irq_chip_and_handler(irq_nr, &external_irq_type, + handle_level_irq); pb1200_disable_irq(irq_nr); } diff --git a/arch/mips/basler/excite/excite_irq.c b/arch/mips/basler/excite/excite_irq.c index 2e2061a286c5..1ecab6350421 100644 --- a/arch/mips/basler/excite/excite_irq.c +++ b/arch/mips/basler/excite/excite_irq.c @@ -47,9 +47,9 @@ extern asmlinkage void excite_handle_int(void); */ void __init arch_init_irq(void) { - mips_cpu_irq_init(0); - rm7k_cpu_irq_init(8); - rm9k_cpu_irq_init(12); + mips_cpu_irq_init(); + rm7k_cpu_irq_init(); + rm9k_cpu_irq_init(); #ifdef CONFIG_KGDB excite_kgdb_init(); diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c index 4c46f0e73783..fe93b846923b 100644 --- a/arch/mips/cobalt/irq.c +++ b/arch/mips/cobalt/irq.c @@ -104,7 +104,7 @@ void __init arch_init_irq(void) GT_WRITE(GT_INTRMASK_OFS, 0); init_i8259_irqs(); /* 0 ... 15 */ - mips_cpu_irq_init(COBALT_CPU_IRQ); /* 16 ... 23 */ + mips_cpu_irq_init(); /* 16 ... 23 */ /* * Mask all cpu interrupts diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c index e8f0f20b852d..a4b69b543bd9 100644 --- a/arch/mips/cobalt/setup.c +++ b/arch/mips/cobalt/setup.c @@ -204,8 +204,7 @@ void __init prom_init(void) add_memory_region(0x0, memsz, BOOT_MEM_RAM); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { /* Nothing to do! */ - return 0; } diff --git a/arch/mips/ddb5xxx/common/prom.c b/arch/mips/ddb5xxx/common/prom.c index efef0f57ce1e..54a857b5e3ba 100644 --- a/arch/mips/ddb5xxx/common/prom.c +++ b/arch/mips/ddb5xxx/common/prom.c @@ -59,9 +59,8 @@ void __init prom_init(void) #endif } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } #if defined(CONFIG_DDB5477) diff --git a/arch/mips/ddb5xxx/ddb5477/irq.c b/arch/mips/ddb5xxx/ddb5477/irq.c index a8bd2e66705c..2b23234a5b95 100644 --- a/arch/mips/ddb5xxx/ddb5477/irq.c +++ b/arch/mips/ddb5xxx/ddb5477/irq.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -73,7 +74,6 @@ set_pci_int_attr(u32 pci, u32 intn, u32 active, u32 trigger) } extern void vrc5477_irq_init(u32 base); -extern void mips_cpu_irq_init(u32 base); static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; void __init arch_init_irq(void) @@ -125,7 +125,7 @@ void __init arch_init_irq(void) /* init all controllers */ init_i8259_irqs(); - mips_cpu_irq_init(CPU_IRQ_BASE); + mips_cpu_irq_init(); vrc5477_irq_init(VRC5477_IRQ_BASE); @@ -146,8 +146,7 @@ u8 i8259_interrupt_ack(void) irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE); ddb_out32(DDB_PCIINIT10, reg); - /* i8259.c set the base vector to be 0x0 */ - return irq + I8259_IRQ_BASE; + return irq; } /* * the first level int-handler will jump here if it is a vrc5477 irq @@ -177,7 +176,7 @@ static void vrc5477_irq_dispatch(void) /* check for i8259 interrupts */ if (intStatus & (1 << VRC5477_I8259_CASCADE)) { int i8259_irq = i8259_interrupt_ack(); - do_IRQ(I8259_IRQ_BASE + i8259_irq); + do_IRQ(i8259_irq); return; } } diff --git a/arch/mips/ddb5xxx/ddb5477/irq_5477.c b/arch/mips/ddb5xxx/ddb5477/irq_5477.c index 96249aa5df5d..98c3b15eb369 100644 --- a/arch/mips/ddb5xxx/ddb5477/irq_5477.c +++ b/arch/mips/ddb5xxx/ddb5477/irq_5477.c @@ -82,7 +82,7 @@ vrc5477_irq_end(unsigned int irq) } struct irq_chip vrc5477_irq_controller = { - .typename = "vrc5477_irq", + .name = "vrc5477_irq", .ack = vrc5477_irq_ack, .mask = vrc5477_irq_disable, .mask_ack = vrc5477_irq_ack, diff --git a/arch/mips/dec/ioasic-irq.c b/arch/mips/dec/ioasic-irq.c index 4c7cb4048d35..3acb133668dc 100644 --- a/arch/mips/dec/ioasic-irq.c +++ b/arch/mips/dec/ioasic-irq.c @@ -62,7 +62,7 @@ static inline void end_ioasic_irq(unsigned int irq) } static struct irq_chip ioasic_irq_type = { - .typename = "IO-ASIC", + .name = "IO-ASIC", .ack = ack_ioasic_irq, .mask = mask_ioasic_irq, .mask_ack = ack_ioasic_irq, @@ -84,7 +84,7 @@ static inline void end_ioasic_dma_irq(unsigned int irq) } static struct irq_chip ioasic_dma_irq_type = { - .typename = "IO-ASIC-DMA", + .name = "IO-ASIC-DMA", .ack = ack_ioasic_dma_irq, .mask = mask_ioasic_dma_irq, .mask_ack = ack_ioasic_dma_irq, diff --git a/arch/mips/dec/kn02-irq.c b/arch/mips/dec/kn02-irq.c index 916e46b8ccd8..02439dc0ba83 100644 --- a/arch/mips/dec/kn02-irq.c +++ b/arch/mips/dec/kn02-irq.c @@ -58,7 +58,7 @@ static void ack_kn02_irq(unsigned int irq) } static struct irq_chip kn02_irq_type = { - .typename = "KN02-CSR", + .name = "KN02-CSR", .ack = ack_kn02_irq, .mask = mask_kn02_irq, .mask_ack = ack_kn02_irq, diff --git a/arch/mips/dec/prom/memory.c b/arch/mips/dec/prom/memory.c index 3aa01d268f2d..5a557e268f78 100644 --- a/arch/mips/dec/prom/memory.c +++ b/arch/mips/dec/prom/memory.c @@ -92,9 +92,9 @@ void __init prom_meminit(u32 magic) rex_setup_memory_region(); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - unsigned long addr, end; + unsigned long end; /* * Free everything below the kernel itself but leave @@ -114,16 +114,5 @@ unsigned long __init prom_free_prom_memory(void) #endif end = __pa(&_text); - addr = PAGE_SIZE; - while (addr < end) { - ClearPageReserved(virt_to_page(__va(addr))); - init_page_count(virt_to_page(__va(addr))); - free_page((unsigned long)__va(addr)); - addr += PAGE_SIZE; - } - - printk("Freeing unused PROM memory: %ldkb freed\n", - (end - PAGE_SIZE) >> 10); - - return end - PAGE_SIZE; + free_init_pages("unused PROM memory", PAGE_SIZE, end); } diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index d34032ac492a..1058e2f409bb 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -234,7 +234,7 @@ static void __init dec_init_kn01(void) memcpy(&cpu_mask_nr_tbl, &kn01_cpu_mask_nr_tbl, sizeof(kn01_cpu_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); } /* dec_init_kn01 */ @@ -309,7 +309,7 @@ static void __init dec_init_kn230(void) memcpy(&cpu_mask_nr_tbl, &kn230_cpu_mask_nr_tbl, sizeof(kn230_cpu_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); } /* dec_init_kn230 */ @@ -403,7 +403,7 @@ static void __init dec_init_kn02(void) memcpy(&asic_mask_nr_tbl, &kn02_asic_mask_nr_tbl, sizeof(kn02_asic_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); init_kn02_irqs(KN02_IRQ_BASE); } /* dec_init_kn02 */ @@ -504,7 +504,7 @@ static void __init dec_init_kn02ba(void) memcpy(&asic_mask_nr_tbl, &kn02ba_asic_mask_nr_tbl, sizeof(kn02ba_asic_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); init_ioasic_irqs(IO_IRQ_BASE); } /* dec_init_kn02ba */ @@ -601,7 +601,7 @@ static void __init dec_init_kn02ca(void) memcpy(&asic_mask_nr_tbl, &kn02ca_asic_mask_nr_tbl, sizeof(kn02ca_asic_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); init_ioasic_irqs(IO_IRQ_BASE); } /* dec_init_kn02ca */ @@ -702,7 +702,7 @@ static void __init dec_init_kn03(void) memcpy(&asic_mask_nr_tbl, &kn03_asic_mask_nr_tbl, sizeof(kn03_asic_mask_nr_tbl)); - mips_cpu_irq_init(DEC_CPU_IRQ_BASE); + mips_cpu_irq_init(); init_ioasic_irqs(IO_IRQ_BASE); } /* dec_init_kn03 */ diff --git a/arch/mips/emma2rh/common/irq_emma2rh.c b/arch/mips/emma2rh/common/irq_emma2rh.c index 8d880f0b06ec..96df37b77759 100644 --- a/arch/mips/emma2rh/common/irq_emma2rh.c +++ b/arch/mips/emma2rh/common/irq_emma2rh.c @@ -57,7 +57,7 @@ static void emma2rh_irq_disable(unsigned int irq) } struct irq_chip emma2rh_irq_controller = { - .typename = "emma2rh_irq", + .name = "emma2rh_irq", .ack = emma2rh_irq_disable, .mask = emma2rh_irq_disable, .mask_ack = emma2rh_irq_disable, diff --git a/arch/mips/emma2rh/markeins/irq.c b/arch/mips/emma2rh/markeins/irq.c index c93369cb4115..3299b6dfe764 100644 --- a/arch/mips/emma2rh/markeins/irq.c +++ b/arch/mips/emma2rh/markeins/irq.c @@ -106,7 +106,7 @@ void __init arch_init_irq(void) emma2rh_irq_init(EMMA2RH_IRQ_BASE); emma2rh_sw_irq_init(EMMA2RH_SW_IRQ_BASE); emma2rh_gpio_irq_init(EMMA2RH_GPIO_IRQ_BASE); - mips_cpu_irq_init(CPU_IRQ_BASE); + mips_cpu_irq_init(); /* setup cascade interrupts */ setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_SW_CASCADE, &irq_cascade); diff --git a/arch/mips/emma2rh/markeins/irq_markeins.c b/arch/mips/emma2rh/markeins/irq_markeins.c index 2116d9be5fa9..fba5c156f472 100644 --- a/arch/mips/emma2rh/markeins/irq_markeins.c +++ b/arch/mips/emma2rh/markeins/irq_markeins.c @@ -49,7 +49,7 @@ static void emma2rh_sw_irq_disable(unsigned int irq) } struct irq_chip emma2rh_sw_irq_controller = { - .typename = "emma2rh_sw_irq", + .name = "emma2rh_sw_irq", .ack = emma2rh_sw_irq_disable, .mask = emma2rh_sw_irq_disable, .mask_ack = emma2rh_sw_irq_disable, @@ -115,7 +115,7 @@ static void emma2rh_gpio_irq_end(unsigned int irq) } struct irq_chip emma2rh_gpio_irq_controller = { - .typename = "emma2rh_gpio_irq", + .name = "emma2rh_gpio_irq", .ack = emma2rh_gpio_irq_ack, .mask = emma2rh_gpio_irq_disable, .mask_ack = emma2rh_gpio_irq_ack, diff --git a/arch/mips/gt64120/ev64120/irq.c b/arch/mips/gt64120/ev64120/irq.c index b3e5796c81d7..04572b9c9642 100644 --- a/arch/mips/gt64120/ev64120/irq.c +++ b/arch/mips/gt64120/ev64120/irq.c @@ -88,7 +88,7 @@ static void end_ev64120_irq(unsigned int irq) } static struct irq_chip ev64120_irq_type = { - .typename = "EV64120", + .name = "EV64120", .ack = disable_ev64120_irq, .mask = disable_ev64120_irq, .mask_ack = disable_ev64120_irq, diff --git a/arch/mips/gt64120/ev64120/setup.c b/arch/mips/gt64120/ev64120/setup.c index 99c8d42212e2..477848c22a2c 100644 --- a/arch/mips/gt64120/ev64120/setup.c +++ b/arch/mips/gt64120/ev64120/setup.c @@ -59,9 +59,8 @@ extern void galileo_machine_power_off(void); */ extern struct pci_ops galileo_pci_ops; -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } /* diff --git a/arch/mips/gt64120/momenco_ocelot/dbg_io.c b/arch/mips/gt64120/momenco_ocelot/dbg_io.c index 2128684584f5..32d6fb4ee679 100644 --- a/arch/mips/gt64120/momenco_ocelot/dbg_io.c +++ b/arch/mips/gt64120/momenco_ocelot/dbg_io.c @@ -1,6 +1,4 @@ -#ifdef CONFIG_KGDB - #include /* For the serial port location and base baud */ /* --- CONFIG --- */ @@ -121,5 +119,3 @@ int putDebugChar(uint8 byte) UART16550_WRITE(OFS_SEND_BUFFER, byte); return 1; } - -#endif diff --git a/arch/mips/gt64120/momenco_ocelot/irq.c b/arch/mips/gt64120/momenco_ocelot/irq.c index d9294401ccb0..2585d9dbda33 100644 --- a/arch/mips/gt64120/momenco_ocelot/irq.c +++ b/arch/mips/gt64120/momenco_ocelot/irq.c @@ -90,6 +90,6 @@ void __init arch_init_irq(void) clear_c0_status(ST0_IM); local_irq_disable(); - mips_cpu_irq_init(0); - rm7k_cpu_irq_init(8); + mips_cpu_irq_init(); + rm7k_cpu_irq_init(); } diff --git a/arch/mips/gt64120/momenco_ocelot/prom.c b/arch/mips/gt64120/momenco_ocelot/prom.c index 8677b6d3ada7..78f393b2afd9 100644 --- a/arch/mips/gt64120/momenco_ocelot/prom.c +++ b/arch/mips/gt64120/momenco_ocelot/prom.c @@ -67,7 +67,6 @@ void __init prom_init(void) add_memory_region(0, 64 << 20, BOOT_MEM_RAM); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } diff --git a/arch/mips/gt64120/wrppmc/irq.c b/arch/mips/gt64120/wrppmc/irq.c index eedfc24e1eae..d3d96591780e 100644 --- a/arch/mips/gt64120/wrppmc/irq.c +++ b/arch/mips/gt64120/wrppmc/irq.c @@ -63,7 +63,7 @@ void gt64120_init_pic(void) void __init arch_init_irq(void) { /* IRQ 0 - 7 are for MIPS common irq_cpu controller */ - mips_cpu_irq_init(0); + mips_cpu_irq_init(); gt64120_init_pic(); } diff --git a/arch/mips/gt64120/wrppmc/setup.c b/arch/mips/gt64120/wrppmc/setup.c index 429afc400cb4..121188d5ec4a 100644 --- a/arch/mips/gt64120/wrppmc/setup.c +++ b/arch/mips/gt64120/wrppmc/setup.c @@ -93,9 +93,8 @@ void __init wrppmc_early_printk(const char *fmt, ...) } #endif /* WRPPMC_EARLY_DEBUG */ -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } #ifdef CONFIG_SERIAL_8250 diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c index f8d417b5c2bb..295892e4ce53 100644 --- a/arch/mips/jazz/irq.c +++ b/arch/mips/jazz/irq.c @@ -40,7 +40,7 @@ void disable_r4030_irq(unsigned int irq) } static struct irq_chip r4030_irq_type = { - .typename = "R4030", + .name = "R4030", .ack = disable_r4030_irq, .mask = disable_r4030_irq, .mask_ack = disable_r4030_irq, diff --git a/arch/mips/jmr3927/common/prom.c b/arch/mips/jmr3927/common/prom.c index 5d5838f41d23..aa481b774c42 100644 --- a/arch/mips/jmr3927/common/prom.c +++ b/arch/mips/jmr3927/common/prom.c @@ -75,7 +75,6 @@ void __init prom_init_cmdline(void) *cp = '\0'; } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c index 3da49c5aaf49..7d2c203cb406 100644 --- a/arch/mips/jmr3927/rbhma3100/irq.c +++ b/arch/mips/jmr3927/rbhma3100/irq.c @@ -439,7 +439,7 @@ void __init arch_init_irq(void) } static struct irq_chip jmr3927_irq_controller = { - .typename = "jmr3927_irq", + .name = "jmr3927_irq", .ack = jmr3927_irq_ack, .mask = jmr3927_irq_disable, .mask_ack = jmr3927_irq_ack, diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c index 138f25efe38a..7ca3d6d07b34 100644 --- a/arch/mips/jmr3927/rbhma3100/setup.c +++ b/arch/mips/jmr3927/rbhma3100/setup.c @@ -434,7 +434,7 @@ void __init tx3927_setup(void) /* DMA */ tx3927_dmaptr->mcr = 0; - for (i = 0; i < sizeof(tx3927_dmaptr->ch) / sizeof(tx3927_dmaptr->ch[0]); i++) { + for (i = 0; i < ARRAY_SIZE(tx3927_dmaptr->ch); i++) { /* reset channel */ tx3927_dmaptr->ch[i].ccr = TX3927_DMA_CCR_CHRST; tx3927_dmaptr->ch[i].ccr = 0; diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index ff88b06f89df..ea7df4b8da33 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -234,10 +234,6 @@ void output_mm_defines(void) constant("#define _PMD_SHIFT ", PMD_SHIFT); constant("#define _PGDIR_SHIFT ", PGDIR_SHIFT); linefeed; - constant("#define _PGD_ORDER ", PGD_ORDER); - constant("#define _PMD_ORDER ", PMD_ORDER); - constant("#define _PTE_ORDER ", PTE_ORDER); - linefeed; constant("#define _PTRS_PER_PGD ", PTRS_PER_PGD); constant("#define _PTRS_PER_PMD ", PTRS_PER_PMD); constant("#define _PTRS_PER_PTE ", PTRS_PER_PTE); diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 442839e9578c..f59ef271d247 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -565,7 +565,7 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) if (config3 & MIPS_CONF3_VEIC) c->options |= MIPS_CPU_VEIC; if (config3 & MIPS_CONF3_MT) - c->ases |= MIPS_ASE_MIPSMT; + c->ases |= MIPS_ASE_MIPSMT; return config3 & MIPS_CONF_M; } diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index 719d26968cb2..7bc882049269 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -505,13 +505,13 @@ void show_gdbregs(struct gdb_regs * regs) */ printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", regs->reg0, regs->reg1, regs->reg2, regs->reg3, - regs->reg4, regs->reg5, regs->reg6, regs->reg7); + regs->reg4, regs->reg5, regs->reg6, regs->reg7); printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", regs->reg8, regs->reg9, regs->reg10, regs->reg11, - regs->reg12, regs->reg13, regs->reg14, regs->reg15); + regs->reg12, regs->reg13, regs->reg14, regs->reg15); printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", regs->reg16, regs->reg17, regs->reg18, regs->reg19, - regs->reg20, regs->reg21, regs->reg22, regs->reg23); + regs->reg20, regs->reg21, regs->reg22, regs->reg23); printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", regs->reg24, regs->reg25, regs->reg26, regs->reg27, regs->reg28, regs->reg29, regs->reg30, regs->reg31); diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index 9a7811d13db2..6f57ca44291f 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -231,28 +231,3 @@ NESTED(smp_bootstrap, 16, sp) #endif /* CONFIG_SMP */ __FINIT - - .comm kernelsp, NR_CPUS * 8, 8 - .comm pgd_current, NR_CPUS * 8, 8 - - .comm fw_arg0, SZREG, SZREG # firmware arguments - .comm fw_arg1, SZREG, SZREG - .comm fw_arg2, SZREG, SZREG - .comm fw_arg3, SZREG, SZREG - - .macro page name, order - .comm \name, (_PAGE_SIZE << \order), (_PAGE_SIZE << \order) - .endm - - /* - * On 64-bit we've got three-level pagetables with a slightly - * different layout ... - */ - page swapper_pg_dir, _PGD_ORDER -#ifdef CONFIG_64BIT -#if defined(CONFIG_MODULES) && !defined(CONFIG_BUILD_ELF64) - page module_pg_dir, _PGD_ORDER -#endif - page invalid_pmd_table, _PMD_ORDER -#endif - page invalid_pte_table, _PTE_ORDER diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index b59a676c6d0e..b33ba6cd7f5b 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -54,9 +54,11 @@ static unsigned int cached_irq_mask = 0xffff; void disable_8259A_irq(unsigned int irq) { - unsigned int mask = 1 << irq; + unsigned int mask; unsigned long flags; + irq -= I8259A_IRQ_BASE; + mask = 1 << irq; spin_lock_irqsave(&i8259A_lock, flags); cached_irq_mask |= mask; if (irq & 8) @@ -68,9 +70,11 @@ void disable_8259A_irq(unsigned int irq) void enable_8259A_irq(unsigned int irq) { - unsigned int mask = ~(1 << irq); + unsigned int mask; unsigned long flags; + irq -= I8259A_IRQ_BASE; + mask = ~(1 << irq); spin_lock_irqsave(&i8259A_lock, flags); cached_irq_mask &= mask; if (irq & 8) @@ -82,10 +86,12 @@ void enable_8259A_irq(unsigned int irq) int i8259A_irq_pending(unsigned int irq) { - unsigned int mask = 1 << irq; + unsigned int mask; unsigned long flags; int ret; + irq -= I8259A_IRQ_BASE; + mask = 1 << irq; spin_lock_irqsave(&i8259A_lock, flags); if (irq < 8) ret = inb(PIC_MASTER_CMD) & mask; @@ -134,9 +140,11 @@ static inline int i8259A_irq_real(unsigned int irq) */ void mask_and_ack_8259A(unsigned int irq) { - unsigned int irqmask = 1 << irq; + unsigned int irqmask; unsigned long flags; + irq -= I8259A_IRQ_BASE; + irqmask = 1 << irq; spin_lock_irqsave(&i8259A_lock, flags); /* * Lightweight spurious IRQ detection. We do not want @@ -169,8 +177,8 @@ handle_real_irq: outb(0x60+irq,PIC_MASTER_CMD); /* 'Specific EOI to master */ } #ifdef CONFIG_MIPS_MT_SMTC - if (irq_hwmask[irq] & ST0_IM) - set_c0_status(irq_hwmask[irq] & ST0_IM); + if (irq_hwmask[irq] & ST0_IM) + set_c0_status(irq_hwmask[irq] & ST0_IM); #endif /* CONFIG_MIPS_MT_SMTC */ spin_unlock_irqrestore(&i8259A_lock, flags); return; @@ -322,8 +330,8 @@ void __init init_i8259_irqs (void) init_8259A(0); - for (i = 0; i < 16; i++) + for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++) set_irq_chip_and_handler(i, &i8259A_chip, handle_level_irq); - setup_irq(PIC_CASCADE_IR, &irq2); + setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); } diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index 37cad5de515c..3cc25c05d367 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -10,6 +10,8 @@ * Copyright (C) 1996 - 2004 David S. Miller * Copyright (C) 2004 - 2005 Steven J. Hill */ +#undef DEBUG + #include #include #include @@ -40,8 +42,6 @@ #include -#undef DEBUG - static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs); static int load_irix_library(struct file *); static int irix_core_dump(long signr, struct pt_regs * regs, @@ -52,72 +52,102 @@ static struct linux_binfmt irix_format = { irix_core_dump, PAGE_SIZE }; -#ifdef DEBUG /* Debugging routines. */ static char *get_elf_p_type(Elf32_Word p_type) { - int i = (int) p_type; +#ifdef DEBUG + switch (p_type) { + case PT_NULL: + return "PT_NULL"; + break; - switch(i) { - case PT_NULL: return("PT_NULL"); break; - case PT_LOAD: return("PT_LOAD"); break; - case PT_DYNAMIC: return("PT_DYNAMIC"); break; - case PT_INTERP: return("PT_INTERP"); break; - case PT_NOTE: return("PT_NOTE"); break; - case PT_SHLIB: return("PT_SHLIB"); break; - case PT_PHDR: return("PT_PHDR"); break; - case PT_LOPROC: return("PT_LOPROC/REGINFO"); break; - case PT_HIPROC: return("PT_HIPROC"); break; - default: return("PT_BOGUS"); break; + case PT_LOAD: + return "PT_LOAD"; + break; + + case PT_DYNAMIC: + return "PT_DYNAMIC"; + break; + + case PT_INTERP: + return "PT_INTERP"; + break; + + case PT_NOTE: + return "PT_NOTE"; + break; + + case PT_SHLIB: + return "PT_SHLIB"; + break; + + case PT_PHDR: + return "PT_PHDR"; + break; + + case PT_LOPROC: + return "PT_LOPROC/REGINFO"; + break; + + case PT_HIPROC: + return "PT_HIPROC"; + break; + + default: + return "PT_BOGUS"; + break; } +#endif } static void print_elfhdr(struct elfhdr *ehp) { int i; - printk("ELFHDR: e_ident<"); - for(i = 0; i < (EI_NIDENT - 1); i++) printk("%x ", ehp->e_ident[i]); - printk("%x>\n", ehp->e_ident[i]); - printk(" e_type[%04x] e_machine[%04x] e_version[%08lx]\n", - (unsigned short) ehp->e_type, (unsigned short) ehp->e_machine, - (unsigned long) ehp->e_version); - printk(" e_entry[%08lx] e_phoff[%08lx] e_shoff[%08lx] " - "e_flags[%08lx]\n", - (unsigned long) ehp->e_entry, (unsigned long) ehp->e_phoff, - (unsigned long) ehp->e_shoff, (unsigned long) ehp->e_flags); - printk(" e_ehsize[%04x] e_phentsize[%04x] e_phnum[%04x]\n", - (unsigned short) ehp->e_ehsize, (unsigned short) ehp->e_phentsize, - (unsigned short) ehp->e_phnum); - printk(" e_shentsize[%04x] e_shnum[%04x] e_shstrndx[%04x]\n", - (unsigned short) ehp->e_shentsize, (unsigned short) ehp->e_shnum, - (unsigned short) ehp->e_shstrndx); + pr_debug("ELFHDR: e_ident<"); + for (i = 0; i < (EI_NIDENT - 1); i++) + pr_debug("%x ", ehp->e_ident[i]); + pr_debug("%x>\n", ehp->e_ident[i]); + pr_debug(" e_type[%04x] e_machine[%04x] e_version[%08lx]\n", + (unsigned short) ehp->e_type, (unsigned short) ehp->e_machine, + (unsigned long) ehp->e_version); + pr_debug(" e_entry[%08lx] e_phoff[%08lx] e_shoff[%08lx] " + "e_flags[%08lx]\n", + (unsigned long) ehp->e_entry, (unsigned long) ehp->e_phoff, + (unsigned long) ehp->e_shoff, (unsigned long) ehp->e_flags); + pr_debug(" e_ehsize[%04x] e_phentsize[%04x] e_phnum[%04x]\n", + (unsigned short) ehp->e_ehsize, + (unsigned short) ehp->e_phentsize, + (unsigned short) ehp->e_phnum); + pr_debug(" e_shentsize[%04x] e_shnum[%04x] e_shstrndx[%04x]\n", + (unsigned short) ehp->e_shentsize, + (unsigned short) ehp->e_shnum, + (unsigned short) ehp->e_shstrndx); } static void print_phdr(int i, struct elf_phdr *ep) { - printk("PHDR[%d]: p_type[%s] p_offset[%08lx] p_vaddr[%08lx] " - "p_paddr[%08lx]\n", i, get_elf_p_type(ep->p_type), - (unsigned long) ep->p_offset, (unsigned long) ep->p_vaddr, - (unsigned long) ep->p_paddr); - printk(" p_filesz[%08lx] p_memsz[%08lx] p_flags[%08lx] " - "p_align[%08lx]\n", (unsigned long) ep->p_filesz, - (unsigned long) ep->p_memsz, (unsigned long) ep->p_flags, - (unsigned long) ep->p_align); + pr_debug("PHDR[%d]: p_type[%s] p_offset[%08lx] p_vaddr[%08lx] " + "p_paddr[%08lx]\n", i, get_elf_p_type(ep->p_type), + (unsigned long) ep->p_offset, (unsigned long) ep->p_vaddr, + (unsigned long) ep->p_paddr); + pr_debug(" p_filesz[%08lx] p_memsz[%08lx] p_flags[%08lx] " + "p_align[%08lx]\n", (unsigned long) ep->p_filesz, + (unsigned long) ep->p_memsz, (unsigned long) ep->p_flags, + (unsigned long) ep->p_align); } static void dump_phdrs(struct elf_phdr *ep, int pnum) { int i; - for(i = 0; i < pnum; i++, ep++) { - if((ep->p_type == PT_LOAD) || - (ep->p_type == PT_INTERP) || - (ep->p_type == PT_PHDR)) + for (i = 0; i < pnum; i++, ep++) { + if ((ep->p_type == PT_LOAD) || + (ep->p_type == PT_INTERP) || + (ep->p_type == PT_PHDR)) print_phdr(i, ep); } } -#endif /* DEBUG */ static void set_brk(unsigned long start, unsigned long end) { @@ -156,11 +186,10 @@ static unsigned long * create_irix_tables(char * p, int argc, int envc, elf_addr_t *envp; elf_addr_t *sp, *csp; -#ifdef DEBUG - printk("create_irix_tables: p[%p] argc[%d] envc[%d] " - "load_addr[%08x] interp_load_addr[%08x]\n", - p, argc, envc, load_addr, interp_load_addr); -#endif + pr_debug("create_irix_tables: p[%p] argc[%d] envc[%d] " + "load_addr[%08x] interp_load_addr[%08x]\n", + p, argc, envc, load_addr, interp_load_addr); + sp = (elf_addr_t *) (~15UL & (unsigned long) p); csp = sp; csp -= exec ? DLINFO_ITEMS*2 : 2; @@ -181,7 +210,7 @@ static unsigned long * create_irix_tables(char * p, int argc, int envc, sp -= 2; NEW_AUX_ENT(0, AT_NULL, 0); - if(exec) { + if (exec) { sp -= 11*2; NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff); @@ -245,9 +274,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, last_bss = 0; error = load_addr = 0; -#ifdef DEBUG print_elfhdr(interp_elf_ex); -#endif /* First of all, some simple consistency checks */ if ((interp_elf_ex->e_type != ET_EXEC && @@ -258,7 +285,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, } /* Now read in all of the header information */ - if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) { + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) { printk("IRIX interp header bigger than a page (%d)\n", (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum)); return 0xffffffff; @@ -267,15 +294,15 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, elf_phdata = kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL); - if(!elf_phdata) { - printk("Cannot kmalloc phdata for IRIX interp.\n"); - return 0xffffffff; + if (!elf_phdata) { + printk("Cannot kmalloc phdata for IRIX interp.\n"); + return 0xffffffff; } /* If the size of this structure has changed, then punt, since * we will be doing the wrong thing. */ - if(interp_elf_ex->e_phentsize != 32) { + if (interp_elf_ex->e_phentsize != 32) { printk("IRIX interp e_phentsize == %d != 32 ", interp_elf_ex->e_phentsize); kfree(elf_phdata); @@ -286,61 +313,71 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, (char *) elf_phdata, sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); -#ifdef DEBUG dump_phdrs(elf_phdata, interp_elf_ex->e_phnum); -#endif eppnt = elf_phdata; - for(i=0; ie_phnum; i++, eppnt++) { - if(eppnt->p_type == PT_LOAD) { - int elf_type = MAP_PRIVATE | MAP_DENYWRITE; - int elf_prot = 0; - unsigned long vaddr = 0; - if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; - if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - elf_type |= MAP_FIXED; - vaddr = eppnt->p_vaddr; + for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { + if (eppnt->p_type == PT_LOAD) { + int elf_type = MAP_PRIVATE | MAP_DENYWRITE; + int elf_prot = 0; + unsigned long vaddr = 0; + if (eppnt->p_flags & PF_R) + elf_prot = PROT_READ; + if (eppnt->p_flags & PF_W) + elf_prot |= PROT_WRITE; + if (eppnt->p_flags & PF_X) + elf_prot |= PROT_EXEC; + elf_type |= MAP_FIXED; + vaddr = eppnt->p_vaddr; - pr_debug("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ", - interpreter, vaddr, - (unsigned long) (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)), - (unsigned long) elf_prot, (unsigned long) elf_type, - (unsigned long) (eppnt->p_offset & 0xfffff000)); - down_write(¤t->mm->mmap_sem); - error = do_mmap(interpreter, vaddr, - eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), - elf_prot, elf_type, - eppnt->p_offset & 0xfffff000); - up_write(¤t->mm->mmap_sem); + pr_debug("INTERP do_mmap" + "(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ", + interpreter, vaddr, + (unsigned long) + (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)), + (unsigned long) + elf_prot, (unsigned long) elf_type, + (unsigned long) + (eppnt->p_offset & 0xfffff000)); - if(error < 0 && error > -1024) { - printk("Aieee IRIX interp mmap error=%d\n", error); - break; /* Real error */ - } - pr_debug("error=%08lx ", (unsigned long) error); - if(!load_addr && interp_elf_ex->e_type == ET_DYN) { - load_addr = error; - pr_debug("load_addr = error "); - } + down_write(¤t->mm->mmap_sem); + error = do_mmap(interpreter, vaddr, + eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), + elf_prot, elf_type, + eppnt->p_offset & 0xfffff000); + up_write(¤t->mm->mmap_sem); - /* Find the end of the file mapping for this phdr, and keep - * track of the largest address we see for this. - */ - k = eppnt->p_vaddr + eppnt->p_filesz; - if(k > elf_bss) elf_bss = k; + if (error < 0 && error > -1024) { + printk("Aieee IRIX interp mmap error=%d\n", + error); + break; /* Real error */ + } + pr_debug("error=%08lx ", (unsigned long) error); + if (!load_addr && interp_elf_ex->e_type == ET_DYN) { + load_addr = error; + pr_debug("load_addr = error "); + } - /* Do the same thing for the memory mapping - between - * elf_bss and last_bss is the bss section. - */ - k = eppnt->p_memsz + eppnt->p_vaddr; - if(k > last_bss) last_bss = k; - pr_debug("\n"); - } + /* + * Find the end of the file mapping for this phdr, and + * keep track of the largest address we see for this. + */ + k = eppnt->p_vaddr + eppnt->p_filesz; + if (k > elf_bss) + elf_bss = k; + + /* Do the same thing for the memory mapping - between + * elf_bss and last_bss is the bss section. + */ + k = eppnt->p_memsz + eppnt->p_vaddr; + if (k > last_bss) + last_bss = k; + pr_debug("\n"); + } } /* Now use mmap to map the library into memory. */ - if(error < 0 && error > -1024) { + if (error < 0 && error > -1024) { pr_debug("got error %d\n", error); kfree(elf_phdata); return 0xffffffff; @@ -377,7 +414,7 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm) return -ENOEXEC; /* First of all, some simple consistency checks */ - if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || + if ((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || !bprm->file->f_op->mmap) { return -ENOEXEC; } @@ -388,7 +425,7 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm) * XXX all registers as 64bits on cpu's capable of this at * XXX exception time plus frob the XTLB exception vector. */ - if((ehp->e_flags & EF_MIPS_ABI2)) + if ((ehp->e_flags & EF_MIPS_ABI2)) return -ENOEXEC; return 0; @@ -410,7 +447,7 @@ static inline int look_for_irix_interpreter(char **name, struct file *file = NULL; *name = NULL; - for(i = 0; i < pnum; i++, epp++) { + for (i = 0; i < pnum; i++, epp++) { if (epp->p_type != PT_INTERP) continue; @@ -467,8 +504,8 @@ static inline void map_executable(struct file *fp, struct elf_phdr *epp, int pnu unsigned int tmp; int i, prot; - for(i = 0; i < pnum; i++, epp++) { - if(epp->p_type != PT_LOAD) + for (i = 0; i < pnum; i++, epp++) { + if (epp->p_type != PT_LOAD) continue; /* Map it. */ @@ -483,23 +520,23 @@ static inline void map_executable(struct file *fp, struct elf_phdr *epp, int pnu up_write(¤t->mm->mmap_sem); /* Fixup location tracking vars. */ - if((epp->p_vaddr & 0xfffff000) < *estack) + if ((epp->p_vaddr & 0xfffff000) < *estack) *estack = (epp->p_vaddr & 0xfffff000); - if(!*laddr) + if (!*laddr) *laddr = epp->p_vaddr - epp->p_offset; - if(epp->p_vaddr < *scode) + if (epp->p_vaddr < *scode) *scode = epp->p_vaddr; tmp = epp->p_vaddr + epp->p_filesz; - if(tmp > *ebss) + if (tmp > *ebss) *ebss = tmp; - if((epp->p_flags & PF_X) && *ecode < tmp) + if ((epp->p_flags & PF_X) && *ecode < tmp) *ecode = tmp; - if(*edata < tmp) + if (*edata < tmp) *edata = tmp; tmp = epp->p_vaddr + epp->p_memsz; - if(tmp > *ebrk) + if (tmp > *ebrk) *ebrk = tmp; } @@ -513,12 +550,12 @@ static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp, int i; *eentry = 0xffffffff; - for(i = 0; i < pnum; i++, epp++) { - if(epp->p_type != PT_INTERP) + for (i = 0; i < pnum; i++, epp++) { + if (epp->p_type != PT_INTERP) continue; /* We should have fielded this error elsewhere... */ - if(*eentry != 0xffffffff) + if (*eentry != 0xffffffff) return -1; set_fs(old_fs); @@ -604,9 +641,7 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) if (elf_ex.e_shnum > 20) goto out; -#ifdef DEBUG print_elfhdr(&elf_ex); -#endif /* Now read in all of the header information */ size = elf_ex.e_phentsize * elf_ex.e_phnum; @@ -622,13 +657,11 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) if (retval < 0) goto out_free_ph; -#ifdef DEBUG dump_phdrs(elf_phdata, elf_ex.e_phnum); -#endif /* Set some things for later. */ - for(i = 0; i < elf_ex.e_phnum; i++) { - switch(elf_phdata[i].p_type) { + for (i = 0; i < elf_ex.e_phnum; i++) { + switch (elf_phdata[i].p_type) { case PT_INTERP: has_interp = 1; elf_ihdr = &elf_phdata[i]; @@ -667,7 +700,7 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) if (elf_interpreter) { retval = verify_irix_interpreter(&interp_elf_ex); - if(retval) + if (retval) goto out_free_interp; } @@ -706,12 +739,12 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) &load_addr, &start_code, &elf_bss, &end_code, &end_data, &elf_brk); - if(elf_interpreter) { + if (elf_interpreter) { retval = map_interpreter(elf_phdata, &interp_elf_ex, interpreter, &interp_load_addr, elf_ex.e_phnum, old_fs, &elf_entry); kfree(elf_interpreter); - if(retval) { + if (retval) { set_fs(old_fs); printk("Unable to load IRIX ELF interpreter\n"); send_sig(SIGSEGV, current, 0); @@ -809,12 +842,12 @@ static int load_irix_library(struct file *file) return -ENOEXEC; /* First of all, some simple consistency checks. */ - if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || + if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || !file->f_op->mmap) return -ENOEXEC; /* Now read in all of the header information. */ - if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) + if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) return -ENOEXEC; elf_phdata = kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL); @@ -825,15 +858,15 @@ static int load_irix_library(struct file *file) sizeof(struct elf_phdr) * elf_ex.e_phnum); j = 0; - for(i=0; ip_type == PT_LOAD) j++; + for (i=0; ip_type == PT_LOAD) j++; - if(j != 1) { + if (j != 1) { kfree(elf_phdata); return -ENOEXEC; } - while(elf_phdata->p_type != PT_LOAD) elf_phdata++; + while (elf_phdata->p_type != PT_LOAD) elf_phdata++; /* Now use mmap to map the library into memory. */ down_write(¤t->mm->mmap_sem); @@ -889,9 +922,7 @@ unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt) return -EFAULT; } -#ifdef DEBUG dump_phdrs(user_phdrp, cnt); -#endif for (i = 0; i < cnt; i++, hp++) { if (__get_user(type, &hp->p_type)) @@ -905,14 +936,14 @@ unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt) filp = fget(fd); if (!filp) return -EACCES; - if(!filp->f_op) { + if (!filp->f_op) { printk("irix_mapelf: Bogon filp!\n"); fput(filp); return -EACCES; } hp = user_phdrp; - for(i = 0; i < cnt; i++, hp++) { + for (i = 0; i < cnt; i++, hp++) { int prot; retval = __get_user(vaddr, &hp->p_vaddr); @@ -1015,8 +1046,6 @@ static int notesize(struct memelfnote *en) return sz; } -/* #define DEBUG */ - #define DUMP_WRITE(addr, nr) \ if (!dump_write(file, (addr), (nr))) \ goto end_coredump; @@ -1093,9 +1122,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) segs++; } -#ifdef DEBUG - printk("irix_core_dump: %d segs taking %d bytes\n", segs, size); -#endif + pr_debug("irix_core_dump: %d segs taking %d bytes\n", segs, size); /* Set up header. */ memcpy(elf.e_ident, ELFMAG, SELFMAG); @@ -1221,7 +1248,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) struct elf_phdr phdr; int sz = 0; - for(i = 0; i < numnote; i++) + for (i = 0; i < numnote; i++) sz += notesize(¬es[i]); phdr.p_type = PT_NOTE; @@ -1241,7 +1268,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) dataoff = offset = roundup(offset, PAGE_SIZE); /* Write program headers for segments dump. */ - for(vma = current->mm->mmap, i = 0; + for (vma = current->mm->mmap, i = 0; i < segs && vma != NULL; vma = vma->vm_next) { struct elf_phdr phdr; size_t sz; @@ -1267,7 +1294,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) DUMP_WRITE(&phdr, sizeof(phdr)); } - for(i = 0; i < numnote; i++) + for (i = 0; i < numnote; i++) if (!writenote(¬es[i], file)) goto end_coredump; @@ -1275,7 +1302,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) DUMP_SEEK(dataoff); - for(i = 0, vma = current->mm->mmap; + for (i = 0, vma = current->mm->mmap; i < segs && vma != NULL; vma = vma->vm_next) { unsigned long addr = vma->vm_start; @@ -1284,9 +1311,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) if (!maydump(vma)) continue; i++; -#ifdef DEBUG - printk("elf_core_dump: writing %08lx %lx\n", addr, len); -#endif + pr_debug("elf_core_dump: writing %08lx %lx\n", addr, len); DUMP_WRITE((void __user *)addr, len); } diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c index bcaad6696082..2967537221e2 100644 --- a/arch/mips/kernel/irq-msc01.c +++ b/arch/mips/kernel/irq-msc01.c @@ -112,7 +112,7 @@ msc_bind_eic_interrupt (unsigned int irq, unsigned int set) } struct irq_chip msc_levelirq_type = { - .typename = "SOC-it-Level", + .name = "SOC-it-Level", .ack = level_mask_and_ack_msc_irq, .mask = mask_msc_irq, .mask_ack = level_mask_and_ack_msc_irq, @@ -122,7 +122,7 @@ struct irq_chip msc_levelirq_type = { }; struct irq_chip msc_edgeirq_type = { - .typename = "SOC-it-Edge", + .name = "SOC-it-Edge", .ack = edge_mask_and_ack_msc_irq, .mask = mask_msc_irq, .mask_ack = edge_mask_and_ack_msc_irq, diff --git a/arch/mips/kernel/irq-mv6434x.c b/arch/mips/kernel/irq-mv6434x.c index efbd219845b5..3dd561832e4c 100644 --- a/arch/mips/kernel/irq-mv6434x.c +++ b/arch/mips/kernel/irq-mv6434x.c @@ -23,13 +23,13 @@ static unsigned int irq_base; static inline int ls1bit32(unsigned int x) { - int b = 31, s; + int b = 31, s; - s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s; - s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s; - s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s; - s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s; - s = 1; if (x << 1 == 0) s = 0; b -= s; + s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s; + s = 8; if (x << 8 == 0) s = 0; b -= s; x <<= s; + s = 4; if (x << 4 == 0) s = 0; b -= s; x <<= s; + s = 2; if (x << 2 == 0) s = 0; b -= s; x <<= s; + s = 1; if (x << 1 == 0) s = 0; b -= s; return b; } @@ -92,7 +92,7 @@ void ll_mv64340_irq(void) } struct irq_chip mv64340_irq_type = { - .typename = "MV-64340", + .name = "MV-64340", .ack = mask_mv64340_irq, .mask = mask_mv64340_irq, .mask_ack = mask_mv64340_irq, diff --git a/arch/mips/kernel/irq-rm7000.c b/arch/mips/kernel/irq-rm7000.c index 123324ba8c14..250732883488 100644 --- a/arch/mips/kernel/irq-rm7000.c +++ b/arch/mips/kernel/irq-rm7000.c @@ -17,28 +17,27 @@ #include #include -static int irq_base; - static inline void unmask_rm7k_irq(unsigned int irq) { - set_c0_intcontrol(0x100 << (irq - irq_base)); + set_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE)); } static inline void mask_rm7k_irq(unsigned int irq) { - clear_c0_intcontrol(0x100 << (irq - irq_base)); + clear_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE)); } static struct irq_chip rm7k_irq_controller = { - .typename = "RM7000", + .name = "RM7000", .ack = mask_rm7k_irq, .mask = mask_rm7k_irq, .mask_ack = mask_rm7k_irq, .unmask = unmask_rm7k_irq, }; -void __init rm7k_cpu_irq_init(int base) +void __init rm7k_cpu_irq_init(void) { + int base = RM7K_CPU_IRQ_BASE; int i; clear_c0_intcontrol(0x00000f00); /* Mask all */ @@ -46,6 +45,4 @@ void __init rm7k_cpu_irq_init(int base) for (i = base; i < base + 4; i++) set_irq_chip_and_handler(i, &rm7k_irq_controller, handle_level_irq); - - irq_base = base; } diff --git a/arch/mips/kernel/irq-rm9000.c b/arch/mips/kernel/irq-rm9000.c index 0e6f4c5349d2..ae83d2df6f31 100644 --- a/arch/mips/kernel/irq-rm9000.c +++ b/arch/mips/kernel/irq-rm9000.c @@ -18,16 +18,14 @@ #include #include -static int irq_base; - static inline void unmask_rm9k_irq(unsigned int irq) { - set_c0_intcontrol(0x1000 << (irq - irq_base)); + set_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE)); } static inline void mask_rm9k_irq(unsigned int irq) { - clear_c0_intcontrol(0x1000 << (irq - irq_base)); + clear_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE)); } static inline void rm9k_cpu_irq_enable(unsigned int irq) @@ -39,15 +37,6 @@ static inline void rm9k_cpu_irq_enable(unsigned int irq) local_irq_restore(flags); } -static void rm9k_cpu_irq_disable(unsigned int irq) -{ - unsigned long flags; - - local_irq_save(flags); - mask_rm9k_irq(irq); - local_irq_restore(flags); -} - /* * Performance counter interrupts are global on all processors. */ @@ -81,7 +70,7 @@ static void rm9k_perfcounter_irq_shutdown(unsigned int irq) } static struct irq_chip rm9k_irq_controller = { - .typename = "RM9000", + .name = "RM9000", .ack = mask_rm9k_irq, .mask = mask_rm9k_irq, .mask_ack = mask_rm9k_irq, @@ -89,7 +78,7 @@ static struct irq_chip rm9k_irq_controller = { }; static struct irq_chip rm9k_perfcounter_irq = { - .typename = "RM9000", + .name = "RM9000", .startup = rm9k_perfcounter_irq_startup, .shutdown = rm9k_perfcounter_irq_shutdown, .ack = mask_rm9k_irq, @@ -102,8 +91,9 @@ unsigned int rm9000_perfcount_irq; EXPORT_SYMBOL(rm9000_perfcount_irq); -void __init rm9k_cpu_irq_init(int base) +void __init rm9k_cpu_irq_init(void) { + int base = RM9K_CPU_IRQ_BASE; int i; clear_c0_intcontrol(0x0000f000); /* Mask all */ @@ -115,6 +105,4 @@ void __init rm9k_cpu_irq_init(int base) rm9000_perfcount_irq = base + 1; set_irq_chip_and_handler(rm9000_perfcount_irq, &rm9k_perfcounter_irq, handle_level_irq); - - irq_base = base; } diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index fcc86b96ccf6..7b66e03b5899 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -25,7 +25,7 @@ * Don't even think about using this on SMP. You have been warned. * * This file exports one global function: - * void mips_cpu_irq_init(int irq_base); + * void mips_cpu_irq_init(void); */ #include #include @@ -36,22 +36,20 @@ #include #include -static int mips_cpu_irq_base; - static inline void unmask_mips_irq(unsigned int irq) { - set_c0_status(0x100 << (irq - mips_cpu_irq_base)); + set_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE)); irq_enable_hazard(); } static inline void mask_mips_irq(unsigned int irq) { - clear_c0_status(0x100 << (irq - mips_cpu_irq_base)); + clear_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE)); irq_disable_hazard(); } static struct irq_chip mips_cpu_irq_controller = { - .typename = "MIPS", + .name = "MIPS", .ack = mask_mips_irq, .mask = mask_mips_irq, .mask_ack = mask_mips_irq, @@ -70,7 +68,7 @@ static unsigned int mips_mt_cpu_irq_startup(unsigned int irq) { unsigned int vpflags = dvpe(); - clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); + clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE)); evpe(vpflags); unmask_mips_mt_irq(irq); @@ -84,13 +82,13 @@ static unsigned int mips_mt_cpu_irq_startup(unsigned int irq) static void mips_mt_cpu_irq_ack(unsigned int irq) { unsigned int vpflags = dvpe(); - clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); + clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE)); evpe(vpflags); mask_mips_mt_irq(irq); } static struct irq_chip mips_mt_cpu_irq_controller = { - .typename = "MIPS", + .name = "MIPS", .startup = mips_mt_cpu_irq_startup, .ack = mips_mt_cpu_irq_ack, .mask = mask_mips_mt_irq, @@ -99,8 +97,9 @@ static struct irq_chip mips_mt_cpu_irq_controller = { .eoi = unmask_mips_mt_irq, }; -void __init mips_cpu_irq_init(int irq_base) +void __init mips_cpu_irq_init(void) { + int irq_base = MIPS_CPU_IRQ_BASE; int i; /* Mask interrupts. */ @@ -118,6 +117,4 @@ void __init mips_cpu_irq_init(int irq_base) for (i = irq_base + 2; i < irq_base + 8; i++) set_irq_chip_and_handler(i, &mips_cpu_irq_controller, handle_level_irq); - - mips_cpu_irq_base = irq_base; } diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index de3fae260ff8..0b8ce59429a8 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -194,15 +194,15 @@ sysn32_waitid(int which, compat_pid_t pid, } struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - u16 procs; + s32 uptime; + u32 loads[3]; + u32 totalram; + u32 freeram; + u32 sharedram; + u32 bufferram; + u32 totalswap; + u32 freeswap; + u16 procs; u32 totalhigh; u32 freehigh; u32 mem_unit; @@ -558,7 +558,7 @@ extern asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf); asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32) { int err; - struct ustat tmp; + struct ustat tmp; struct ustat32 tmp32; mm_segment_t old_fs = get_fs(); @@ -569,11 +569,11 @@ asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32) if (err) goto out; - memset(&tmp32,0,sizeof(struct ustat32)); - tmp32.f_tfree = tmp.f_tfree; - tmp32.f_tinode = tmp.f_tinode; + memset(&tmp32,0,sizeof(struct ustat32)); + tmp32.f_tfree = tmp.f_tfree; + tmp32.f_tinode = tmp.f_tinode; - err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0; + err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0; out: return err; diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c index c1373a6e668b..a32f6797353a 100644 --- a/arch/mips/kernel/mips-mt.c +++ b/arch/mips/kernel/mips-mt.c @@ -96,6 +96,10 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, goto out_unlock; } + retval = security_task_setscheduler(p, 0, NULL); + if (retval) + goto out_unlock; + /* Record new user-specified CPU set for future reference */ p->thread.user_cpus_allowed = new_mask; @@ -141,8 +145,9 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len, p = find_process_by_pid(pid); if (!p) goto out_unlock; - - retval = 0; + retval = security_task_getscheduler(p); + if (retval) + goto out_unlock; cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map); diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 4ed37ba19731..5ddc2e9deecf 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -31,13 +31,13 @@ static const char *cpu_name[] = { [CPU_R4000PC] = "R4000PC", [CPU_R4000SC] = "R4000SC", [CPU_R4000MC] = "R4000MC", - [CPU_R4200] = "R4200", + [CPU_R4200] = "R4200", [CPU_R4400PC] = "R4400PC", [CPU_R4400SC] = "R4400SC", [CPU_R4400MC] = "R4400MC", [CPU_R4600] = "R4600", [CPU_R6000] = "R6000", - [CPU_R6000A] = "R6000A", + [CPU_R6000A] = "R6000A", [CPU_R8000] = "R8000", [CPU_R10000] = "R10000", [CPU_R12000] = "R12000", @@ -46,14 +46,14 @@ static const char *cpu_name[] = { [CPU_R4650] = "R4650", [CPU_R4700] = "R4700", [CPU_R5000] = "R5000", - [CPU_R5000A] = "R5000A", + [CPU_R5000A] = "R5000A", [CPU_R4640] = "R4640", [CPU_NEVADA] = "Nevada", [CPU_RM7000] = "RM7000", [CPU_RM9000] = "RM9000", [CPU_R5432] = "R5432", [CPU_4KC] = "MIPS 4Kc", - [CPU_5KC] = "MIPS 5Kc", + [CPU_5KC] = "MIPS 5Kc", [CPU_R4310] = "R4310", [CPU_SB1] = "SiByte SB1", [CPU_SB1A] = "SiByte SB1A", diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index ec8209f3a0c6..04e5b38d327d 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -41,10 +41,6 @@ #include #include #include -#ifdef CONFIG_MIPS_MT_SMTC -#include -extern void smtc_idle_loop_hook(void); -#endif /* CONFIG_MIPS_MT_SMTC */ /* * The idle thread. There's no useful work to be done, so just try to conserve @@ -57,6 +53,8 @@ ATTRIB_NORET void cpu_idle(void) while (1) { while (!need_resched()) { #ifdef CONFIG_MIPS_MT_SMTC + extern void smtc_idle_loop_hook(void); + smtc_idle_loop_hook(); #endif /* CONFIG_MIPS_MT_SMTC */ if (cpu_wait) diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 880fa6e841ee..59c1577ecbb3 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -114,6 +114,14 @@ LEAF(_save_fp_context32) */ LEAF(_restore_fp_context) EX lw t0, SC_FPC_CSR(a0) + + /* Fail if the CSR has exceptions pending */ + srl t1, t0, 5 + and t1, t0 + andi t1, 0x1f << 7 + bnez t1, fault + nop + #ifdef CONFIG_64BIT EX ldc1 $f1, SC_FPREGS+8(a0) EX ldc1 $f3, SC_FPREGS+24(a0) @@ -157,6 +165,14 @@ LEAF(_restore_fp_context) LEAF(_restore_fp_context32) /* Restore an o32 sigcontext. */ EX lw t0, SC32_FPC_CSR(a0) + + /* Fail if the CSR has exceptions pending */ + srl t1, t0, 5 + and t1, t0 + andi t1, 0x1f << 7 + bnez t1, fault + nop + EX ldc1 $f0, SC32_FPREGS+0(a0) EX ldc1 $f2, SC32_FPREGS+16(a0) EX ldc1 $f4, SC32_FPREGS+32(a0) @@ -177,9 +193,10 @@ LEAF(_restore_fp_context32) jr ra li v0, 0 # success END(_restore_fp_context32) - .set reorder #endif + .set reorder + .type fault@function .ent fault fault: li v0, -EFAULT # failure diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 5a99e3e0c96d..8610f4a925e9 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -63,7 +63,7 @@ extern void *vpe_get_shared(int index); static void rtlx_dispatch(void) { - do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ); + do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ); } @@ -491,7 +491,7 @@ static struct irqaction rtlx_irq = { .name = "RTLX", }; -static int rtlx_irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ; +static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ; static char register_chrdev_failed[] __initdata = KERN_ERR "rtlx_module_init: unable to register device\n"; diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index a7bff2a54723..39add2341aa2 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -384,7 +384,7 @@ EXPORT(sysn32_call_table) PTR sys_readlinkat PTR sys_fchmodat PTR sys_faccessat - PTR sys_pselect6 + PTR compat_sys_pselect6 PTR sys_ppoll /* 6265 */ PTR sys_unshare PTR sys_splice diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index e91379c1be1d..c58b8e0105ea 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -506,7 +506,7 @@ sys_call_table: PTR sys_readlinkat PTR sys_fchmodat PTR sys_faccessat /* 4300 */ - PTR sys_pselect6 + PTR compat_sys_pselect6 PTR sys_ppoll PTR sys_unshare PTR sys_splice diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 89440a0d8528..d2e01e7167b8 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -271,8 +271,7 @@ static void __init bootmem_init(void) static void __init bootmem_init(void) { unsigned long reserved_end; - unsigned long highest = 0; - unsigned long mapstart = -1UL; + unsigned long mapstart = ~0UL; unsigned long bootmap_size; int i; @@ -283,6 +282,13 @@ static void __init bootmem_init(void) */ reserved_end = max(init_initrd(), PFN_UP(__pa_symbol(&_end))); + /* + * max_low_pfn is not a number of pages. The number of pages + * of the system is given by 'max_low_pfn - min_low_pfn'. + */ + min_low_pfn = ~0UL; + max_low_pfn = 0; + /* * Find the highest page frame number we have available. */ @@ -296,8 +302,10 @@ static void __init bootmem_init(void) end = PFN_DOWN(boot_mem_map.map[i].addr + boot_mem_map.map[i].size); - if (end > highest) - highest = end; + if (end > max_low_pfn) + max_low_pfn = end; + if (start < min_low_pfn) + min_low_pfn = start; if (end <= reserved_end) continue; if (start >= mapstart) @@ -305,22 +313,36 @@ static void __init bootmem_init(void) mapstart = max(reserved_end, start); } + if (min_low_pfn >= max_low_pfn) + panic("Incorrect memory mapping !!!"); + if (min_low_pfn > ARCH_PFN_OFFSET) { + printk(KERN_INFO + "Wasting %lu bytes for tracking %lu unused pages\n", + (min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page), + min_low_pfn - ARCH_PFN_OFFSET); + } else if (min_low_pfn < ARCH_PFN_OFFSET) { + printk(KERN_INFO + "%lu free pages won't be used\n", + ARCH_PFN_OFFSET - min_low_pfn); + } + min_low_pfn = ARCH_PFN_OFFSET; + /* * Determine low and high memory ranges */ - if (highest > PFN_DOWN(HIGHMEM_START)) { + if (max_low_pfn > PFN_DOWN(HIGHMEM_START)) { #ifdef CONFIG_HIGHMEM highstart_pfn = PFN_DOWN(HIGHMEM_START); - highend_pfn = highest; + highend_pfn = max_low_pfn; #endif - highest = PFN_DOWN(HIGHMEM_START); + max_low_pfn = PFN_DOWN(HIGHMEM_START); } /* * Initialize the boot-time allocator with low memory only. */ - bootmap_size = init_bootmem(mapstart, highest); - + bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart, + min_low_pfn, max_low_pfn); /* * Register fully available low RAM pages with the bootmem allocator. */ @@ -507,9 +529,9 @@ void __init setup_arch(char **cmdline_p) #if defined(CONFIG_VT) #if defined(CONFIG_VGA_CONSOLE) - conswitchp = &vga_con; + conswitchp = &vga_con; #elif defined(CONFIG_DUMMY_CONSOLE) - conswitchp = &dummy_con; + conswitchp = &dummy_con; #endif #endif @@ -541,3 +563,6 @@ int __init dsp_disable(char *s) } __setup("nodsp", dsp_disable); + +unsigned long kernelsp[NR_CPUS]; +unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3; diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index b9d358e05214..9a44053cd9f1 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -89,7 +89,7 @@ _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) spin_lock_irq(¤t->sighand->siglock); current->saved_sigmask = current->blocked; current->blocked = newset; - recalc_sigpending(); + recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); current->state = TASK_INTERRUPTIBLE; @@ -124,7 +124,7 @@ asmlinkage int sys_sigaction(int sig, const struct sigaction __user *act, if (!ret && oact) { if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) - return -EFAULT; + return -EFAULT; err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); @@ -304,7 +304,7 @@ int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, current->comm, current->pid, frame, regs->cp0_epc, frame->regs[31]); #endif - return 0; + return 0; give_sigsegv: force_sigsegv(signr, current); diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index a67c18555ed3..b28646b3ceae 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -105,7 +105,7 @@ _sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) spin_lock_irq(¤t->sighand->siglock); current->saved_sigmask = current->blocked; current->blocked = newset; - recalc_sigpending(); + recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); current->state = TASK_INTERRUPTIBLE; @@ -184,7 +184,7 @@ int setup_rt_frame_n32(struct k_sigaction * ka, /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); err |= __put_user(0, &frame->rs_uc.uc_link); - sp = (int) (long) current->sas_ss_sp; + sp = (int) (long) current->sas_ss_sp; err |= __put_user(sp, &frame->rs_uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->regs[29]), diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 1ee689c0e0c9..64b62bdfb4f6 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c @@ -35,7 +35,6 @@ #include #include #include -#include /* This is f*cking wrong */ #define MIPS_CPU_IPI_RESCHED_IRQ 0 #define MIPS_CPU_IPI_CALL_IRQ 1 @@ -108,12 +107,12 @@ void __init sanitize_tlb_entries(void) static void ipi_resched_dispatch(void) { - do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ); + do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); } static void ipi_call_dispatch(void) { - do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ); + do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); } static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) @@ -270,8 +269,8 @@ void __init plat_prepare_cpus(unsigned int max_cpus) set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch); } - cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ; - cpu_ipi_call_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ; + cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ; + cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ; setup_irq(cpu_ipi_resched_irq, &irq_resched); setup_irq(cpu_ipi_call_irq, &irq_call); diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 6a857bf030b0..9251ea824937 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -26,16 +26,6 @@ * This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set. */ -/* - * MIPSCPU_INT_BASE is identically defined in both - * asm-mips/mips-boards/maltaint.h and asm-mips/mips-boards/simint.h, - * but as yet there's no properly organized include structure that - * will ensure that the right *int.h file will be included for a - * given platform build. - */ - -#define MIPSCPU_INT_BASE 16 - #define MIPS_CPU_IPI_IRQ 1 #define LOCK_MT_PRA() \ @@ -77,15 +67,15 @@ unsigned int ipi_timer_latch[NR_CPUS]; #define IPIBUF_PER_CPU 4 -struct smtc_ipi_q IPIQ[NR_CPUS]; -struct smtc_ipi_q freeIPIq; +static struct smtc_ipi_q IPIQ[NR_CPUS]; +static struct smtc_ipi_q freeIPIq; /* Forward declarations */ void ipi_decode(struct smtc_ipi *); -void post_direct_ipi(int cpu, struct smtc_ipi *pipi); -void setup_cross_vpe_interrupts(void); +static void post_direct_ipi(int cpu, struct smtc_ipi *pipi); +static void setup_cross_vpe_interrupts(void); void init_smtc_stats(void); /* Global SMTC Status */ @@ -200,7 +190,7 @@ void __init sanitize_tlb_entries(void) * Configure shared TLB - VPC configuration bit must be set by caller */ -void smtc_configure_tlb(void) +static void smtc_configure_tlb(void) { int i,tlbsiz,vpes; unsigned long mvpconf0; @@ -648,7 +638,7 @@ int setup_irq_smtc(unsigned int irq, struct irqaction * new, * the VPE. */ -void smtc_ipi_qdump(void) +static void smtc_ipi_qdump(void) { int i; @@ -686,28 +676,6 @@ static __inline__ int atomic_postincrement(unsigned int *pv) return result; } -/* No longer used in IPI dispatch, but retained for future recycling */ - -static __inline__ int atomic_postclear(unsigned int *pv) -{ - unsigned long result; - - unsigned long temp; - - __asm__ __volatile__( - "1: ll %0, %2 \n" - " or %1, $0, $0 \n" - " sc %1, %2 \n" - " beqz %1, 1b \n" - " sync \n" - : "=&r" (result), "=&r" (temp), "=m" (*pv) - : "m" (*pv) - : "memory"); - - return result; -} - - void smtc_send_ipi(int cpu, int type, unsigned int action) { int tcstatus; @@ -781,7 +749,7 @@ void smtc_send_ipi(int cpu, int type, unsigned int action) /* * Send IPI message to Halted TC, TargTC/TargVPE already having been set */ -void post_direct_ipi(int cpu, struct smtc_ipi *pipi) +static void post_direct_ipi(int cpu, struct smtc_ipi *pipi) { struct pt_regs *kstack; unsigned long tcstatus; @@ -921,7 +889,7 @@ void smtc_timer_broadcast(int vpe) * interrupts. */ -static int cpu_ipi_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_IRQ; +static int cpu_ipi_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_IRQ; static irqreturn_t ipi_interrupt(int irq, void *dev_idm) { @@ -1000,7 +968,7 @@ static void ipi_irq_dispatch(void) static struct irqaction irq_ipi; -void setup_cross_vpe_interrupts(void) +static void setup_cross_vpe_interrupts(void) { if (!cpu_has_vint) panic("SMTC Kernel requires Vectored Interupt support"); @@ -1191,7 +1159,7 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) * It would be nice to be able to use a spinlock here, * but this is invoked from within TLB flush routines * that protect themselves with DVPE, so if a lock is - * held by another TC, it'll never be freed. + * held by another TC, it'll never be freed. * * DVPE/DMT must not be done with interrupts enabled, * so even so most callers will already have disabled @@ -1296,7 +1264,7 @@ void smtc_flush_tlb_asid(unsigned long asid) * Support for single-threading cache flush operations. */ -int halt_state_save[NR_CPUS]; +static int halt_state_save[NR_CPUS]; /* * To really, really be sure that nothing is being done diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 6c2406a93f2b..93a148486f88 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -669,7 +669,7 @@ asmlinkage int irix_mount(char __user *dev_name, char __user *dir_name, struct irix_statfs { short f_type; - long f_bsize, f_frsize, f_blocks, f_bfree, f_files, f_ffree; + long f_bsize, f_frsize, f_blocks, f_bfree, f_files, f_ffree; char f_fname[6], f_fpack[6]; }; @@ -959,7 +959,7 @@ static inline loff_t llseek(struct file *file, loff_t offset, int origin) fn = default_llseek; if (file->f_op && file->f_op->llseek) - fn = file->f_op->llseek; + fn = file->f_op->llseek; lock_kernel(); retval = fn(file, offset, origin); unlock_kernel(); diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 458fccf87c54..459624969c99 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -522,7 +522,7 @@ static int (*reloc_handlers[]) (struct module *me, uint32_t *location, }; static char *rstrs[] = { - [R_MIPS_NONE] = "MIPS_NONE", + [R_MIPS_NONE] = "MIPS_NONE", [R_MIPS_32] = "MIPS_32", [R_MIPS_26] = "MIPS_26", [R_MIPS_HI16] = "MIPS_HI16", @@ -695,7 +695,7 @@ static void dump_tclist(void) } /* We are prepared so configure and start the VPE... */ -int vpe_run(struct vpe * v) +static int vpe_run(struct vpe * v) { struct vpe_notifications *n; unsigned long val, dmt_flag; @@ -713,16 +713,16 @@ int vpe_run(struct vpe * v) dvpe(); if (!list_empty(&v->tc)) { - if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { - printk(KERN_WARNING "VPE loader: TC %d is already in use.\n", - t->index); - return -ENOEXEC; - } - } else { - printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n", - v->minor); - return -ENOEXEC; - } + if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { + printk(KERN_WARNING "VPE loader: TC %d is already in use.\n", + t->index); + return -ENOEXEC; + } + } else { + printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n", + v->minor); + return -ENOEXEC; + } /* Put MVPE's into 'configuration state' */ set_c0_mvpcontrol(MVPCONTROL_VPC); @@ -775,14 +775,14 @@ int vpe_run(struct vpe * v) back_to_back_c0_hazard(); - /* Set up the XTC bit in vpeconf0 to point at our tc */ - write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC)) - | (t->index << VPECONF0_XTC_SHIFT)); + /* Set up the XTC bit in vpeconf0 to point at our tc */ + write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC)) + | (t->index << VPECONF0_XTC_SHIFT)); back_to_back_c0_hazard(); - /* enable this VPE */ - write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); + /* enable this VPE */ + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); /* clear out any left overs from a previous program */ write_vpe_c0_status(0); @@ -832,7 +832,7 @@ static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, * contents of the program (p)buffer performing relocatations/etc, free's it * when finished. */ -int vpe_elfload(struct vpe * v) +static int vpe_elfload(struct vpe * v) { Elf_Ehdr *hdr; Elf_Shdr *sechdrs; diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c index 2affa5ff171c..9a622b9a1051 100644 --- a/arch/mips/lasat/interrupt.c +++ b/arch/mips/lasat/interrupt.c @@ -45,7 +45,7 @@ void enable_lasat_irq(unsigned int irq_nr) } static struct irq_chip lasat_irq_type = { - .typename = "Lasat", + .name = "Lasat", .ack = disable_lasat_irq, .mask = disable_lasat_irq, .mask_ack = disable_lasat_irq, diff --git a/arch/mips/lasat/prom.c b/arch/mips/lasat/prom.c index 88c7ab871ec4..d47692f73a26 100644 --- a/arch/mips/lasat/prom.c +++ b/arch/mips/lasat/prom.c @@ -132,9 +132,8 @@ void __init prom_init(void) add_memory_region(0, lasat_board_info.li_memsize, BOOT_MEM_RAM); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } const char *get_system_type(void) diff --git a/arch/mips/lib-32/Makefile b/arch/mips/lib-32/Makefile index dcd4d2ed2ac4..2036cf5e6857 100644 --- a/arch/mips/lib-32/Makefile +++ b/arch/mips/lib-32/Makefile @@ -2,7 +2,7 @@ # Makefile for MIPS-specific library files.. # -lib-y += memset.o watch.o +lib-y += watch.o obj-$(CONFIG_CPU_MIPS32) += dump_tlb.o obj-$(CONFIG_CPU_MIPS64) += dump_tlb.o diff --git a/arch/mips/lib-64/Makefile b/arch/mips/lib-64/Makefile index dcd4d2ed2ac4..2036cf5e6857 100644 --- a/arch/mips/lib-64/Makefile +++ b/arch/mips/lib-64/Makefile @@ -2,7 +2,7 @@ # Makefile for MIPS-specific library files.. # -lib-y += memset.o watch.o +lib-y += watch.o obj-$(CONFIG_CPU_MIPS32) += dump_tlb.o obj-$(CONFIG_CPU_MIPS64) += dump_tlb.o diff --git a/arch/mips/lib-64/memset.S b/arch/mips/lib-64/memset.S deleted file mode 100644 index e2c42c85113b..000000000000 --- a/arch/mips/lib-64/memset.S +++ /dev/null @@ -1,142 +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) 1998, 1999, 2000 by Ralf Baechle - * Copyright (C) 1999, 2000 Silicon Graphics, Inc. - */ -#include -#include -#include - -#define EX(insn,reg,addr,handler) \ -9: insn reg, addr; \ - .section __ex_table,"a"; \ - PTR 9b, handler; \ - .previous - - .macro f_fill64 dst, offset, val, fixup - EX(LONG_S, \val, (\offset + 0 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 1 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 2 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 3 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 4 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 5 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 6 * LONGSIZE)(\dst), \fixup) - EX(LONG_S, \val, (\offset + 7 * LONGSIZE)(\dst), \fixup) - .endm - -/* - * memset(void *s, int c, size_t n) - * - * a0: start of area to clear - * a1: char to fill with - * a2: size of area to clear - */ - .set noreorder - .align 5 -LEAF(memset) - beqz a1, 1f - move v0, a0 /* result */ - - andi a1, 0xff /* spread fillword */ - dsll t1, a1, 8 - or a1, t1 - dsll t1, a1, 16 - or a1, t1 - dsll t1, a1, 32 - or a1, t1 -1: - -FEXPORT(__bzero) - sltiu t0, a2, LONGSIZE /* very small region? */ - bnez t0, small_memset - andi t0, a0, LONGMASK /* aligned? */ - - beqz t0, 1f - PTR_SUBU t0, LONGSIZE /* alignment in bytes */ - -#ifdef __MIPSEB__ - EX(sdl, a1, (a0), first_fixup) /* make dword aligned */ -#endif -#ifdef __MIPSEL__ - EX(sdr, a1, (a0), first_fixup) /* make dword aligned */ -#endif - PTR_SUBU a0, t0 /* long align ptr */ - PTR_ADDU a2, t0 /* correct size */ - -1: ori t1, a2, 0x3f /* # of full blocks */ - xori t1, 0x3f - beqz t1, memset_partial /* no block to fill */ - andi t0, a2, 0x38 - - PTR_ADDU t1, a0 /* end address */ - .set reorder -1: PTR_ADDIU a0, 64 - f_fill64 a0, -64, a1, fwd_fixup - bne t1, a0, 1b - .set noreorder - -memset_partial: - PTR_LA t1, 2f /* where to start */ - .set noat - dsrl AT, t0, 1 - PTR_SUBU t1, AT - .set noat - jr t1 - PTR_ADDU a0, t0 /* dest ptr */ - - .set push - .set noreorder - .set nomacro - f_fill64 a0, -64, a1, partial_fixup /* ... but first do longs ... */ -2: .set pop - andi a2, LONGMASK /* At most one long to go */ - - beqz a2, 1f - PTR_ADDU a0, a2 /* What's left */ -#ifdef __MIPSEB__ - EX(sdr, a1, -1(a0), last_fixup) -#endif -#ifdef __MIPSEL__ - EX(sdl, a1, -1(a0), last_fixup) -#endif -1: jr ra - move a2, zero - -small_memset: - beqz a2, 2f - PTR_ADDU t1, a0, a2 - -1: PTR_ADDIU a0, 1 /* fill bytewise */ - bne t1, a0, 1b - sb a1, -1(a0) - -2: jr ra /* done */ - move a2, zero - END(memset) - -first_fixup: - jr ra - nop - -fwd_fixup: - PTR_L t0, TI_TASK($28) - LONG_L t0, THREAD_BUADDR(t0) - andi a2, 0x3f - LONG_ADDU a2, t1 - jr ra - LONG_SUBU a2, t0 - -partial_fixup: - PTR_L t0, TI_TASK($28) - LONG_L t0, THREAD_BUADDR(t0) - andi a2, LONGMASK - LONG_ADDU a2, t1 - jr ra - LONG_SUBU a2, t0 - -last_fixup: - jr ra - andi v1, a2, LONGMASK diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index 989c900b8b14..5ad501b30b43 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for MIPS-specific library files.. # -lib-y += csum_partial.o memcpy.o promlib.o \ +lib-y += csum_partial.o memcpy.o memset.o promlib.o \ strlen_user.o strncpy_user.o strnlen_user.o uncached.o obj-y += iomap.o diff --git a/arch/mips/lib-32/memset.S b/arch/mips/lib/memset.S similarity index 85% rename from arch/mips/lib-32/memset.S rename to arch/mips/lib/memset.S index 1981485bd48b..3f8b8b3d0b23 100644 --- a/arch/mips/lib-32/memset.S +++ b/arch/mips/lib/memset.S @@ -10,6 +10,14 @@ #include #include +#if LONGSIZE == 4 +#define LONG_S_L swl +#define LONG_S_R swr +#else +#define LONG_S_L sdl +#define LONG_S_R sdr +#endif + #define EX(insn,reg,addr,handler) \ 9: insn reg, addr; \ .section __ex_table,"a"; \ @@ -25,6 +33,7 @@ EX(LONG_S, \val, (\offset + 5 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 6 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 7 * LONGSIZE)(\dst), \fixup) +#if LONGSIZE == 4 EX(LONG_S, \val, (\offset + 8 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 9 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 10 * LONGSIZE)(\dst), \fixup) @@ -33,6 +42,7 @@ EX(LONG_S, \val, (\offset + 13 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 14 * LONGSIZE)(\dst), \fixup) EX(LONG_S, \val, (\offset + 15 * LONGSIZE)(\dst), \fixup) +#endif .endm /* @@ -49,9 +59,13 @@ LEAF(memset) move v0, a0 /* result */ andi a1, 0xff /* spread fillword */ - sll t1, a1, 8 + LONG_SLL t1, a1, 8 or a1, t1 - sll t1, a1, 16 + LONG_SLL t1, a1, 16 +#if LONGSIZE == 8 + or a1, t1 + LONG_SLL t1, a1, 32 +#endif or a1, t1 1: @@ -64,10 +78,10 @@ FEXPORT(__bzero) PTR_SUBU t0, LONGSIZE /* alignment in bytes */ #ifdef __MIPSEB__ - EX(swl, a1, (a0), first_fixup) /* make word aligned */ + EX(LONG_S_L, a1, (a0), first_fixup) /* make word/dword aligned */ #endif #ifdef __MIPSEL__ - EX(swr, a1, (a0), first_fixup) /* make word aligned */ + EX(LONG_S_R, a1, (a0), first_fixup) /* make word/dword aligned */ #endif PTR_SUBU a0, t0 /* long align ptr */ PTR_ADDU a2, t0 /* correct size */ @@ -75,7 +89,7 @@ FEXPORT(__bzero) 1: ori t1, a2, 0x3f /* # of full blocks */ xori t1, 0x3f beqz t1, memset_partial /* no block to fill */ - andi t0, a2, 0x3c + andi t0, a2, 0x40-LONGSIZE PTR_ADDU t1, a0 /* end address */ .set reorder @@ -86,7 +100,14 @@ FEXPORT(__bzero) memset_partial: PTR_LA t1, 2f /* where to start */ +#if LONGSIZE == 4 PTR_SUBU t1, t0 +#else + .set noat + LONG_SRL AT, t0, 1 + PTR_SUBU t1, AT + .set noat +#endif jr t1 PTR_ADDU a0, t0 /* dest ptr */ @@ -100,10 +121,10 @@ memset_partial: beqz a2, 1f PTR_ADDU a0, a2 /* What's left */ #ifdef __MIPSEB__ - EX(swr, a1, -1(a0), last_fixup) + EX(LONG_S_R, a1, -1(a0), last_fixup) #endif #ifdef __MIPSEL__ - EX(swl, a1, -1(a0), last_fixup) + EX(LONG_S_L, a1, -1(a0), last_fixup) #endif 1: jr ra move a2, zero diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c index 98ce89f8068b..2388f7f3ffde 100644 --- a/arch/mips/lib/uncached.c +++ b/arch/mips/lib/uncached.c @@ -44,20 +44,24 @@ unsigned long __init run_uncached(void *func) if (sp >= (long)CKSEG0 && sp < (long)CKSEG2) usp = CKSEG1ADDR(sp); +#ifdef CONFIG_64BIT else if ((long long)sp >= (long long)PHYS_TO_XKPHYS(0LL, 0) && (long long)sp < (long long)PHYS_TO_XKPHYS(8LL, 0)) usp = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED, XKPHYS_TO_PHYS((long long)sp)); +#endif else { BUG(); usp = sp; } if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2) ufunc = CKSEG1ADDR(lfunc); +#ifdef CONFIG_64BIT else if ((long long)lfunc >= (long long)PHYS_TO_XKPHYS(0LL, 0) && (long long)lfunc < (long long)PHYS_TO_XKPHYS(8LL, 0)) ufunc = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED, XKPHYS_TO_PHYS((long long)lfunc)); +#endif else { BUG(); ufunc = lfunc; diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c index 43dba6ce6603..dfa0acbd7fc2 100644 --- a/arch/mips/mips-boards/atlas/atlas_int.c +++ b/arch/mips/mips-boards/atlas/atlas_int.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -69,7 +70,7 @@ static void end_atlas_irq(unsigned int irq) } static struct irq_chip atlas_irq_type = { - .typename = "Atlas", + .name = "Atlas", .ack = disable_atlas_irq, .mask = disable_atlas_irq, .mask_ack = disable_atlas_irq, @@ -220,7 +221,7 @@ msc_irqmap_t __initdata msc_irqmap[] = { {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, }; -int __initdata msc_nr_irqs = sizeof(msc_irqmap) / sizeof(*msc_irqmap); +int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap); msc_irqmap_t __initdata msc_eicirqmap[] = { {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, @@ -231,14 +232,14 @@ msc_irqmap_t __initdata msc_eicirqmap[] = { {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} }; -int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap) / sizeof(*msc_eicirqmap); +int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap); void __init arch_init_irq(void) { init_atlas_irqs(ATLAS_INT_BASE); if (!cpu_has_veic) - mips_cpu_irq_init(MIPSCPU_INT_BASE); + mips_cpu_irq_init(); switch(mips_revision_corid) { case MIPS_REVISION_CORID_CORE_MSC: diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c index eeed944e0f83..ebf0e16c5a0d 100644 --- a/arch/mips/mips-boards/generic/memory.c +++ b/arch/mips/mips-boards/generic/memory.c @@ -166,9 +166,8 @@ void __init prom_meminit(void) } } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - unsigned long freed = 0; unsigned long addr; int i; @@ -176,17 +175,8 @@ unsigned long __init prom_free_prom_memory(void) if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) continue; - addr = PAGE_ALIGN(boot_mem_map.map[i].addr); - while (addr < boot_mem_map.map[i].addr - + boot_mem_map.map[i].size) { - ClearPageReserved(virt_to_page(__va(addr))); - init_page_count(virt_to_page(__va(addr))); - free_page((unsigned long)__va(addr)); - addr += PAGE_SIZE; - freed += PAGE_SIZE; - } + addr = boot_mem_map.map[i].addr; + free_init_pages("prom memory", + addr, addr + boot_mem_map.map[i].size); } - printk("Freeing prom memory: %ldkb freed\n", freed >> 10); - - return freed; } diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c index 90ad5bf3e2f1..3c206bb17160 100644 --- a/arch/mips/mips-boards/malta/malta_int.c +++ b/arch/mips/mips-boards/malta/malta_int.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -289,7 +290,7 @@ msc_irqmap_t __initdata msc_irqmap[] = { {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, }; -int __initdata msc_nr_irqs = sizeof(msc_irqmap)/sizeof(msc_irqmap_t); +int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap); msc_irqmap_t __initdata msc_eicirqmap[] = { {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, @@ -303,14 +304,14 @@ msc_irqmap_t __initdata msc_eicirqmap[] = { {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} }; -int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t); +int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap); void __init arch_init_irq(void) { init_i8259_irqs(); if (!cpu_has_veic) - mips_cpu_irq_init (MIPSCPU_INT_BASE); + mips_cpu_irq_init(); switch(mips_revision_corid) { case MIPS_REVISION_CORID_CORE_MSC: diff --git a/arch/mips/mips-boards/sead/sead_int.c b/arch/mips/mips-boards/sead/sead_int.c index 874ccb0066b8..c4b9de3a7f27 100644 --- a/arch/mips/mips-boards/sead/sead_int.c +++ b/arch/mips/mips-boards/sead/sead_int.c @@ -113,5 +113,5 @@ asmlinkage void plat_irq_dispatch(void) void __init arch_init_irq(void) { - mips_cpu_irq_init(MIPSCPU_INT_BASE); + mips_cpu_irq_init(); } diff --git a/arch/mips/mips-boards/sim/sim_int.c b/arch/mips/mips-boards/sim/sim_int.c index 2ce449dce6f2..15ac0655c1ff 100644 --- a/arch/mips/mips-boards/sim/sim_int.c +++ b/arch/mips/mips-boards/sim/sim_int.c @@ -21,9 +21,7 @@ #include #include #include - - -extern void mips_cpu_irq_init(int); +#include static inline int clz(unsigned long x) { @@ -86,5 +84,5 @@ asmlinkage void plat_irq_dispatch(void) void __init arch_init_irq(void) { - mips_cpu_irq_init(MIPSCPU_INT_BASE); + mips_cpu_irq_init(); } diff --git a/arch/mips/mips-boards/sim/sim_mem.c b/arch/mips/mips-boards/sim/sim_mem.c index f7ce76983328..46bc16f8b15d 100644 --- a/arch/mips/mips-boards/sim/sim_mem.c +++ b/arch/mips/mips-boards/sim/sim_mem.c @@ -99,10 +99,9 @@ void __init prom_meminit(void) } } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { int i; - unsigned long freed = 0; unsigned long addr; for (i = 0; i < boot_mem_map.nr_map; i++) { @@ -110,16 +109,7 @@ unsigned long __init prom_free_prom_memory(void) continue; addr = boot_mem_map.map[i].addr; - while (addr < boot_mem_map.map[i].addr - + boot_mem_map.map[i].size) { - ClearPageReserved(virt_to_page(__va(addr))); - init_page_count(virt_to_page(__va(addr))); - free_page((unsigned long)__va(addr)); - addr += PAGE_SIZE; - freed += PAGE_SIZE; - } + free_init_pages("prom memory", + addr, addr + boot_mem_map.map[i].size); } - printk("Freeing prom memory: %ldkb freed\n", freed >> 10); - - return freed; } diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 49065c133ebf..125a4a85ec05 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -341,7 +341,6 @@ static int __init page_is_ram(unsigned long pagenr) void __init paging_init(void) { unsigned long zones_size[MAX_NR_ZONES] = { 0, }; - unsigned long max_dma, low; #ifndef CONFIG_FLATMEM unsigned long zholes_size[MAX_NR_ZONES] = { 0, }; unsigned long i, j, pfn; @@ -354,19 +353,19 @@ void __init paging_init(void) #endif kmap_coherent_init(); - max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; - low = max_low_pfn; - #ifdef CONFIG_ISA - if (low < max_dma) - zones_size[ZONE_DMA] = low; - else { - zones_size[ZONE_DMA] = max_dma; - zones_size[ZONE_NORMAL] = low - max_dma; - } -#else - zones_size[ZONE_DMA] = low; + if (max_low_pfn >= MAX_DMA_PFN) + if (min_low_pfn >= MAX_DMA_PFN) { + zones_size[ZONE_DMA] = 0; + zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn; + } else { + zones_size[ZONE_DMA] = MAX_DMA_PFN - min_low_pfn; + zones_size[ZONE_NORMAL] = max_low_pfn - MAX_DMA_PFN; + } + else #endif + zones_size[ZONE_DMA] = max_low_pfn - min_low_pfn; + #ifdef CONFIG_HIGHMEM zones_size[ZONE_HIGHMEM] = highend_pfn - highstart_pfn; @@ -467,7 +466,7 @@ void __init mem_init(void) } #endif /* !CONFIG_NEED_MULTIPLE_NODES */ -static void free_init_pages(char *what, unsigned long begin, unsigned long end) +void free_init_pages(const char *what, unsigned long begin, unsigned long end) { unsigned long pfn; @@ -493,18 +492,25 @@ void free_initrd_mem(unsigned long start, unsigned long end) } #endif -extern unsigned long prom_free_prom_memory(void); - void free_initmem(void) { - unsigned long freed; - - freed = prom_free_prom_memory(); - if (freed) - printk(KERN_INFO "Freeing firmware memory: %ldkb freed\n", - freed >> 10); - + prom_free_prom_memory(); free_init_pages("unused kernel memory", __pa_symbol(&__init_begin), __pa_symbol(&__init_end)); } + +unsigned long pgd_current[NR_CPUS]; +/* + * On 64-bit we've got three-level pagetables with a slightly + * different layout ... + */ +#define __page_aligned(order) __attribute__((__aligned__(PAGE_SIZE< +#include +#include +#include +#include + +#include "jaguar_atx_fpga.h" + +#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) + +static struct resource mv643xx_eth_shared_resources[] = { + [0] = { + .name = "ethernet shared base", + .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS, + .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS + + MV643XX_ETH_SHARED_REGS_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device mv643xx_eth_shared_device = { + .name = MV643XX_ETH_SHARED_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(mv643xx_eth_shared_resources), + .resource = mv643xx_eth_shared_resources, +}; + +#define MV_SRAM_BASE 0xfe000000UL +#define MV_SRAM_SIZE (256 * 1024) + +#define MV_SRAM_RXRING_SIZE (MV_SRAM_SIZE / 4) +#define MV_SRAM_TXRING_SIZE (MV_SRAM_SIZE / 4) + +#define MV_SRAM_BASE_ETH0 MV_SRAM_BASE +#define MV_SRAM_BASE_ETH1 (MV_SRAM_BASE + (MV_SRAM_SIZE / 2)) + +#define MV64x60_IRQ_ETH_0 48 +#define MV64x60_IRQ_ETH_1 49 +#define MV64x60_IRQ_ETH_2 50 + +#ifdef CONFIG_MV643XX_ETH_0 + +static struct resource mv64x60_eth0_resources[] = { + [0] = { + .name = "eth0 irq", + .start = MV64x60_IRQ_ETH_0, + .end = MV64x60_IRQ_ETH_0, + .flags = IORESOURCE_IRQ, + }, +}; + +static char eth0_mac_addr[ETH_ALEN]; + +static struct mv643xx_eth_platform_data eth0_pd = { + .mac_addr = eth0_mac_addr, + + .tx_sram_addr = MV_SRAM_BASE_ETH0, + .tx_sram_size = MV_SRAM_TXRING_SIZE, + .tx_queue_size = MV_SRAM_TXRING_SIZE / 16, + + .rx_sram_addr = MV_SRAM_BASE_ETH0 + MV_SRAM_TXRING_SIZE, + .rx_sram_size = MV_SRAM_RXRING_SIZE, + .rx_queue_size = MV_SRAM_RXRING_SIZE / 16, +}; + +static struct platform_device eth0_device = { + .name = MV643XX_ETH_NAME, + .id = 0, + .num_resources = ARRAY_SIZE(mv64x60_eth0_resources), + .resource = mv64x60_eth0_resources, + .dev = { + .platform_data = ð0_pd, + }, +}; +#endif /* CONFIG_MV643XX_ETH_0 */ + +#ifdef CONFIG_MV643XX_ETH_1 + +static struct resource mv64x60_eth1_resources[] = { + [0] = { + .name = "eth1 irq", + .start = MV64x60_IRQ_ETH_1, + .end = MV64x60_IRQ_ETH_1, + .flags = IORESOURCE_IRQ, + }, +}; + +static char eth1_mac_addr[ETH_ALEN]; + +static struct mv643xx_eth_platform_data eth1_pd = { + .mac_addr = eth1_mac_addr, + + .tx_sram_addr = MV_SRAM_BASE_ETH1, + .tx_sram_size = MV_SRAM_TXRING_SIZE, + .tx_queue_size = MV_SRAM_TXRING_SIZE / 16, + + .rx_sram_addr = MV_SRAM_BASE_ETH1 + MV_SRAM_TXRING_SIZE, + .rx_sram_size = MV_SRAM_RXRING_SIZE, + .rx_queue_size = MV_SRAM_RXRING_SIZE / 16, +}; + +static struct platform_device eth1_device = { + .name = MV643XX_ETH_NAME, + .id = 1, + .num_resources = ARRAY_SIZE(mv64x60_eth1_resources), + .resource = mv64x60_eth1_resources, + .dev = { + .platform_data = ð1_pd, + }, +}; +#endif /* CONFIG_MV643XX_ETH_1 */ + +#ifdef CONFIG_MV643XX_ETH_2 + +static struct resource mv64x60_eth2_resources[] = { + [0] = { + .name = "eth2 irq", + .start = MV64x60_IRQ_ETH_2, + .end = MV64x60_IRQ_ETH_2, + .flags = IORESOURCE_IRQ, + }, +}; + +static char eth2_mac_addr[ETH_ALEN]; + +static struct mv643xx_eth_platform_data eth2_pd = { + .mac_addr = eth2_mac_addr, +}; + +static struct platform_device eth2_device = { + .name = MV643XX_ETH_NAME, + .id = 1, + .num_resources = ARRAY_SIZE(mv64x60_eth2_resources), + .resource = mv64x60_eth2_resources, + .dev = { + .platform_data = ð2_pd, + }, +}; +#endif /* CONFIG_MV643XX_ETH_2 */ + +static struct platform_device *mv643xx_eth_pd_devs[] __initdata = { + &mv643xx_eth_shared_device, +#ifdef CONFIG_MV643XX_ETH_0 + ð0_device, +#endif +#ifdef CONFIG_MV643XX_ETH_1 + ð1_device, +#endif +#ifdef CONFIG_MV643XX_ETH_2 + ð2_device, +#endif +}; + +static u8 __init exchange_bit(u8 val, u8 cs) +{ + /* place the data */ + JAGUAR_FPGA_WRITE((val << 2) | cs, EEPROM_MODE); + udelay(1); + + /* turn the clock on */ + JAGUAR_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE); + udelay(1); + + /* turn the clock off and read-strobe */ + JAGUAR_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE); + + /* return the data */ + return (JAGUAR_FPGA_READ(EEPROM_MODE) >> 3) & 0x1; +} + +static void __init get_mac(char dest[6]) +{ + u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int i,j; + + for (i = 0; i < 12; i++) + exchange_bit(read_opcode[i], 1); + + for (j = 0; j < 6; j++) { + dest[j] = 0; + for (i = 0; i < 8; i++) { + dest[j] <<= 1; + dest[j] |= exchange_bit(0, 1); + } + } + + /* turn off CS */ + exchange_bit(0,0); +} + +/* + * Copy and increment ethernet MAC address by a small value. + * + * This is useful for systems where the only one MAC address is stored in + * non-volatile memory for multiple ports. + */ +static inline void eth_mac_add(unsigned char *dst, unsigned char *src, + unsigned int add) +{ + int i; + + BUG_ON(add >= 256); + + for (i = ETH_ALEN; i >= 0; i--) { + dst[i] = src[i] + add; + add = dst[i] < src[i]; /* compute carry */ + } + + WARN_ON(add); +} + +static int __init mv643xx_eth_add_pds(void) +{ + unsigned char mac[ETH_ALEN]; + int ret; + + get_mac(mac); +#ifdef CONFIG_MV643XX_ETH_0 + eth_mac_add(eth1_mac_addr, mac, 0); +#endif +#ifdef CONFIG_MV643XX_ETH_1 + eth_mac_add(eth1_mac_addr, mac, 1); +#endif +#ifdef CONFIG_MV643XX_ETH_2 + eth_mac_add(eth2_mac_addr, mac, 2); +#endif + ret = platform_add_devices(mv643xx_eth_pd_devs, + ARRAY_SIZE(mv643xx_eth_pd_devs)); + + return ret; +} + +device_initcall(mv643xx_eth_add_pds); + +#endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */ diff --git a/arch/mips/momentum/jaguar_atx/prom.c b/arch/mips/momentum/jaguar_atx/prom.c index 3d2712929293..5dd154ee58f6 100644 --- a/arch/mips/momentum/jaguar_atx/prom.c +++ b/arch/mips/momentum/jaguar_atx/prom.c @@ -39,56 +39,6 @@ const char *get_system_type(void) return "Momentum Jaguar-ATX"; } -#ifdef CONFIG_MV643XX_ETH -extern unsigned char prom_mac_addr_base[6]; - -static void burn_clocks(void) -{ - int i; - - /* this loop should burn at least 1us -- this should be plenty */ - for (i = 0; i < 0x10000; i++) - ; -} - -static u8 exchange_bit(u8 val, u8 cs) -{ - /* place the data */ - JAGUAR_FPGA_WRITE((val << 2) | cs, EEPROM_MODE); - burn_clocks(); - - /* turn the clock on */ - JAGUAR_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE); - burn_clocks(); - - /* turn the clock off and read-strobe */ - JAGUAR_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE); - - /* return the data */ - return ((JAGUAR_FPGA_READ(EEPROM_MODE) >> 3) & 0x1); -} - -void get_mac(char dest[6]) -{ - u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - int i,j; - - for (i = 0; i < 12; i++) - exchange_bit(read_opcode[i], 1); - - for (j = 0; j < 6; j++) { - dest[j] = 0; - for (i = 0; i < 8; i++) { - dest[j] <<= 1; - dest[j] |= exchange_bit(0, 1); - } - } - - /* turn off CS */ - exchange_bit(0,0); -} -#endif - #ifdef CONFIG_64BIT unsigned long signext(unsigned long addr) @@ -228,16 +178,10 @@ void __init prom_init(void) #endif /* CONFIG_64BIT */ mips_machgroup = MACH_GROUP_MOMENCO; mips_machtype = MACH_MOMENCO_JAGUAR_ATX; - -#ifdef CONFIG_MV643XX_ETH - /* get the base MAC address for on-board ethernet ports */ - get_mac(prom_mac_addr_base); -#endif } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } void __init prom_fixup_mem_map(unsigned long start, unsigned long end) diff --git a/arch/mips/momentum/ocelot_3/irq.c b/arch/mips/momentum/ocelot_3/irq.c index cea0e5deb80e..3862d1d1add4 100644 --- a/arch/mips/momentum/ocelot_3/irq.c +++ b/arch/mips/momentum/ocelot_3/irq.c @@ -65,7 +65,7 @@ void __init arch_init_irq(void) */ clear_c0_status(ST0_IM | ST0_BEV); - rm7k_cpu_irq_init(8); + rm7k_cpu_irq_init(); /* set up the cascading interrupts */ setup_irq(8, &cascade_mv64340); /* unmask intControl IM8, IRQ 9 */ diff --git a/arch/mips/momentum/ocelot_3/prom.c b/arch/mips/momentum/ocelot_3/prom.c index 6ce9b7fdb824..8e02df63578a 100644 --- a/arch/mips/momentum/ocelot_3/prom.c +++ b/arch/mips/momentum/ocelot_3/prom.c @@ -180,9 +180,8 @@ void __init prom_init(void) #endif } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } void __init prom_fixup_mem_map(unsigned long start, unsigned long end) diff --git a/arch/mips/momentum/ocelot_c/cpci-irq.c b/arch/mips/momentum/ocelot_c/cpci-irq.c index bb11fef08472..186a140fd2a9 100644 --- a/arch/mips/momentum/ocelot_c/cpci-irq.c +++ b/arch/mips/momentum/ocelot_c/cpci-irq.c @@ -84,7 +84,7 @@ void ll_cpci_irq(void) } struct irq_chip cpci_irq_type = { - .typename = "CPCI/FPGA", + .name = "CPCI/FPGA", .ack = mask_cpci_irq, .mask = mask_cpci_irq, .mask_ack = mask_cpci_irq, diff --git a/arch/mips/momentum/ocelot_c/dbg_io.c b/arch/mips/momentum/ocelot_c/dbg_io.c index 2128684584f5..32d6fb4ee679 100644 --- a/arch/mips/momentum/ocelot_c/dbg_io.c +++ b/arch/mips/momentum/ocelot_c/dbg_io.c @@ -1,6 +1,4 @@ -#ifdef CONFIG_KGDB - #include /* For the serial port location and base baud */ /* --- CONFIG --- */ @@ -121,5 +119,3 @@ int putDebugChar(uint8 byte) UART16550_WRITE(OFS_SEND_BUFFER, byte); return 1; } - -#endif diff --git a/arch/mips/momentum/ocelot_c/irq.c b/arch/mips/momentum/ocelot_c/irq.c index ea65223a6d2c..40472f7944d7 100644 --- a/arch/mips/momentum/ocelot_c/irq.c +++ b/arch/mips/momentum/ocelot_c/irq.c @@ -94,7 +94,7 @@ void __init arch_init_irq(void) */ clear_c0_status(ST0_IM); - mips_cpu_irq_init(0); + mips_cpu_irq_init(); /* set up the cascading interrupts */ setup_irq(3, &cascade_fpga); diff --git a/arch/mips/momentum/ocelot_c/prom.c b/arch/mips/momentum/ocelot_c/prom.c index d0b77e101d74..b689ceea8cfb 100644 --- a/arch/mips/momentum/ocelot_c/prom.c +++ b/arch/mips/momentum/ocelot_c/prom.c @@ -178,7 +178,6 @@ void __init prom_init(void) #endif } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } diff --git a/arch/mips/momentum/ocelot_c/uart-irq.c b/arch/mips/momentum/ocelot_c/uart-irq.c index a7a80c0da569..de1a31ee52f3 100644 --- a/arch/mips/momentum/ocelot_c/uart-irq.c +++ b/arch/mips/momentum/ocelot_c/uart-irq.c @@ -77,7 +77,7 @@ void ll_uart_irq(void) } struct irq_chip uart_irq_type = { - .typename = "UART/FPGA", + .name = "UART/FPGA", .ack = mask_uart_irq, .mask = mask_uart_irq, .mask_ack = mask_uart_irq, diff --git a/arch/mips/momentum/ocelot_g/dbg_io.c b/arch/mips/momentum/ocelot_g/dbg_io.c index 2128684584f5..32d6fb4ee679 100644 --- a/arch/mips/momentum/ocelot_g/dbg_io.c +++ b/arch/mips/momentum/ocelot_g/dbg_io.c @@ -1,6 +1,4 @@ -#ifdef CONFIG_KGDB - #include /* For the serial port location and base baud */ /* --- CONFIG --- */ @@ -121,5 +119,3 @@ int putDebugChar(uint8 byte) UART16550_WRITE(OFS_SEND_BUFFER, byte); return 1; } - -#endif diff --git a/arch/mips/momentum/ocelot_g/irq.c b/arch/mips/momentum/ocelot_g/irq.c index da46524e87cb..273541fe7087 100644 --- a/arch/mips/momentum/ocelot_g/irq.c +++ b/arch/mips/momentum/ocelot_g/irq.c @@ -94,8 +94,8 @@ void __init arch_init_irq(void) clear_c0_status(ST0_IM); local_irq_disable(); - mips_cpu_irq_init(0); - rm7k_cpu_irq_init(8); + mips_cpu_irq_init(); + rm7k_cpu_irq_init(); gt64240_irq_init(); } diff --git a/arch/mips/momentum/ocelot_g/prom.c b/arch/mips/momentum/ocelot_g/prom.c index 2f75c6b91ec5..836d0830720d 100644 --- a/arch/mips/momentum/ocelot_g/prom.c +++ b/arch/mips/momentum/ocelot_g/prom.c @@ -79,7 +79,6 @@ void __init prom_init(void) } } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } diff --git a/arch/mips/oprofile/Kconfig b/arch/mips/oprofile/Kconfig index 55feaf798596..ca395ef06d4e 100644 --- a/arch/mips/oprofile/Kconfig +++ b/arch/mips/oprofile/Kconfig @@ -11,7 +11,7 @@ config PROFILING config OPROFILE tristate "OProfile system profiling (EXPERIMENTAL)" - depends on PROFILING && EXPERIMENTAL + depends on PROFILING && !!MIPS_MT_SMTC && EXPERIMENTAL help OProfile is a profiling system capable of profiling the whole system, include the kernel, kernel modules, libraries, diff --git a/arch/mips/pci/fixup-vr4133.c b/arch/mips/pci/fixup-vr4133.c index 597b89764ba1..a8d9d22b13df 100644 --- a/arch/mips/pci/fixup-vr4133.c +++ b/arch/mips/pci/fixup-vr4133.c @@ -17,8 +17,10 @@ */ #include #include +#include #include +#include #include extern int vr4133_rockhopper; @@ -142,7 +144,7 @@ int rockhopper_get_irq(struct pci_dev *dev, u8 pin, u8 slot) if (bus == NULL) return -1; - for (i = 0; i < sizeof (int_map) / sizeof (int_map[0]); i++) { + for (i = 0; i < ARRAY_SIZE(int_map); i++) { if (int_map[i].bus == bus->number && int_map[i].slot == slot) { int line; for (line = 0; line < 4; line++) @@ -160,17 +162,7 @@ int rockhopper_get_irq(struct pci_dev *dev, u8 pin, u8 slot) #ifdef CONFIG_ROCKHOPPER void i8259_init(void) { - outb(0x11, 0x20); /* Master ICW1 */ - outb(I8259_IRQ_BASE, 0x21); /* Master ICW2 */ - outb(0x04, 0x21); /* Master ICW3 */ - outb(0x01, 0x21); /* Master ICW4 */ - outb(0xff, 0x21); /* Master IMW */ - - outb(0x11, 0xa0); /* Slave ICW1 */ - outb(I8259_IRQ_BASE + 8, 0xa1); /* Slave ICW2 */ - outb(0x02, 0xa1); /* Slave ICW3 */ - outb(0x01, 0xa1); /* Slave ICW4 */ - outb(0xff, 0xa1); /* Slave IMW */ + init_i8259_irqs(); outb(0x00, 0x4d0); outb(0x02, 0x4d1); /* USB IRQ9 is level */ diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/philips/pnx8550/common/int.c index 2c36c108c4d6..d48665ebd33c 100644 --- a/arch/mips/philips/pnx8550/common/int.c +++ b/arch/mips/philips/pnx8550/common/int.c @@ -159,7 +159,7 @@ int pnx8550_set_gic_priority(int irq, int priority) } static struct irq_chip level_irq_type = { - .typename = "PNX Level IRQ", + .name = "PNX Level IRQ", .ack = mask_irq, .mask = mask_irq, .mask_ack = mask_irq, diff --git a/arch/mips/philips/pnx8550/common/prom.c b/arch/mips/philips/pnx8550/common/prom.c index eb6ec11fef07..8aeed6c2b8c3 100644 --- a/arch/mips/philips/pnx8550/common/prom.c +++ b/arch/mips/philips/pnx8550/common/prom.c @@ -106,9 +106,8 @@ int get_ethernet_addr(char *ethernet_addr) return 0; } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } extern int pnx8550_console_port; diff --git a/arch/mips/pmc-sierra/yosemite/dbg_io.c b/arch/mips/pmc-sierra/yosemite/dbg_io.c index 0f659c9106ac..6362c702e389 100644 --- a/arch/mips/pmc-sierra/yosemite/dbg_io.c +++ b/arch/mips/pmc-sierra/yosemite/dbg_io.c @@ -93,7 +93,7 @@ * Functions to READ and WRITE to serial port 1 */ #define SERIAL_READ_1(ofs) (*((volatile unsigned char*) \ - (TITAN_SERIAL_BASE_1 + ofs) + (TITAN_SERIAL_BASE_1 + ofs))) #define SERIAL_WRITE_1(ofs, val) ((*((volatile unsigned char*) \ (TITAN_SERIAL_BASE_1 + ofs))) = val) diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c index adb048527e76..428d1f45a287 100644 --- a/arch/mips/pmc-sierra/yosemite/irq.c +++ b/arch/mips/pmc-sierra/yosemite/irq.c @@ -148,9 +148,9 @@ void __init arch_init_irq(void) { clear_c0_status(ST0_IM); - mips_cpu_irq_init(0); - rm7k_cpu_irq_init(8); - rm9k_cpu_irq_init(12); + mips_cpu_irq_init(); + rm7k_cpu_irq_init(); + rm9k_cpu_irq_init(); #ifdef CONFIG_KGDB /* At this point, initialize the second serial port */ diff --git a/arch/mips/pmc-sierra/yosemite/prom.c b/arch/mips/pmc-sierra/yosemite/prom.c index 9fe4973377c3..1e1685e415a4 100644 --- a/arch/mips/pmc-sierra/yosemite/prom.c +++ b/arch/mips/pmc-sierra/yosemite/prom.c @@ -132,9 +132,8 @@ void __init prom_init(void) prom_grab_secondary(); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } void __init prom_fixup_mem_map(unsigned long start, unsigned long end) diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c index 1b9b0d396d3e..6a6e15e40009 100644 --- a/arch/mips/pmc-sierra/yosemite/setup.c +++ b/arch/mips/pmc-sierra/yosemite/setup.c @@ -171,6 +171,7 @@ static void __init py_map_ocd(void) static void __init py_uart_setup(void) { +#ifdef CONFIG_SERIAL_8250 struct uart_port up; /* @@ -188,6 +189,7 @@ static void __init py_uart_setup(void) if (early_serial_setup(&up)) printk(KERN_ERR "Early serial init of port 0 failed\n"); +#endif /* CONFIG_SERIAL_8250 */ } static void __init py_rtc_setup(void) diff --git a/arch/mips/qemu/q-mem.c b/arch/mips/qemu/q-mem.c index d174fac43031..dae39b59de15 100644 --- a/arch/mips/qemu/q-mem.c +++ b/arch/mips/qemu/q-mem.c @@ -1,6 +1,5 @@ #include -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0UL; } diff --git a/arch/mips/sgi-ip22/ip22-eisa.c b/arch/mips/sgi-ip22/ip22-eisa.c index a1a9af6da7bf..6b6e97b90c6e 100644 --- a/arch/mips/sgi-ip22/ip22-eisa.c +++ b/arch/mips/sgi-ip22/ip22-eisa.c @@ -139,7 +139,7 @@ static void end_eisa1_irq(unsigned int irq) } static struct irq_chip ip22_eisa1_irq_type = { - .typename = "IP22 EISA", + .name = "IP22 EISA", .startup = startup_eisa1_irq, .ack = mask_and_ack_eisa1_irq, .mask = disable_eisa1_irq, @@ -194,7 +194,7 @@ static void end_eisa2_irq(unsigned int irq) } static struct irq_chip ip22_eisa2_irq_type = { - .typename = "IP22 EISA", + .name = "IP22 EISA", .startup = startup_eisa2_irq, .ack = mask_and_ack_eisa2_irq, .mask = disable_eisa2_irq, diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index c44f8be0644f..b454924aeb56 100644 --- a/arch/mips/sgi-ip22/ip22-int.c +++ b/arch/mips/sgi-ip22/ip22-int.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -52,7 +53,7 @@ static void disable_local0_irq(unsigned int irq) } static struct irq_chip ip22_local0_irq_type = { - .typename = "IP22 local 0", + .name = "IP22 local 0", .ack = disable_local0_irq, .mask = disable_local0_irq, .mask_ack = disable_local0_irq, @@ -73,7 +74,7 @@ void disable_local1_irq(unsigned int irq) } static struct irq_chip ip22_local1_irq_type = { - .typename = "IP22 local 1", + .name = "IP22 local 1", .ack = disable_local1_irq, .mask = disable_local1_irq, .mask_ack = disable_local1_irq, @@ -94,7 +95,7 @@ void disable_local2_irq(unsigned int irq) } static struct irq_chip ip22_local2_irq_type = { - .typename = "IP22 local 2", + .name = "IP22 local 2", .ack = disable_local2_irq, .mask = disable_local2_irq, .mask_ack = disable_local2_irq, @@ -115,7 +116,7 @@ void disable_local3_irq(unsigned int irq) } static struct irq_chip ip22_local3_irq_type = { - .typename = "IP22 local 3", + .name = "IP22 local 3", .ack = disable_local3_irq, .mask = disable_local3_irq, .mask_ack = disable_local3_irq, @@ -253,8 +254,6 @@ asmlinkage void plat_irq_dispatch(void) indy_8254timer_irq(); } -extern void mips_cpu_irq_init(unsigned int irq_base); - void __init arch_init_irq(void) { int i; @@ -316,7 +315,7 @@ void __init arch_init_irq(void) sgint->cmeimask1 = 0; /* init CPU irqs */ - mips_cpu_irq_init(SGINT_CPU); + mips_cpu_irq_init(); for (i = SGINT_LOCAL0; i < SGI_INTERRUPTS; i++) { struct irq_chip *handler; diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c index b58bd522262b..ddb6506d8341 100644 --- a/arch/mips/sgi-ip22/ip22-mc.c +++ b/arch/mips/sgi-ip22/ip22-mc.c @@ -202,7 +202,6 @@ void __init sgimc_init(void) } void __init prom_meminit(void) {} -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index 319f8803ef6f..60ade7690e09 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c @@ -333,7 +333,7 @@ static inline void disable_bridge_irq(unsigned int irq) } static struct irq_chip bridge_irq_type = { - .typename = "bridge", + .name = "bridge", .startup = startup_bridge_irq, .shutdown = shutdown_bridge_irq, .ack = disable_bridge_irq, diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c index 16e5682b01f1..0e3d535e9f43 100644 --- a/arch/mips/sgi-ip27/ip27-memory.c +++ b/arch/mips/sgi-ip27/ip27-memory.c @@ -498,10 +498,9 @@ void __init prom_meminit(void) } } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { /* We got nothing to free here ... */ - return 0; } extern void pagetable_init(void); diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index c20e9899b34b..9ce513629b14 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -181,7 +181,7 @@ static void disable_rt_irq(unsigned int irq) } static struct irq_chip rt_irq_type = { - .typename = "SN HUB RT timer", + .name = "SN HUB RT timer", .ack = disable_rt_irq, .mask = disable_rt_irq, .mask_ack = disable_rt_irq, diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c index ae063864c026..8c450d9e8696 100644 --- a/arch/mips/sgi-ip32/ip32-irq.c +++ b/arch/mips/sgi-ip32/ip32-irq.c @@ -144,7 +144,7 @@ static void end_cpu_irq(unsigned int irq) } static struct irq_chip ip32_cpu_interrupt = { - .typename = "IP32 CPU", + .name = "IP32 CPU", .ack = disable_cpu_irq, .mask = disable_cpu_irq, .mask_ack = disable_cpu_irq, @@ -193,7 +193,7 @@ static void end_crime_irq(unsigned int irq) } static struct irq_chip ip32_crime_interrupt = { - .typename = "IP32 CRIME", + .name = "IP32 CRIME", .ack = mask_and_ack_crime_irq, .mask = disable_crime_irq, .mask_ack = mask_and_ack_crime_irq, @@ -234,7 +234,7 @@ static void end_macepci_irq(unsigned int irq) } static struct irq_chip ip32_macepci_interrupt = { - .typename = "IP32 MACE PCI", + .name = "IP32 MACE PCI", .ack = disable_macepci_irq, .mask = disable_macepci_irq, .mask_ack = disable_macepci_irq, @@ -347,7 +347,7 @@ static void end_maceisa_irq(unsigned irq) } static struct irq_chip ip32_maceisa_interrupt = { - .typename = "IP32 MACE ISA", + .name = "IP32 MACE ISA", .ack = mask_and_ack_maceisa_irq, .mask = disable_maceisa_irq, .mask_ack = mask_and_ack_maceisa_irq, @@ -379,7 +379,7 @@ static void end_mace_irq(unsigned int irq) } static struct irq_chip ip32_mace_interrupt = { - .typename = "IP32 MACE", + .name = "IP32 MACE", .ack = disable_mace_irq, .mask = disable_mace_irq, .mask_ack = disable_mace_irq, diff --git a/arch/mips/sgi-ip32/ip32-memory.c b/arch/mips/sgi-ip32/ip32-memory.c index d37d40a3cdae..849d392a0013 100644 --- a/arch/mips/sgi-ip32/ip32-memory.c +++ b/arch/mips/sgi-ip32/ip32-memory.c @@ -43,7 +43,6 @@ void __init prom_meminit (void) } -unsigned long __init prom_free_prom_memory (void) +void __init prom_free_prom_memory(void) { - return 0; } diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c index 2e8f6b2e2420..1dc5d05d8962 100644 --- a/arch/mips/sibyte/bcm1480/irq.c +++ b/arch/mips/sibyte/bcm1480/irq.c @@ -82,7 +82,7 @@ extern char sb1250_duart_present[]; #endif static struct irq_chip bcm1480_irq_type = { - .typename = "BCM1480-IMR", + .name = "BCM1480-IMR", .ack = ack_bcm1480_irq, .mask = disable_bcm1480_irq, .mask_ack = ack_bcm1480_irq, diff --git a/arch/mips/sibyte/cfe/setup.c b/arch/mips/sibyte/cfe/setup.c index 6e8952da6e2a..9e6099e69622 100644 --- a/arch/mips/sibyte/cfe/setup.c +++ b/arch/mips/sibyte/cfe/setup.c @@ -343,10 +343,9 @@ void __init prom_init(void) prom_meminit(); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { /* Not sure what I'm supposed to do here. Nothing, I think */ - return 0; } void prom_putchar(char c) diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c index 82ce7533053f..148239446e6e 100644 --- a/arch/mips/sibyte/sb1250/irq.c +++ b/arch/mips/sibyte/sb1250/irq.c @@ -67,7 +67,7 @@ extern char sb1250_duart_present[]; #endif static struct irq_chip sb1250_irq_type = { - .typename = "SB1250-IMR", + .name = "SB1250-IMR", .ack = ack_sb1250_irq, .mask = disable_sb1250_irq, .mask_ack = ack_sb1250_irq, diff --git a/arch/mips/sibyte/sb1250/prom.c b/arch/mips/sibyte/sb1250/prom.c index 3c33a4517bc3..257c4e674353 100644 --- a/arch/mips/sibyte/sb1250/prom.c +++ b/arch/mips/sibyte/sb1250/prom.c @@ -87,10 +87,9 @@ void __init prom_init(void) prom_meminit(); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { /* Not sure what I'm supposed to do here. Nothing, I think */ - return 0; } void prom_putchar(char c) diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c index 8511bcc6d99d..039e8e540508 100644 --- a/arch/mips/sni/irq.c +++ b/arch/mips/sni/irq.c @@ -37,7 +37,7 @@ static void end_pciasic_irq(unsigned int irq) } static struct irq_chip pciasic_irq_type = { - .typename = "ASIC-PCI", + .name = "ASIC-PCI", .ack = disable_pciasic_irq, .mask = disable_pciasic_irq, .mask_ack = disable_pciasic_irq, diff --git a/arch/mips/sni/sniprom.c b/arch/mips/sni/sniprom.c index d1d0f1f493b4..1213d166f22e 100644 --- a/arch/mips/sni/sniprom.c +++ b/arch/mips/sni/sniprom.c @@ -67,9 +67,8 @@ void prom_printf(char *fmt, ...) va_end(args); } -unsigned long prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } /* diff --git a/arch/mips/tx4927/common/tx4927_irq.c b/arch/mips/tx4927/common/tx4927_irq.c index ed4a19adf361..e7f3e5b84dcf 100644 --- a/arch/mips/tx4927/common/tx4927_irq.c +++ b/arch/mips/tx4927/common/tx4927_irq.c @@ -120,7 +120,7 @@ static void tx4927_irq_pic_disable(unsigned int irq); #define TX4927_CP0_NAME "TX4927-CP0" static struct irq_chip tx4927_irq_cp0_type = { - .typename = TX4927_CP0_NAME, + .name = TX4927_CP0_NAME, .ack = tx4927_irq_cp0_disable, .mask = tx4927_irq_cp0_disable, .mask_ack = tx4927_irq_cp0_disable, @@ -129,7 +129,7 @@ static struct irq_chip tx4927_irq_cp0_type = { #define TX4927_PIC_NAME "TX4927-PIC" static struct irq_chip tx4927_irq_pic_type = { - .typename = TX4927_PIC_NAME, + .name = TX4927_PIC_NAME, .ack = tx4927_irq_pic_disable, .mask = tx4927_irq_pic_disable, .mask_ack = tx4927_irq_pic_disable, diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c index b54b529a29f9..dcce88f403c9 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c @@ -228,7 +228,7 @@ static void toshiba_rbtx4927_irq_isa_mask_and_ack(unsigned int irq); #define TOSHIBA_RBTX4927_IOC_NAME "RBTX4927-IOC" static struct irq_chip toshiba_rbtx4927_irq_ioc_type = { - .typename = TOSHIBA_RBTX4927_IOC_NAME, + .name = TOSHIBA_RBTX4927_IOC_NAME, .ack = toshiba_rbtx4927_irq_ioc_disable, .mask = toshiba_rbtx4927_irq_ioc_disable, .mask_ack = toshiba_rbtx4927_irq_ioc_disable, @@ -241,7 +241,7 @@ static struct irq_chip toshiba_rbtx4927_irq_ioc_type = { #ifdef CONFIG_TOSHIBA_FPCIB0 #define TOSHIBA_RBTX4927_ISA_NAME "RBTX4927-ISA" static struct irq_chip toshiba_rbtx4927_irq_isa_type = { - .typename = TOSHIBA_RBTX4927_ISA_NAME, + .name = TOSHIBA_RBTX4927_ISA_NAME, .ack = toshiba_rbtx4927_irq_isa_mask_and_ack, .mask = toshiba_rbtx4927_irq_isa_disable, .mask_ack = toshiba_rbtx4927_irq_isa_mask_and_ack, @@ -490,13 +490,13 @@ void toshiba_rbtx4927_irq_dump(char *key) { u32 i, j = 0; for (i = 0; i < NR_IRQS; i++) { - if (strcmp(irq_desc[i].chip->typename, "none") + if (strcmp(irq_desc[i].chip->name, "none") == 0) continue; if ((i >= 1) - && (irq_desc[i - 1].chip->typename == - irq_desc[i].chip->typename)) { + && (irq_desc[i - 1].chip->name == + irq_desc[i].chip->name)) { j++; } else { j = 0; @@ -510,7 +510,7 @@ void toshiba_rbtx4927_irq_dump(char *key) (u32) (irq_desc[i].action ? irq_desc[i]. action->handler : 0), irq_desc[i].depth, - irq_desc[i].chip->typename, j); + irq_desc[i].chip->name, j); } } #endif diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c index efe50562f0ce..9a3a5babd1fb 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c @@ -80,9 +80,8 @@ void __init prom_init(void) add_memory_region(0, msize << 20, BOOT_MEM_RAM); } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } const char *get_system_type(void) diff --git a/arch/mips/tx4938/common/irq.c b/arch/mips/tx4938/common/irq.c index a347b424d91c..3a2dbfc25014 100644 --- a/arch/mips/tx4938/common/irq.c +++ b/arch/mips/tx4938/common/irq.c @@ -49,7 +49,7 @@ static void tx4938_irq_pic_disable(unsigned int irq); #define TX4938_CP0_NAME "TX4938-CP0" static struct irq_chip tx4938_irq_cp0_type = { - .typename = TX4938_CP0_NAME, + .name = TX4938_CP0_NAME, .ack = tx4938_irq_cp0_disable, .mask = tx4938_irq_cp0_disable, .mask_ack = tx4938_irq_cp0_disable, @@ -58,7 +58,7 @@ static struct irq_chip tx4938_irq_cp0_type = { #define TX4938_PIC_NAME "TX4938-PIC" static struct irq_chip tx4938_irq_pic_type = { - .typename = TX4938_PIC_NAME, + .name = TX4938_PIC_NAME, .ack = tx4938_irq_pic_disable, .mask = tx4938_irq_pic_disable, .mask_ack = tx4938_irq_pic_disable, diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c index b6f363d08011..2e96dbb248b1 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/irq.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c @@ -92,7 +92,7 @@ static void toshiba_rbtx4938_irq_ioc_disable(unsigned int irq); #define TOSHIBA_RBTX4938_IOC_NAME "RBTX4938-IOC" static struct irq_chip toshiba_rbtx4938_irq_ioc_type = { - .typename = TOSHIBA_RBTX4938_IOC_NAME, + .name = TOSHIBA_RBTX4938_IOC_NAME, .ack = toshiba_rbtx4938_irq_ioc_disable, .mask = toshiba_rbtx4938_irq_ioc_disable, .mask_ack = toshiba_rbtx4938_irq_ioc_disable, diff --git a/arch/mips/tx4938/toshiba_rbtx4938/prom.c b/arch/mips/tx4938/toshiba_rbtx4938/prom.c index e44daf30a7c1..7dc6a0aae21c 100644 --- a/arch/mips/tx4938/toshiba_rbtx4938/prom.c +++ b/arch/mips/tx4938/toshiba_rbtx4938/prom.c @@ -56,9 +56,8 @@ void __init prom_init(void) return; } -unsigned long __init prom_free_prom_memory(void) +void __init prom_free_prom_memory(void) { - return 0; } void __init prom_fixup_mem_map(unsigned long start, unsigned long end) diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c index c075261976c5..adabc6bad440 100644 --- a/arch/mips/vr41xx/common/icu.c +++ b/arch/mips/vr41xx/common/icu.c @@ -3,7 +3,7 @@ * * Copyright (C) 2001-2002 MontaVista Software Inc. * Author: Yoichi Yuasa - * Copyright (C) 2003-2005 Yoichi Yuasa + * Copyright (C) 2003-2006 Yoichi Yuasa * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -68,6 +68,7 @@ static unsigned char sysint2_assign[16] = { #define MPIUINTREG 0x0e #define MAIUINTREG 0x10 #define MKIUINTREG 0x12 +#define MMACINTREG 0x12 #define MGIUINTLREG 0x14 #define MDSIUINTREG 0x16 #define NMIREG 0x18 @@ -241,6 +242,30 @@ void vr41xx_disable_kiuint(uint16_t mask) EXPORT_SYMBOL(vr41xx_disable_kiuint); +void vr41xx_enable_macint(uint16_t mask) +{ + struct irq_desc *desc = irq_desc + ETHERNET_IRQ; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + icu1_set(MMACINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vr41xx_enable_macint); + +void vr41xx_disable_macint(uint16_t mask) +{ + struct irq_desc *desc = irq_desc + ETHERNET_IRQ; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + icu1_clear(MMACINTREG, mask); + spin_unlock_irqrestore(&desc->lock, flags); +} + +EXPORT_SYMBOL(vr41xx_disable_macint); + void vr41xx_enable_dsiuint(uint16_t mask) { struct irq_desc *desc = irq_desc + DSIU_IRQ; @@ -428,7 +453,7 @@ static void enable_sysint1_irq(unsigned int irq) } static struct irq_chip sysint1_irq_type = { - .typename = "SYSINT1", + .name = "SYSINT1", .ack = disable_sysint1_irq, .mask = disable_sysint1_irq, .mask_ack = disable_sysint1_irq, @@ -446,7 +471,7 @@ static void enable_sysint2_irq(unsigned int irq) } static struct irq_chip sysint2_irq_type = { - .typename = "SYSINT2", + .name = "SYSINT2", .ack = disable_sysint2_irq, .mask = disable_sysint2_irq, .mask_ack = disable_sysint2_irq, diff --git a/arch/mips/vr41xx/common/init.c b/arch/mips/vr41xx/common/init.c index a2e285c1d4d5..4f97e0ba9e24 100644 --- a/arch/mips/vr41xx/common/init.c +++ b/arch/mips/vr41xx/common/init.c @@ -81,7 +81,6 @@ void __init prom_init(void) } } -unsigned long __init prom_free_prom_memory (void) +void __init prom_free_prom_memory(void) { - return 0UL; } diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c index 16decf4ac2f4..cba36a247e32 100644 --- a/arch/mips/vr41xx/common/irq.c +++ b/arch/mips/vr41xx/common/irq.c @@ -95,27 +95,27 @@ asmlinkage void plat_irq_dispatch(void) unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM; if (pending & CAUSEF_IP7) - do_IRQ(7); + do_IRQ(TIMER_IRQ); else if (pending & 0x7800) { if (pending & CAUSEF_IP3) - irq_dispatch(3); + irq_dispatch(INT1_IRQ); else if (pending & CAUSEF_IP4) - irq_dispatch(4); + irq_dispatch(INT2_IRQ); else if (pending & CAUSEF_IP5) - irq_dispatch(5); + irq_dispatch(INT3_IRQ); else if (pending & CAUSEF_IP6) - irq_dispatch(6); + irq_dispatch(INT4_IRQ); } else if (pending & CAUSEF_IP2) - irq_dispatch(2); + irq_dispatch(INT0_IRQ); else if (pending & CAUSEF_IP0) - do_IRQ(0); + do_IRQ(MIPS_SOFTINT0_IRQ); else if (pending & CAUSEF_IP1) - do_IRQ(1); + do_IRQ(MIPS_SOFTINT1_IRQ); else spurious_interrupt(); } void __init arch_init_irq(void) { - mips_cpu_irq_init(MIPS_CPU_IRQ_BASE); + mips_cpu_irq_init(); } diff --git a/arch/mips/vr41xx/nec-cmbvr4133/irq.c b/arch/mips/vr41xx/nec-cmbvr4133/irq.c index 128ed8d6f111..7d2d076b0f54 100644 --- a/arch/mips/vr41xx/nec-cmbvr4133/irq.c +++ b/arch/mips/vr41xx/nec-cmbvr4133/irq.c @@ -21,60 +21,16 @@ #include #include +#include #include -extern void enable_8259A_irq(unsigned int irq); -extern void disable_8259A_irq(unsigned int irq); -extern void mask_and_ack_8259A(unsigned int irq); -extern void init_8259A(int hoge); - extern int vr4133_rockhopper; -static void enable_i8259_irq(unsigned int irq) -{ - enable_8259A_irq(irq - I8259_IRQ_BASE); -} - -static void disable_i8259_irq(unsigned int irq) -{ - disable_8259A_irq(irq - I8259_IRQ_BASE); -} - -static void ack_i8259_irq(unsigned int irq) -{ - mask_and_ack_8259A(irq - I8259_IRQ_BASE); -} - -static struct irq_chip i8259_irq_type = { - .typename = "XT-PIC", - .ack = ack_i8259_irq, - .mask = disable_i8259_irq, - .mask_ack = ack_i8259_irq, - .unmask = enable_i8259_irq, -}; - static int i8259_get_irq_number(int irq) { - unsigned long isr; - - isr = inb(0x20); - irq = ffz(~isr); - if (irq == 2) { - isr = inb(0xa0); - irq = 8 + ffz(~isr); - } - - if (irq < 0 || irq > 15) - return -EINVAL; - - return I8259_IRQ_BASE + irq; + return i8259_irq(); } -static struct irqaction i8259_slave_cascade = { - .handler = &no_action, - .name = "cascade", -}; - void __init rockhopper_init_irq(void) { int i; @@ -84,11 +40,6 @@ void __init rockhopper_init_irq(void) return; } - for (i = I8259_IRQ_BASE; i <= I8259_IRQ_LAST; i++) - set_irq_chip_and_handler(i, &i8259_irq_type, handle_level_irq); - - setup_irq(I8259_SLAVE_IRQ, &i8259_slave_cascade); - vr41xx_set_irq_trigger(CMBVR41XX_INTC_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH); vr41xx_set_irq_level(CMBVR41XX_INTC_PIN, LEVEL_HIGH); vr41xx_cascade_irq(CMBVR41XX_INTC_IRQ, i8259_get_irq_number); diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index abc6bd2f858e..f08e80a0bf0a 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -552,6 +552,11 @@ config PPC_PS3 bool "Sony PS3 (incomplete)" depends on PPC_MULTIPLATFORM && PPC64 select PPC_CELL + select USB_ARCH_HAS_OHCI + select USB_OHCI_LITTLE_ENDIAN + select USB_OHCI_BIG_ENDIAN_MMIO + select USB_ARCH_HAS_EHCI + select USB_EHCI_BIG_ENDIAN_MMIO help This option enables support for the Sony PS3 game console and other platforms using the PS3 hypervisor. diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 6828df4afd99..7e97d71a5f8f 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/arch/s390/Kconfig b/arch/s390/Kconfig index 12272361c018..eaed402ad346 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -34,10 +34,6 @@ config GENERIC_HWEIGHT bool default y -config GENERIC_CALIBRATE_DELAY - bool - default y - config GENERIC_TIME def_bool y @@ -134,6 +130,31 @@ config AUDIT_ARCH bool default y +config S390_SWITCH_AMODE + bool "Switch kernel/user addressing modes" + help + This option allows to switch the addressing modes of kernel and user + space. The kernel parameter switch_amode=on will enable this feature, + default is disabled. Enabling this (via kernel parameter) on machines + earlier than IBM System z9-109 EC/BC will reduce system performance. + + Note that this option will also be selected by selecting the execute + protection option below. Enabling the execute protection via the + noexec kernel parameter will also switch the addressing modes, + independent of the switch_amode kernel parameter. + + +config S390_EXEC_PROTECT + bool "Data execute protection" + select S390_SWITCH_AMODE + help + This option allows to enable a buffer overflow protection for user + space programs and it also selects the addressing mode option above. + The kernel parameter noexec=on will enable this feature and also + switch the addressing modes, default is disabled. Enabling this (via + kernel parameter) on machines earlier than IBM System z9-109 EC/BC + will reduce system performance. + comment "Code generation options" choice diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index b8c237290263..c9da7d16145e 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -81,7 +81,7 @@ static struct ctl_table appldata_dir_table[] = { /* * Timer */ -DEFINE_PER_CPU(struct vtimer_list, appldata_timer); +static DEFINE_PER_CPU(struct vtimer_list, appldata_timer); static atomic_t appldata_expire_count = ATOMIC_INIT(0); static DEFINE_SPINLOCK(appldata_timer_lock); diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c index 8aea3698a77b..4ca615788702 100644 --- a/arch/s390/appldata/appldata_mem.c +++ b/arch/s390/appldata/appldata_mem.c @@ -36,7 +36,7 @@ * book: * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml */ -struct appldata_mem_data { +static struct appldata_mem_data { u64 timestamp; u32 sync_count_1; /* after VM collected the record data, */ u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c index 075e619bf37d..f64b8c867ae2 100644 --- a/arch/s390/appldata/appldata_net_sum.c +++ b/arch/s390/appldata/appldata_net_sum.c @@ -34,7 +34,7 @@ * book: * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml */ -struct appldata_net_sum_data { +static struct appldata_net_sum_data { u64 timestamp; u32 sync_count_1; /* after VM collected the record data, */ u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the diff --git a/arch/s390/crypto/Kconfig b/arch/s390/crypto/Kconfig new file mode 100644 index 000000000000..99ff9f08e4d7 --- /dev/null +++ b/arch/s390/crypto/Kconfig @@ -0,0 +1,60 @@ +config CRYPTO_SHA1_S390 + tristate "SHA1 digest algorithm" + depends on S390 + select CRYPTO_ALGAPI + help + This is the s390 hardware accelerated implementation of the + SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). + +config CRYPTO_SHA256_S390 + tristate "SHA256 digest algorithm" + depends on S390 + select CRYPTO_ALGAPI + help + This is the s390 hardware accelerated implementation of the + SHA256 secure hash standard (DFIPS 180-2). + + This version of SHA implements a 256 bit hash with 128 bits of + security against collision attacks. + +config CRYPTO_DES_S390 + tristate "DES and Triple DES cipher algorithms" + depends on S390 + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + help + This us the s390 hardware accelerated implementation of the + DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). + +config CRYPTO_AES_S390 + tristate "AES cipher algorithms" + depends on S390 + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + help + This is the s390 hardware accelerated implementation of the + AES cipher algorithms (FIPS-197). AES uses the Rijndael + algorithm. + + Rijndael appears to be consistently a very good performer in + both hardware and software across a wide range of computing + environments regardless of its use in feedback or non-feedback + modes. Its key setup time is excellent, and its key agility is + good. Rijndael's very low memory requirements make it very well + suited for restricted-space environments, in which it also + demonstrates excellent performance. Rijndael's operations are + among the easiest to defend against power and timing attacks. + + On s390 the System z9-109 currently only supports the key size + of 128 bit. + +config S390_PRNG + tristate "Pseudo random number generator device driver" + depends on S390 + default "m" + help + Select this option if you want to use the s390 pseudo random number + generator. The PRNG is part of the cryptograhic processor functions + and uses triple-DES to generate secure random numbers like the + ANSI X9.17 standard. The PRNG is usable via the char device + /dev/prandom. diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile index bfe2541dc5cf..14e552c5cc43 100644 --- a/arch/s390/crypto/Makefile +++ b/arch/s390/crypto/Makefile @@ -6,5 +6,4 @@ obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o - -obj-$(CONFIG_CRYPTO_TEST) += crypt_s390_query.o +obj-$(CONFIG_S390_PRNG) += prng.o diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 15c9eec02928..91636353f6f0 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -4,7 +4,7 @@ * s390 implementation of the AES Cipher Algorithm. * * s390 Version: - * Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation + * Copyright IBM Corp. 2005,2007 * Author(s): Jan Glauber (jang@de.ibm.com) * * Derived from "crypto/aes.c" @@ -27,9 +27,11 @@ /* data block size for all key lengths */ #define AES_BLOCK_SIZE 16 -int has_aes_128 = 0; -int has_aes_192 = 0; -int has_aes_256 = 0; +#define AES_KEYLEN_128 1 +#define AES_KEYLEN_192 2 +#define AES_KEYLEN_256 4 + +static char keylen_flag = 0; struct s390_aes_ctx { u8 iv[AES_BLOCK_SIZE]; @@ -47,20 +49,19 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, switch (key_len) { case 16: - if (!has_aes_128) + if (!(keylen_flag & AES_KEYLEN_128)) goto fail; break; case 24: - if (!has_aes_192) + if (!(keylen_flag & AES_KEYLEN_192)) goto fail; break; case 32: - if (!has_aes_256) + if (!(keylen_flag & AES_KEYLEN_256)) goto fail; break; default: - /* invalid key length */ goto fail; break; } @@ -322,34 +323,32 @@ static int __init aes_init(void) int ret; if (crypt_s390_func_available(KM_AES_128_ENCRYPT)) - has_aes_128 = 1; + keylen_flag |= AES_KEYLEN_128; if (crypt_s390_func_available(KM_AES_192_ENCRYPT)) - has_aes_192 = 1; + keylen_flag |= AES_KEYLEN_192; if (crypt_s390_func_available(KM_AES_256_ENCRYPT)) - has_aes_256 = 1; + keylen_flag |= AES_KEYLEN_256; - if (!has_aes_128 && !has_aes_192 && !has_aes_256) - return -ENOSYS; + if (!keylen_flag) + return -EOPNOTSUPP; + + /* z9 109 and z9 BC/EC only support 128 bit key length */ + if (keylen_flag == AES_KEYLEN_128) + printk(KERN_INFO + "aes_s390: hardware acceleration only available for" + "128 bit keys\n"); ret = crypto_register_alg(&aes_alg); - if (ret != 0) { - printk(KERN_INFO "crypt_s390: aes-s390 couldn't be loaded.\n"); + if (ret) goto aes_err; - } ret = crypto_register_alg(&ecb_aes_alg); - if (ret != 0) { - printk(KERN_INFO - "crypt_s390: ecb-aes-s390 couldn't be loaded.\n"); + if (ret) goto ecb_aes_err; - } ret = crypto_register_alg(&cbc_aes_alg); - if (ret != 0) { - printk(KERN_INFO - "crypt_s390: cbc-aes-s390 couldn't be loaded.\n"); + if (ret) goto cbc_aes_err; - } out: return ret; diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h index 2b137089f625..2775d2618332 100644 --- a/arch/s390/crypto/crypt_s390.h +++ b/arch/s390/crypto/crypt_s390.h @@ -3,8 +3,9 @@ * * Support for s390 cryptographic instructions. * - * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation - * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * Copyright IBM Corp. 2003,2007 + * Author(s): Thomas Spatzier + * Jan Glauber (jan.glauber@de.ibm.com) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -32,7 +33,8 @@ enum crypt_s390_operations { CRYPT_S390_KMAC = 0x0500 }; -/* function codes for KM (CIPHER MESSAGE) instruction +/* + * function codes for KM (CIPHER MESSAGE) instruction * 0x80 is the decipher modifier bit */ enum crypt_s390_km_func { @@ -51,7 +53,8 @@ enum crypt_s390_km_func { KM_AES_256_DECRYPT = CRYPT_S390_KM | 0x14 | 0x80, }; -/* function codes for KMC (CIPHER MESSAGE WITH CHAINING) +/* + * function codes for KMC (CIPHER MESSAGE WITH CHAINING) * instruction */ enum crypt_s390_kmc_func { @@ -68,9 +71,11 @@ enum crypt_s390_kmc_func { KMC_AES_192_DECRYPT = CRYPT_S390_KMC | 0x13 | 0x80, KMC_AES_256_ENCRYPT = CRYPT_S390_KMC | 0x14, KMC_AES_256_DECRYPT = CRYPT_S390_KMC | 0x14 | 0x80, + KMC_PRNG = CRYPT_S390_KMC | 0x43, }; -/* function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) +/* + * function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) * instruction */ enum crypt_s390_kimd_func { @@ -79,7 +84,8 @@ enum crypt_s390_kimd_func { KIMD_SHA_256 = CRYPT_S390_KIMD | 2, }; -/* function codes for KLMD (COMPUTE LAST MESSAGE DIGEST) +/* + * function codes for KLMD (COMPUTE LAST MESSAGE DIGEST) * instruction */ enum crypt_s390_klmd_func { @@ -88,7 +94,8 @@ enum crypt_s390_klmd_func { KLMD_SHA_256 = CRYPT_S390_KLMD | 2, }; -/* function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) +/* + * function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) * instruction */ enum crypt_s390_kmac_func { @@ -98,229 +105,219 @@ enum crypt_s390_kmac_func { KMAC_TDEA_192 = CRYPT_S390_KMAC | 3 }; -/* status word for s390 crypto instructions' QUERY functions */ -struct crypt_s390_query_status { - u64 high; - u64 low; -}; - -/* +/** + * crypt_s390_km: + * @func: the function code passed to KM; see crypt_s390_km_func + * @param: address of parameter block; see POP for details on each func + * @dest: address of destination memory area + * @src: address of source memory area + * @src_len: length of src operand in bytes + * * Executes the KM (CIPHER MESSAGE) operation of the CPU. - * @param func: the function code passed to KM; see crypt_s390_km_func - * @param param: address of parameter block; see POP for details on each func - * @param dest: address of destination memory area - * @param src: address of source memory area - * @param src_len: length of src operand in bytes - * @returns < zero for failure, 0 for the query func, number of processed bytes - * for encryption/decryption funcs + * + * Returns -1 for failure, 0 for the query func, number of processed + * bytes for encryption/decryption funcs */ -static inline int -crypt_s390_km(long func, void* param, u8* dest, const u8* src, long src_len) +static inline int crypt_s390_km(long func, void *param, + u8 *dest, const u8 *src, long src_len) { register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; - register void* __param asm("1") = param; - register const u8* __src asm("2") = src; + register void *__param asm("1") = param; + register const u8 *__src asm("2") = src; register long __src_len asm("3") = src_len; - register u8* __dest asm("4") = dest; + register u8 *__dest asm("4") = dest; int ret; asm volatile( "0: .insn rre,0xb92e0000,%3,%1 \n" /* KM opcode */ "1: brc 1,0b \n" /* handle partial completion */ - " ahi %0,%h7\n" - "2: ahi %0,%h8\n" - "3:\n" - EX_TABLE(0b,3b) EX_TABLE(1b,2b) + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest) - : "d" (__func), "a" (__param), "0" (-EFAULT), - "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); - if (ret < 0) - return ret; - return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; -} - -/* - * Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the CPU. - * @param func: the function code passed to KM; see crypt_s390_kmc_func - * @param param: address of parameter block; see POP for details on each func - * @param dest: address of destination memory area - * @param src: address of source memory area - * @param src_len: length of src operand in bytes - * @returns < zero for failure, 0 for the query func, number of processed bytes - * for encryption/decryption funcs - */ -static inline int -crypt_s390_kmc(long func, void* param, u8* dest, const u8* src, long src_len) -{ - register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; - register void* __param asm("1") = param; - register const u8* __src asm("2") = src; - register long __src_len asm("3") = src_len; - register u8* __dest asm("4") = dest; - int ret; - - asm volatile( - "0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC opcode */ - "1: brc 1,0b \n" /* handle partial completion */ - " ahi %0,%h7\n" - "2: ahi %0,%h8\n" - "3:\n" - EX_TABLE(0b,3b) EX_TABLE(1b,2b) - : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest) - : "d" (__func), "a" (__param), "0" (-EFAULT), - "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); - if (ret < 0) - return ret; - return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; -} - -/* - * Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation - * of the CPU. - * @param func: the function code passed to KM; see crypt_s390_kimd_func - * @param param: address of parameter block; see POP for details on each func - * @param src: address of source memory area - * @param src_len: length of src operand in bytes - * @returns < zero for failure, 0 for the query func, number of processed bytes - * for digest funcs - */ -static inline int -crypt_s390_kimd(long func, void* param, const u8* src, long src_len) -{ - register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; - register void* __param asm("1") = param; - register const u8* __src asm("2") = src; - register long __src_len asm("3") = src_len; - int ret; - - asm volatile( - "0: .insn rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */ - "1: brc 1,0b \n" /* handle partial completion */ - " ahi %0,%h6\n" - "2: ahi %0,%h7\n" - "3:\n" - EX_TABLE(0b,3b) EX_TABLE(1b,2b) - : "=d" (ret), "+a" (__src), "+d" (__src_len) - : "d" (__func), "a" (__param), "0" (-EFAULT), - "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); - if (ret < 0) - return ret; - return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; -} - -/* - * Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the CPU. - * @param func: the function code passed to KM; see crypt_s390_klmd_func - * @param param: address of parameter block; see POP for details on each func - * @param src: address of source memory area - * @param src_len: length of src operand in bytes - * @returns < zero for failure, 0 for the query func, number of processed bytes - * for digest funcs - */ -static inline int -crypt_s390_klmd(long func, void* param, const u8* src, long src_len) -{ - register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; - register void* __param asm("1") = param; - register const u8* __src asm("2") = src; - register long __src_len asm("3") = src_len; - int ret; - - asm volatile( - "0: .insn rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */ - "1: brc 1,0b \n" /* handle partial completion */ - " ahi %0,%h6\n" - "2: ahi %0,%h7\n" - "3:\n" - EX_TABLE(0b,3b) EX_TABLE(1b,2b) - : "=d" (ret), "+a" (__src), "+d" (__src_len) - : "d" (__func), "a" (__param), "0" (-EFAULT), - "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); - if (ret < 0) - return ret; - return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; -} - -/* - * Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation - * of the CPU. - * @param func: the function code passed to KM; see crypt_s390_klmd_func - * @param param: address of parameter block; see POP for details on each func - * @param src: address of source memory area - * @param src_len: length of src operand in bytes - * @returns < zero for failure, 0 for the query func, number of processed bytes - * for digest funcs - */ -static inline int -crypt_s390_kmac(long func, void* param, const u8* src, long src_len) -{ - register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; - register void* __param asm("1") = param; - register const u8* __src asm("2") = src; - register long __src_len asm("3") = src_len; - int ret; - - asm volatile( - "0: .insn rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */ - "1: brc 1,0b \n" /* handle partial completion */ - " ahi %0,%h6\n" - "2: ahi %0,%h7\n" - "3:\n" - EX_TABLE(0b,3b) EX_TABLE(1b,2b) - : "=d" (ret), "+a" (__src), "+d" (__src_len) - : "d" (__func), "a" (__param), "0" (-EFAULT), - "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); + : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); if (ret < 0) return ret; return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; } /** - * Tests if a specific crypto function is implemented on the machine. - * @param func: the function code of the specific function; 0 if op in general - * @return 1 if func available; 0 if func or op in general not available + * crypt_s390_kmc: + * @func: the function code passed to KM; see crypt_s390_kmc_func + * @param: address of parameter block; see POP for details on each func + * @dest: address of destination memory area + * @src: address of source memory area + * @src_len: length of src operand in bytes + * + * Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the CPU. + * + * Returns -1 for failure, 0 for the query func, number of processed + * bytes for encryption/decryption funcs */ -static inline int -crypt_s390_func_available(int func) +static inline int crypt_s390_kmc(long func, void *param, + u8 *dest, const u8 *src, long src_len) { + register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; + register void *__param asm("1") = param; + register const u8 *__src asm("2") = src; + register long __src_len asm("3") = src_len; + register u8 *__dest asm("4") = dest; int ret; - struct crypt_s390_query_status status = { - .high = 0, - .low = 0 - }; - switch (func & CRYPT_S390_OP_MASK){ - case CRYPT_S390_KM: - ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0); - break; - case CRYPT_S390_KMC: - ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0); - break; - case CRYPT_S390_KIMD: - ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0); - break; - case CRYPT_S390_KLMD: - ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0); - break; - case CRYPT_S390_KMAC: - ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0); - break; - default: - ret = 0; - return ret; - } - if (ret >= 0){ - func &= CRYPT_S390_FUNC_MASK; - func &= 0x7f; //mask modifier bit - if (func < 64){ - ret = (status.high >> (64 - func - 1)) & 0x1; - } else { - ret = (status.low >> (128 - func - 1)) & 0x1; - } - } else { - ret = 0; - } - return ret; + asm volatile( + "0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC opcode */ + "1: brc 1,0b \n" /* handle partial completion */ + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) + : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest) + : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); + if (ret < 0) + return ret; + return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; } -#endif // _CRYPTO_ARCH_S390_CRYPT_S390_H +/** + * crypt_s390_kimd: + * @func: the function code passed to KM; see crypt_s390_kimd_func + * @param: address of parameter block; see POP for details on each func + * @src: address of source memory area + * @src_len: length of src operand in bytes + * + * Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation + * of the CPU. + * + * Returns -1 for failure, 0 for the query func, number of processed + * bytes for digest funcs + */ +static inline int crypt_s390_kimd(long func, void *param, + const u8 *src, long src_len) +{ + register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; + register void *__param asm("1") = param; + register const u8 *__src asm("2") = src; + register long __src_len asm("3") = src_len; + int ret; + + asm volatile( + "0: .insn rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */ + "1: brc 1,0b \n" /* handle partial completion */ + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) + : "=d" (ret), "+a" (__src), "+d" (__src_len) + : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); + if (ret < 0) + return ret; + return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; +} + +/** + * crypt_s390_klmd: + * @func: the function code passed to KM; see crypt_s390_klmd_func + * @param: address of parameter block; see POP for details on each func + * @src: address of source memory area + * @src_len: length of src operand in bytes + * + * Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the CPU. + * + * Returns -1 for failure, 0 for the query func, number of processed + * bytes for digest funcs + */ +static inline int crypt_s390_klmd(long func, void *param, + const u8 *src, long src_len) +{ + register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; + register void *__param asm("1") = param; + register const u8 *__src asm("2") = src; + register long __src_len asm("3") = src_len; + int ret; + + asm volatile( + "0: .insn rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */ + "1: brc 1,0b \n" /* handle partial completion */ + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) + : "=d" (ret), "+a" (__src), "+d" (__src_len) + : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); + if (ret < 0) + return ret; + return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; +} + +/** + * crypt_s390_kmac: + * @func: the function code passed to KM; see crypt_s390_klmd_func + * @param: address of parameter block; see POP for details on each func + * @src: address of source memory area + * @src_len: length of src operand in bytes + * + * Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation + * of the CPU. + * + * Returns -1 for failure, 0 for the query func, number of processed + * bytes for digest funcs + */ +static inline int crypt_s390_kmac(long func, void *param, + const u8 *src, long src_len) +{ + register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; + register void *__param asm("1") = param; + register const u8 *__src asm("2") = src; + register long __src_len asm("3") = src_len; + int ret; + + asm volatile( + "0: .insn rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */ + "1: brc 1,0b \n" /* handle partial completion */ + " la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) EX_TABLE(1b,2b) + : "=d" (ret), "+a" (__src), "+d" (__src_len) + : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory"); + if (ret < 0) + return ret; + return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; +} + +/** + * crypt_s390_func_available: + * @func: the function code of the specific function; 0 if op in general + * + * Tests if a specific crypto function is implemented on the machine. + * + * Returns 1 if func available; 0 if func or op in general not available + */ +static inline int crypt_s390_func_available(int func) +{ + unsigned char status[16]; + int ret; + + switch (func & CRYPT_S390_OP_MASK) { + case CRYPT_S390_KM: + ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0); + break; + case CRYPT_S390_KMC: + ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0); + break; + case CRYPT_S390_KIMD: + ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0); + break; + case CRYPT_S390_KLMD: + ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0); + break; + case CRYPT_S390_KMAC: + ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0); + break; + default: + return 0; + } + if (ret < 0) + return 0; + func &= CRYPT_S390_FUNC_MASK; + func &= 0x7f; /* mask modifier bit */ + return (status[func >> 3] & (0x80 >> (func & 7))) != 0; +} + +#endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */ diff --git a/arch/s390/crypto/crypt_s390_query.c b/arch/s390/crypto/crypt_s390_query.c deleted file mode 100644 index 54fb11d7fadd..000000000000 --- a/arch/s390/crypto/crypt_s390_query.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Cryptographic API. - * - * Support for s390 cryptographic instructions. - * Testing module for querying processor crypto capabilities. - * - * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Thomas Spatzier (tspat@de.ibm.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#include -#include -#include -#include -#include "crypt_s390.h" - -static void query_available_functions(void) -{ - printk(KERN_INFO "#####################\n"); - - /* query available KM functions */ - printk(KERN_INFO "KM_QUERY: %d\n", - crypt_s390_func_available(KM_QUERY)); - printk(KERN_INFO "KM_DEA: %d\n", - crypt_s390_func_available(KM_DEA_ENCRYPT)); - printk(KERN_INFO "KM_TDEA_128: %d\n", - crypt_s390_func_available(KM_TDEA_128_ENCRYPT)); - printk(KERN_INFO "KM_TDEA_192: %d\n", - crypt_s390_func_available(KM_TDEA_192_ENCRYPT)); - printk(KERN_INFO "KM_AES_128: %d\n", - crypt_s390_func_available(KM_AES_128_ENCRYPT)); - printk(KERN_INFO "KM_AES_192: %d\n", - crypt_s390_func_available(KM_AES_192_ENCRYPT)); - printk(KERN_INFO "KM_AES_256: %d\n", - crypt_s390_func_available(KM_AES_256_ENCRYPT)); - - /* query available KMC functions */ - printk(KERN_INFO "KMC_QUERY: %d\n", - crypt_s390_func_available(KMC_QUERY)); - printk(KERN_INFO "KMC_DEA: %d\n", - crypt_s390_func_available(KMC_DEA_ENCRYPT)); - printk(KERN_INFO "KMC_TDEA_128: %d\n", - crypt_s390_func_available(KMC_TDEA_128_ENCRYPT)); - printk(KERN_INFO "KMC_TDEA_192: %d\n", - crypt_s390_func_available(KMC_TDEA_192_ENCRYPT)); - printk(KERN_INFO "KMC_AES_128: %d\n", - crypt_s390_func_available(KMC_AES_128_ENCRYPT)); - printk(KERN_INFO "KMC_AES_192: %d\n", - crypt_s390_func_available(KMC_AES_192_ENCRYPT)); - printk(KERN_INFO "KMC_AES_256: %d\n", - crypt_s390_func_available(KMC_AES_256_ENCRYPT)); - - /* query available KIMD functions */ - printk(KERN_INFO "KIMD_QUERY: %d\n", - crypt_s390_func_available(KIMD_QUERY)); - printk(KERN_INFO "KIMD_SHA_1: %d\n", - crypt_s390_func_available(KIMD_SHA_1)); - printk(KERN_INFO "KIMD_SHA_256: %d\n", - crypt_s390_func_available(KIMD_SHA_256)); - - /* query available KLMD functions */ - printk(KERN_INFO "KLMD_QUERY: %d\n", - crypt_s390_func_available(KLMD_QUERY)); - printk(KERN_INFO "KLMD_SHA_1: %d\n", - crypt_s390_func_available(KLMD_SHA_1)); - printk(KERN_INFO "KLMD_SHA_256: %d\n", - crypt_s390_func_available(KLMD_SHA_256)); - - /* query available KMAC functions */ - printk(KERN_INFO "KMAC_QUERY: %d\n", - crypt_s390_func_available(KMAC_QUERY)); - printk(KERN_INFO "KMAC_DEA: %d\n", - crypt_s390_func_available(KMAC_DEA)); - printk(KERN_INFO "KMAC_TDEA_128: %d\n", - crypt_s390_func_available(KMAC_TDEA_128)); - printk(KERN_INFO "KMAC_TDEA_192: %d\n", - crypt_s390_func_available(KMAC_TDEA_192)); -} - -static int init(void) -{ - struct crypt_s390_query_status status = { - .high = 0, - .low = 0 - }; - - printk(KERN_INFO "crypt_s390: querying available crypto functions\n"); - crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0); - printk(KERN_INFO "KM:\t%016llx %016llx\n", - (unsigned long long) status.high, - (unsigned long long) status.low); - status.high = status.low = 0; - crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0); - printk(KERN_INFO "KMC:\t%016llx %016llx\n", - (unsigned long long) status.high, - (unsigned long long) status.low); - status.high = status.low = 0; - crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0); - printk(KERN_INFO "KIMD:\t%016llx %016llx\n", - (unsigned long long) status.high, - (unsigned long long) status.low); - status.high = status.low = 0; - crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0); - printk(KERN_INFO "KLMD:\t%016llx %016llx\n", - (unsigned long long) status.high, - (unsigned long long) status.low); - status.high = status.low = 0; - crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0); - printk(KERN_INFO "KMAC:\t%016llx %016llx\n", - (unsigned long long) status.high, - (unsigned long long) status.low); - - query_available_functions(); - return -ECANCELED; -} - -static void __exit cleanup(void) -{ -} - -module_init(init); -module_exit(cleanup); - -MODULE_LICENSE("GPL"); diff --git a/arch/s390/crypto/des_check_key.c b/arch/s390/crypto/des_check_key.c index e3f5c5f238fe..5706af266442 100644 --- a/arch/s390/crypto/des_check_key.c +++ b/arch/s390/crypto/des_check_key.c @@ -10,8 +10,9 @@ * scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL. * * s390 Version: - * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation - * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * Copyright IBM Corp. 2003 + * Author(s): Thomas Spatzier + * Jan Glauber (jan.glauber@de.ibm.com) * * Derived from "crypto/des.c" * Copyright (c) 1992 Dana L. How. @@ -30,6 +31,7 @@ #include #include #include +#include "crypto_des.h" #define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o)) diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index 2aba04852fe3..ea22707f435f 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -3,9 +3,9 @@ * * s390 implementation of the DES Cipher Algorithm. * - * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Thomas Spatzier (tspat@de.ibm.com) - * + * Copyright IBM Corp. 2003,2007 + * Author(s): Thomas Spatzier + * Jan Glauber (jan.glauber@de.ibm.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -557,7 +557,7 @@ static int init(void) if (!crypt_s390_func_available(KM_DEA_ENCRYPT) || !crypt_s390_func_available(KM_TDEA_128_ENCRYPT) || !crypt_s390_func_available(KM_TDEA_192_ENCRYPT)) - return -ENOSYS; + return -EOPNOTSUPP; ret = crypto_register_alg(&des_alg); if (ret) diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c new file mode 100644 index 000000000000..8eb3a1aedc22 --- /dev/null +++ b/arch/s390/crypto/prng.c @@ -0,0 +1,213 @@ +/* + * Copyright IBM Corp. 2006,2007 + * Author(s): Jan Glauber + * Driver for the s390 pseudo random number generator + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crypt_s390.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jan Glauber "); +MODULE_DESCRIPTION("s390 PRNG interface"); + +static int prng_chunk_size = 256; +module_param(prng_chunk_size, int, S_IRUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(prng_chunk_size, "PRNG read chunk size in bytes"); + +static int prng_entropy_limit = 4096; +module_param(prng_entropy_limit, int, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR); +MODULE_PARM_DESC(prng_entropy_limit, + "PRNG add entropy after that much bytes were produced"); + +/* + * Any one who considers arithmetical methods of producing random digits is, + * of course, in a state of sin. -- John von Neumann + */ + +struct s390_prng_data { + unsigned long count; /* how many bytes were produced */ + char *buf; +}; + +static struct s390_prng_data *p; + +/* copied from libica, use a non-zero initial parameter block */ +static unsigned char parm_block[32] = { +0x0F,0x2B,0x8E,0x63,0x8C,0x8E,0xD2,0x52,0x64,0xB7,0xA0,0x7B,0x75,0x28,0xB8,0xF4, +0x75,0x5F,0xD2,0xA6,0x8D,0x97,0x11,0xFF,0x49,0xD8,0x23,0xF3,0x7E,0x21,0xEC,0xA0, +}; + +static int prng_open(struct inode *inode, struct file *file) +{ + return nonseekable_open(inode, file); +} + +static void prng_add_entropy(void) +{ + __u64 entropy[4]; + unsigned int i; + int ret; + + for (i = 0; i < 16; i++) { + ret = crypt_s390_kmc(KMC_PRNG, parm_block, (char *)entropy, + (char *)entropy, sizeof(entropy)); + BUG_ON(ret < 0 || ret != sizeof(entropy)); + memcpy(parm_block, entropy, sizeof(entropy)); + } +} + +static void prng_seed(int nbytes) +{ + char buf[16]; + int i = 0; + + BUG_ON(nbytes > 16); + get_random_bytes(buf, nbytes); + + /* Add the entropy */ + while (nbytes >= 8) { + *((__u64 *)parm_block) ^= *((__u64 *)buf+i*8); + prng_add_entropy(); + i += 8; + nbytes -= 8; + } + prng_add_entropy(); +} + +static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes, + loff_t *ppos) +{ + int chunk, n; + int ret = 0; + int tmp; + + /* nbytes can be arbitrary long, we spilt it into chunks */ + while (nbytes) { + /* same as in extract_entropy_user in random.c */ + if (need_resched()) { + if (signal_pending(current)) { + if (ret == 0) + ret = -ERESTARTSYS; + break; + } + schedule(); + } + + /* + * we lose some random bytes if an attacker issues + * reads < 8 bytes, but we don't care + */ + chunk = min_t(int, nbytes, prng_chunk_size); + + /* PRNG only likes multiples of 8 bytes */ + n = (chunk + 7) & -8; + + if (p->count > prng_entropy_limit) + prng_seed(8); + + /* if the CPU supports PRNG stckf is present too */ + asm volatile(".insn s,0xb27c0000,%0" + : "=m" (*((unsigned long long *)p->buf)) : : "cc"); + + /* + * Beside the STCKF the input for the TDES-EDE is the output + * of the last operation. We differ here from X9.17 since we + * only store one timestamp into the buffer. Padding the whole + * buffer with timestamps does not improve security, since + * successive stckf have nearly constant offsets. + * If an attacker knows the first timestamp it would be + * trivial to guess the additional values. One timestamp + * is therefore enough and still guarantees unique input values. + * + * Note: you can still get strict X9.17 conformity by setting + * prng_chunk_size to 8 bytes. + */ + tmp = crypt_s390_kmc(KMC_PRNG, parm_block, p->buf, p->buf, n); + BUG_ON((tmp < 0) || (tmp != n)); + + p->count += n; + + if (copy_to_user(ubuf, p->buf, chunk)) + return -EFAULT; + + nbytes -= chunk; + ret += chunk; + ubuf += chunk; + } + return ret; +} + +static struct file_operations prng_fops = { + .owner = THIS_MODULE, + .open = &prng_open, + .release = NULL, + .read = &prng_read, +}; + +static struct miscdevice prng_dev = { + .name = "prandom", + .minor = MISC_DYNAMIC_MINOR, + .fops = &prng_fops, +}; + +static int __init prng_init(void) +{ + int ret; + + /* check if the CPU has a PRNG */ + if (!crypt_s390_func_available(KMC_PRNG)) + return -EOPNOTSUPP; + + if (prng_chunk_size < 8) + return -EINVAL; + + p = kmalloc(sizeof(struct s390_prng_data), GFP_KERNEL); + if (!p) + return -ENOMEM; + p->count = 0; + + p->buf = kmalloc(prng_chunk_size, GFP_KERNEL); + if (!p->buf) { + ret = -ENOMEM; + goto out_free; + } + + /* initialize the PRNG, add 128 bits of entropy */ + prng_seed(16); + + ret = misc_register(&prng_dev); + if (ret) { + printk(KERN_WARNING + "Could not register misc device for PRNG.\n"); + goto out_buf; + } + return 0; + +out_buf: + kfree(p->buf); +out_free: + kfree(p); + return ret; +} + +static void __exit prng_exit(void) +{ + /* wipe me */ + memset(p->buf, 0, prng_chunk_size); + kfree(p->buf); + kfree(p); + + misc_deregister(&prng_dev); +} + +module_init(prng_init); +module_exit(prng_exit); diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index 49ca8690ee39..969639f31977 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -8,8 +8,9 @@ * implementation written by Steve Reid. * * s390 Version: - * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation - * Author(s): Thomas Spatzier (tspat@de.ibm.com) + * Copyright IBM Corp. 2003,2007 + * Author(s): Thomas Spatzier + * Jan Glauber (jan.glauber@de.ibm.com) * * Derived from "crypto/sha1.c" * Copyright (c) Alan Smithee. @@ -43,16 +44,14 @@ struct crypt_s390_sha1_ctx { static void sha1_init(struct crypto_tfm *tfm) { struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm); - static const u32 initstate[5] = { - 0x67452301, - 0xEFCDAB89, - 0x98BADCFE, - 0x10325476, - 0xC3D2E1F0 - }; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; ctx->count = 0; - memcpy(ctx->state, &initstate, sizeof(initstate)); ctx->buf_len = 0; } @@ -63,13 +62,13 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data, long imd_len; sctx = crypto_tfm_ctx(tfm); - sctx->count += len * 8; //message bit length + sctx->count += len * 8; /* message bit length */ - //anything in buffer yet? -> must be completed + /* anything in buffer yet? -> must be completed */ if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) { - //complete full block and hash + /* complete full block and hash */ memcpy(sctx->buffer + sctx->buf_len, data, - SHA1_BLOCK_SIZE - sctx->buf_len); + SHA1_BLOCK_SIZE - sctx->buf_len); crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, SHA1_BLOCK_SIZE); data += SHA1_BLOCK_SIZE - sctx->buf_len; @@ -77,37 +76,36 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data, sctx->buf_len = 0; } - //rest of data contains full blocks? + /* rest of data contains full blocks? */ imd_len = len & ~0x3ful; - if (imd_len){ + if (imd_len) { crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, imd_len); data += imd_len; len -= imd_len; } - //anything left? store in buffer - if (len){ + /* anything left? store in buffer */ + if (len) { memcpy(sctx->buffer + sctx->buf_len , data, len); sctx->buf_len += len; } } -static void -pad_message(struct crypt_s390_sha1_ctx* sctx) +static void pad_message(struct crypt_s390_sha1_ctx* sctx) { int index; index = sctx->buf_len; - sctx->buf_len = (sctx->buf_len < 56)? - SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE; - //start pad with 1 + sctx->buf_len = (sctx->buf_len < 56) ? + SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE; + /* start pad with 1 */ sctx->buffer[index] = 0x80; - //pad with zeros + /* pad with zeros */ index++; memset(sctx->buffer + index, 0x00, sctx->buf_len - index); - //append length + /* append length */ memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count, - sizeof sctx->count); + sizeof sctx->count); } /* Add padding and return the message digest. */ @@ -115,47 +113,40 @@ static void sha1_final(struct crypto_tfm *tfm, u8 *out) { struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm); - //must perform manual padding + /* must perform manual padding */ pad_message(sctx); crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len); - //copy digest to out + /* copy digest to out */ memcpy(out, sctx->state, SHA1_DIGEST_SIZE); - /* Wipe context */ + /* wipe context */ memset(sctx, 0, sizeof *sctx); } static struct crypto_alg alg = { .cra_name = "sha1", - .cra_driver_name = "sha1-s390", + .cra_driver_name= "sha1-s390", .cra_priority = CRYPT_S390_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_DIGEST, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct crypt_s390_sha1_ctx), .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { .digest = { .dia_digestsize = SHA1_DIGEST_SIZE, - .dia_init = sha1_init, - .dia_update = sha1_update, - .dia_final = sha1_final } } + .dia_init = sha1_init, + .dia_update = sha1_update, + .dia_final = sha1_final } } }; -static int -init(void) +static int __init init(void) { - int ret = -ENOSYS; + if (!crypt_s390_func_available(KIMD_SHA_1)) + return -EOPNOTSUPP; - if (crypt_s390_func_available(KIMD_SHA_1)){ - ret = crypto_register_alg(&alg); - if (ret == 0){ - printk(KERN_INFO "crypt_s390: sha1_s390 loaded.\n"); - } - } - return ret; + return crypto_register_alg(&alg); } -static void __exit -fini(void) +static void __exit fini(void) { crypto_unregister_alg(&alg); } diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index 8e4e67503fe7..78436c696d37 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -4,7 +4,7 @@ * s390 implementation of the SHA256 Secure Hash Algorithm. * * s390 Version: - * Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation + * Copyright IBM Corp. 2005,2007 * Author(s): Jan Glauber (jang@de.ibm.com) * * Derived from "crypto/sha256.c" @@ -143,15 +143,10 @@ static struct crypto_alg alg = { static int init(void) { - int ret; - if (!crypt_s390_func_available(KIMD_SHA_256)) - return -ENOSYS; + return -EOPNOTSUPP; - ret = crypto_register_alg(&alg); - if (ret != 0) - printk(KERN_INFO "crypt_s390: sha256_s390 couldn't be loaded."); - return ret; + return crypto_register_alg(&alg); } static void __exit fini(void) diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 5368cf4a350e..7c621b8ef683 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -108,6 +108,8 @@ CONFIG_DEFAULT_MIGRATION_COST=1000000 CONFIG_COMPAT=y CONFIG_SYSVIPC_COMPAT=y CONFIG_AUDIT_ARCH=y +CONFIG_S390_SWITCH_AMODE=y +CONFIG_S390_EXEC_PROTECT=y # # Code generation options @@ -431,7 +433,6 @@ CONFIG_TN3270_CONSOLE=y CONFIG_TN3215=y CONFIG_TN3215_CONSOLE=y CONFIG_CCW_CONSOLE=y -CONFIG_SCLP=y CONFIG_SCLP_TTY=y CONFIG_SCLP_CONSOLE=y CONFIG_SCLP_VT220_TTY=y @@ -724,9 +725,7 @@ CONFIG_CRYPTO_MANAGER=y # CONFIG_CRYPTO_MD4 is not set # CONFIG_CRYPTO_MD5 is not set # CONFIG_CRYPTO_SHA1 is not set -# CONFIG_CRYPTO_SHA1_S390 is not set # CONFIG_CRYPTO_SHA256 is not set -# CONFIG_CRYPTO_SHA256_S390 is not set # CONFIG_CRYPTO_SHA512 is not set # CONFIG_CRYPTO_WP512 is not set # CONFIG_CRYPTO_TGR192 is not set @@ -735,12 +734,10 @@ CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_CBC=y # CONFIG_CRYPTO_LRW is not set # CONFIG_CRYPTO_DES is not set -# CONFIG_CRYPTO_DES_S390 is not set # CONFIG_CRYPTO_BLOWFISH is not set # CONFIG_CRYPTO_TWOFISH is not set # CONFIG_CRYPTO_SERPENT is not set # CONFIG_CRYPTO_AES is not set -# CONFIG_CRYPTO_AES_S390 is not set # CONFIG_CRYPTO_CAST5 is not set # CONFIG_CRYPTO_CAST6 is not set # CONFIG_CRYPTO_TEA is not set @@ -755,6 +752,11 @@ CONFIG_CRYPTO_CBC=y # # Hardware crypto devices # +# CONFIG_CRYPTO_SHA1_S390 is not set +# CONFIG_CRYPTO_SHA256_S390 is not set +# CONFIG_CRYPTO_DES_S390 is not set +# CONFIG_CRYPTO_AES_S390 is not set +CONFIG_S390_PRNG=m # # Library routines diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile index f4b00cd81f7c..b08d2abf6178 100644 --- a/arch/s390/hypfs/Makefile +++ b/arch/s390/hypfs/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o -s390_hypfs-objs := inode.o hypfs_diag.o +s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h index f3dbd91965c6..aea572009d60 100644 --- a/arch/s390/hypfs/hypfs.h +++ b/arch/s390/hypfs/hypfs.h @@ -27,4 +27,13 @@ extern struct dentry *hypfs_create_str(struct super_block *sb, struct dentry *dir, const char *name, char *string); +/* LPAR Hypervisor */ +extern int hypfs_diag_init(void); +extern void hypfs_diag_exit(void); +extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root); + +/* VM Hypervisor */ +extern int hypfs_vm_init(void); +extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root); + #endif /* _HYPFS_H_ */ diff --git a/arch/s390/hypfs/hypfs_diag.h b/arch/s390/hypfs/hypfs_diag.h deleted file mode 100644 index 256b384aebe1..000000000000 --- a/arch/s390/hypfs/hypfs_diag.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * arch/s390/hypfs_diag.h - * Hypervisor filesystem for Linux on s390. - * - * Copyright (C) IBM Corp. 2006 - * Author(s): Michael Holzheu - */ - -#ifndef _HYPFS_DIAG_H_ -#define _HYPFS_DIAG_H_ - -extern int hypfs_diag_init(void); -extern void hypfs_diag_exit(void); -extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root); - -#endif /* _HYPFS_DIAG_H_ */ diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c new file mode 100644 index 000000000000..d01fc8f799f0 --- /dev/null +++ b/arch/s390/hypfs/hypfs_vm.c @@ -0,0 +1,231 @@ +/* + * Hypervisor filesystem for Linux on s390. z/VM implementation. + * + * Copyright (C) IBM Corp. 2006 + * Author(s): Michael Holzheu + */ + +#include +#include +#include +#include +#include +#include "hypfs.h" + +#define NAME_LEN 8 + +static char local_guest[] = " "; +static char all_guests[] = "* "; +static char *guest_query; + +struct diag2fc_data { + __u32 version; + __u32 flags; + __u64 used_cpu; + __u64 el_time; + __u64 mem_min_kb; + __u64 mem_max_kb; + __u64 mem_share_kb; + __u64 mem_used_kb; + __u32 pcpus; + __u32 lcpus; + __u32 vcpus; + __u32 cpu_min; + __u32 cpu_max; + __u32 cpu_shares; + __u32 cpu_use_samp; + __u32 cpu_delay_samp; + __u32 page_wait_samp; + __u32 idle_samp; + __u32 other_samp; + __u32 total_samp; + char guest_name[NAME_LEN]; +}; + +struct diag2fc_parm_list { + char userid[NAME_LEN]; + char aci_grp[NAME_LEN]; + __u64 addr; + __u32 size; + __u32 fmt; +}; + +static int diag2fc(int size, char* query, void *addr) +{ + unsigned long residual_cnt; + unsigned long rc; + struct diag2fc_parm_list parm_list; + + memcpy(parm_list.userid, query, NAME_LEN); + ASCEBC(parm_list.userid, NAME_LEN); + parm_list.addr = (unsigned long) addr ; + parm_list.size = size; + parm_list.fmt = 0x02; + memset(parm_list.aci_grp, 0x40, NAME_LEN); + rc = -1; + + asm volatile( + " diag %0,%1,0x2fc\n" + "0:\n" + EX_TABLE(0b,0b) + : "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory"); + + if ((rc != 0 ) && (rc != -2)) + return rc; + else + return -residual_cnt; +} + +static struct diag2fc_data *diag2fc_store(char *query, int *count) +{ + int size; + struct diag2fc_data *data; + + do { + size = diag2fc(0, query, NULL); + if (size < 0) + return ERR_PTR(-EACCES); + data = vmalloc(size); + if (!data) + return ERR_PTR(-ENOMEM); + if (diag2fc(size, query, data) == 0) + break; + vfree(data); + } while (1); + *count = (size / sizeof(*data)); + + return data; +} + +static void diag2fc_free(void *data) +{ + vfree(data); +} + +#define ATTRIBUTE(sb, dir, name, member) \ +do { \ + void *rc; \ + rc = hypfs_create_u64(sb, dir, name, member); \ + if (IS_ERR(rc)) \ + return PTR_ERR(rc); \ +} while(0) + +static int hpyfs_vm_create_guest(struct super_block *sb, + struct dentry *systems_dir, + struct diag2fc_data *data) +{ + char guest_name[NAME_LEN + 1] = {}; + struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir; + int dedicated_flag, capped_value; + + capped_value = (data->flags & 0x00000006) >> 1; + dedicated_flag = (data->flags & 0x00000008) >> 3; + + /* guest dir */ + memcpy(guest_name, data->guest_name, NAME_LEN); + EBCASC(guest_name, NAME_LEN); + strstrip(guest_name); + guest_dir = hypfs_mkdir(sb, systems_dir, guest_name); + if (IS_ERR(guest_dir)) + return PTR_ERR(guest_dir); + ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time); + + /* logical cpu information */ + cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus"); + if (IS_ERR(cpus_dir)) + return PTR_ERR(cpus_dir); + ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu); + ATTRIBUTE(sb, cpus_dir, "capped", capped_value); + ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag); + ATTRIBUTE(sb, cpus_dir, "count", data->vcpus); + ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min); + ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max); + ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares); + + /* memory information */ + mem_dir = hypfs_mkdir(sb, guest_dir, "mem"); + if (IS_ERR(mem_dir)) + return PTR_ERR(mem_dir); + ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb); + ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb); + ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb); + ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb); + + /* samples */ + samples_dir = hypfs_mkdir(sb, guest_dir, "samples"); + if (IS_ERR(samples_dir)) + return PTR_ERR(samples_dir); + ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp); + ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp); + ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp); + ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp); + ATTRIBUTE(sb, samples_dir, "other", data->other_samp); + ATTRIBUTE(sb, samples_dir, "total", data->total_samp); + return 0; +} + +int hypfs_vm_create_files(struct super_block *sb, struct dentry *root) +{ + struct dentry *dir, *file; + struct diag2fc_data *data; + int rc, i, count = 0; + + data = diag2fc_store(guest_query, &count); + if (IS_ERR(data)) + return PTR_ERR(data); + + /* Hpervisor Info */ + dir = hypfs_mkdir(sb, root, "hyp"); + if (IS_ERR(dir)) { + rc = PTR_ERR(dir); + goto failed; + } + file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor"); + if (IS_ERR(file)) { + rc = PTR_ERR(file); + goto failed; + } + + /* physical cpus */ + dir = hypfs_mkdir(sb, root, "cpus"); + if (IS_ERR(dir)) { + rc = PTR_ERR(dir); + goto failed; + } + file = hypfs_create_u64(sb, dir, "count", data->lcpus); + if (IS_ERR(file)) { + rc = PTR_ERR(file); + goto failed; + } + + /* guests */ + dir = hypfs_mkdir(sb, root, "systems"); + if (IS_ERR(dir)) { + rc = PTR_ERR(dir); + goto failed; + } + + for (i = 0; i < count; i++) { + rc = hpyfs_vm_create_guest(sb, dir, &(data[i])); + if (rc) + goto failed; + } + diag2fc_free(data); + return 0; + +failed: + diag2fc_free(data); + return rc; +} + +int hypfs_vm_init(void) +{ + if (diag2fc(0, all_guests, NULL) > 0) + guest_query = all_guests; + else if (diag2fc(0, local_guest, NULL) > 0) + guest_query = local_guest; + else + return -EACCES; + + return 0; +} diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index b6716c4b9934..a4fda7b53640 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -19,7 +19,6 @@ #include #include #include "hypfs.h" -#include "hypfs_diag.h" #define HYPFS_MAGIC 0x687970 /* ASCII 'hyp' */ #define TMP_SIZE 64 /* size of temporary buffers */ @@ -192,7 +191,10 @@ static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov, goto out; } hypfs_delete_tree(sb->s_root); - rc = hypfs_diag_create_files(sb, sb->s_root); + if (MACHINE_IS_VM) + rc = hypfs_vm_create_files(sb, sb->s_root); + else + rc = hypfs_diag_create_files(sb, sb->s_root); if (rc) { printk(KERN_ERR "hypfs: Update failed\n"); hypfs_delete_tree(sb->s_root); @@ -289,7 +291,10 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent) rc = -ENOMEM; goto err_alloc; } - rc = hypfs_diag_create_files(sb, root_dentry); + if (MACHINE_IS_VM) + rc = hypfs_vm_create_files(sb, root_dentry); + else + rc = hypfs_diag_create_files(sb, root_dentry); if (rc) goto err_tree; sbi->update_file = hypfs_create_update_file(sb, root_dentry); @@ -462,11 +467,15 @@ static int __init hypfs_init(void) { int rc; - if (MACHINE_IS_VM) - return -ENODATA; - if (hypfs_diag_init()) { - rc = -ENODATA; - goto fail_diag; + if (MACHINE_IS_VM) { + if (hypfs_vm_init()) + /* no diag 2fc, just exit */ + return -ENODATA; + } else { + if (hypfs_diag_init()) { + rc = -ENODATA; + goto fail_diag; + } } kset_set_kset_s(&s390_subsys, hypervisor_subsys); rc = subsystem_register(&s390_subsys); @@ -480,7 +489,8 @@ static int __init hypfs_init(void) fail_filesystem: subsystem_unregister(&s390_subsys); fail_sysfs: - hypfs_diag_exit(); + if (!MACHINE_IS_VM) + hypfs_diag_exit(); fail_diag: printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc); return rc; @@ -488,7 +498,8 @@ fail_diag: static void __exit hypfs_exit(void) { - hypfs_diag_exit(); + if (!MACHINE_IS_VM) + hypfs_diag_exit(); unregister_filesystem(&hypfs_type); subsystem_unregister(&s390_subsys); } diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index a81881c9b297..5492d25d7d69 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -4,9 +4,9 @@ EXTRA_AFLAGS := -traditional -obj-y := bitmap.o traps.o time.o process.o reset.o \ +obj-y := bitmap.o traps.o time.o process.o base.o early.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o + semaphore.o s390_ext.o debug.o irq.o ipl.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S new file mode 100644 index 000000000000..dc7e5259770f --- /dev/null +++ b/arch/s390/kernel/base.S @@ -0,0 +1,150 @@ +/* + * arch/s390/kernel/base.S + * + * Copyright IBM Corp. 2006,2007 + * Author(s): Heiko Carstens + * Michael Holzheu + */ + +#include +#include + +#ifdef CONFIG_64BIT + + .globl s390_base_mcck_handler +s390_base_mcck_handler: + basr %r13,0 +0: lg %r15,__LC_PANIC_STACK # load panic stack + aghi %r15,-STACK_FRAME_OVERHEAD + larl %r1,s390_base_mcck_handler_fn + lg %r1,0(%r1) + ltgr %r1,%r1 + jz 1f + basr %r14,%r1 +1: la %r1,4095 + lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) + lpswe __LC_MCK_OLD_PSW + + .section .bss + .globl s390_base_mcck_handler_fn +s390_base_mcck_handler_fn: + .quad 0 + .previous + + .globl s390_base_ext_handler +s390_base_ext_handler: + stmg %r0,%r15,__LC_SAVE_AREA + basr %r13,0 +0: aghi %r15,-STACK_FRAME_OVERHEAD + larl %r1,s390_base_ext_handler_fn + lg %r1,0(%r1) + ltgr %r1,%r1 + jz 1f + basr %r14,%r1 +1: lmg %r0,%r15,__LC_SAVE_AREA + ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit + lpswe __LC_EXT_OLD_PSW + + .section .bss + .globl s390_base_ext_handler_fn +s390_base_ext_handler_fn: + .quad 0 + .previous + + .globl s390_base_pgm_handler +s390_base_pgm_handler: + stmg %r0,%r15,__LC_SAVE_AREA + basr %r13,0 +0: aghi %r15,-STACK_FRAME_OVERHEAD + larl %r1,s390_base_pgm_handler_fn + lg %r1,0(%r1) + ltgr %r1,%r1 + jz 1f + basr %r14,%r1 + lmg %r0,%r15,__LC_SAVE_AREA + lpswe __LC_PGM_OLD_PSW +1: lpswe disabled_wait_psw-0b(%r13) + + .align 8 +disabled_wait_psw: + .quad 0x0002000180000000,0x0000000000000000 + s390_base_pgm_handler + + .section .bss + .globl s390_base_pgm_handler_fn +s390_base_pgm_handler_fn: + .quad 0 + .previous + +#else /* CONFIG_64BIT */ + + .globl s390_base_mcck_handler +s390_base_mcck_handler: + basr %r13,0 +0: l %r15,__LC_PANIC_STACK # load panic stack + ahi %r15,-STACK_FRAME_OVERHEAD + l %r1,2f-0b(%r13) + l %r1,0(%r1) + ltr %r1,%r1 + jz 1f + basr %r14,%r1 +1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA + lpsw __LC_MCK_OLD_PSW + +2: .long s390_base_mcck_handler_fn + + .section .bss + .globl s390_base_mcck_handler_fn +s390_base_mcck_handler_fn: + .long 0 + .previous + + .globl s390_base_ext_handler +s390_base_ext_handler: + stm %r0,%r15,__LC_SAVE_AREA + basr %r13,0 +0: ahi %r15,-STACK_FRAME_OVERHEAD + l %r1,2f-0b(%r13) + l %r1,0(%r1) + ltr %r1,%r1 + jz 1f + basr %r14,%r1 +1: lm %r0,%r15,__LC_SAVE_AREA + ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit + lpsw __LC_EXT_OLD_PSW + +2: .long s390_base_ext_handler_fn + + .section .bss + .globl s390_base_ext_handler_fn +s390_base_ext_handler_fn: + .long 0 + .previous + + .globl s390_base_pgm_handler +s390_base_pgm_handler: + stm %r0,%r15,__LC_SAVE_AREA + basr %r13,0 +0: ahi %r15,-STACK_FRAME_OVERHEAD + l %r1,2f-0b(%r13) + l %r1,0(%r1) + ltr %r1,%r1 + jz 1f + basr %r14,%r1 + lm %r0,%r15,__LC_SAVE_AREA + lpsw __LC_PGM_OLD_PSW + +1: lpsw disabled_wait_psw-0b(%r13) + +2: .long s390_base_pgm_handler_fn + +disabled_wait_psw: + .align 8 + .long 0x000a0000,0x00000000 + s390_base_pgm_handler + + .section .bss + .globl s390_base_pgm_handler_fn +s390_base_pgm_handler_fn: + .long 0 + .previous + +#endif /* CONFIG_64BIT */ diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c index 5c46054195cb..f1e40ca00d8d 100644 --- a/arch/s390/kernel/binfmt_elf32.c +++ b/arch/s390/kernel/binfmt_elf32.c @@ -192,7 +192,7 @@ MODULE_AUTHOR("Gerhard Tonn "); #undef cputime_to_timeval #define cputime_to_timeval cputime_to_compat_timeval -static __inline__ void +static inline void cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) { value->tv_usec = cputime % 1000000; diff --git a/arch/s390/kernel/compat_exec_domain.c b/arch/s390/kernel/compat_exec_domain.c index 71d27c493568..914d49444f92 100644 --- a/arch/s390/kernel/compat_exec_domain.c +++ b/arch/s390/kernel/compat_exec_domain.c @@ -12,10 +12,9 @@ #include #include -struct exec_domain s390_exec_domain; +static struct exec_domain s390_exec_domain; -static int __init -s390_init (void) +static int __init s390_init (void) { s390_exec_domain.name = "Linux/s390"; s390_exec_domain.handler = NULL; diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 5b33f823863a..666bb6daa148 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -69,6 +69,12 @@ #include "compat_linux.h" +long psw_user32_bits = (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME | + PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | + PSW_MASK_PSTATE | PSW_DEFAULT_KEY); +long psw32_user_bits = (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | + PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | + PSW32_MASK_PSTATE); /* For this source file, we want overflow handling. */ @@ -416,7 +422,7 @@ asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info) mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); - ret = sys_sysinfo((struct sysinfo __user *) &s); + ret = sys_sysinfo((struct sysinfo __force __user *) &s); set_fs (old_fs); err = put_user (s.uptime, &info->uptime); err |= __put_user (s.loads[0], &info->loads[0]); @@ -445,7 +451,8 @@ asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid, mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); - ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t); + ret = sys_sched_rr_get_interval(pid, + (struct timespec __force __user *) &t); set_fs (old_fs); if (put_compat_timespec(&t, interval)) return -EFAULT; @@ -472,8 +479,8 @@ asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set, } set_fs (KERNEL_DS); ret = sys_rt_sigprocmask(how, - set ? (sigset_t __user *) &s : NULL, - oset ? (sigset_t __user *) &s : NULL, + set ? (sigset_t __force __user *) &s : NULL, + oset ? (sigset_t __force __user *) &s : NULL, sigsetsize); set_fs (old_fs); if (ret) return ret; @@ -499,7 +506,7 @@ asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set, mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); - ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize); + ret = sys_rt_sigpending((sigset_t __force __user *) &s, sigsetsize); set_fs (old_fs); if (!ret) { switch (_NSIG_WORDS) { @@ -524,7 +531,7 @@ sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo) if (copy_siginfo_from_user32(&info, uinfo)) return -EFAULT; set_fs (KERNEL_DS); - ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info); + ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *) &info); set_fs (old_fs); return ret; } @@ -682,7 +689,7 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offse set_fs(KERNEL_DS); ret = sys_sendfile(out_fd, in_fd, - offset ? (off_t __user *) &of : NULL, count); + offset ? (off_t __force __user *) &of : NULL, count); set_fs(old_fs); if (offset && put_user(of, offset)) @@ -703,7 +710,8 @@ asmlinkage long sys32_sendfile64(int out_fd, int in_fd, set_fs(KERNEL_DS); ret = sys_sendfile64(out_fd, in_fd, - offset ? (loff_t __user *) &lof : NULL, count); + offset ? (loff_t __force __user *) &lof : NULL, + count); set_fs(old_fs); if (offset && put_user(lof, offset)) diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h index 1a18e29668ef..e89f8c0c42a0 100644 --- a/arch/s390/kernel/compat_linux.h +++ b/arch/s390/kernel/compat_linux.h @@ -115,37 +115,6 @@ typedef struct __u32 addr; } _psw_t32 __attribute__ ((aligned(8))); -#define PSW32_MASK_PER 0x40000000UL -#define PSW32_MASK_DAT 0x04000000UL -#define PSW32_MASK_IO 0x02000000UL -#define PSW32_MASK_EXT 0x01000000UL -#define PSW32_MASK_KEY 0x00F00000UL -#define PSW32_MASK_MCHECK 0x00040000UL -#define PSW32_MASK_WAIT 0x00020000UL -#define PSW32_MASK_PSTATE 0x00010000UL -#define PSW32_MASK_ASC 0x0000C000UL -#define PSW32_MASK_CC 0x00003000UL -#define PSW32_MASK_PM 0x00000f00UL - -#define PSW32_ADDR_AMODE31 0x80000000UL -#define PSW32_ADDR_INSN 0x7FFFFFFFUL - -#define PSW32_BASE_BITS 0x00080000UL - -#define PSW32_ASC_PRIMARY 0x00000000UL -#define PSW32_ASC_ACCREG 0x00004000UL -#define PSW32_ASC_SECONDARY 0x00008000UL -#define PSW32_ASC_HOME 0x0000C000UL - -#define PSW32_USER_BITS (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | \ - PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \ - PSW32_MASK_PSTATE) - -#define PSW32_MASK_MERGE(CURRENT,NEW) \ - (((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \ - ((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM))) - - typedef struct { _psw_t32 psw; diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 861888ab8c13..887a9881d0d0 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -275,8 +275,8 @@ sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss, } set_fs (KERNEL_DS); - ret = do_sigaltstack((stack_t __user *) (uss ? &kss : NULL), - (stack_t __user *) (uoss ? &koss : NULL), + ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL), + (stack_t __force __user *) (uoss ? &koss : NULL), regs->gprs[15]); set_fs (old_fs); @@ -298,7 +298,7 @@ static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs) _s390_regs_common32 regs32; int err, i; - regs32.psw.mask = PSW32_MASK_MERGE(PSW32_USER_BITS, + regs32.psw.mask = PSW32_MASK_MERGE(psw32_user_bits, (__u32)(regs->psw.mask >> 32)); regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr; for (i = 0; i < NUM_GPRS; i++) @@ -401,7 +401,7 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) goto badframe; set_fs (KERNEL_DS); - do_sigaltstack((stack_t __user *)&st, NULL, regs->gprs[15]); + do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]); set_fs (old_fs); return regs->gprs[2]; diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index a5972f1541fe..6c89f30c8e31 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -16,6 +16,7 @@ #include #include #include +#include static DEFINE_SPINLOCK(cpcmd_lock); static char cpcmd_buf[241]; @@ -88,13 +89,8 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) int len; unsigned long flags; - if ((rlen == 0) || (response == NULL) - || !((unsigned long)response >> 31)) { - spin_lock_irqsave(&cpcmd_lock, flags); - len = __cpcmd(cmd, response, rlen, response_code); - spin_unlock_irqrestore(&cpcmd_lock, flags); - } - else { + if ((virt_to_phys(response) != (unsigned long) response) || + (((unsigned long)response + rlen) >> 31)) { lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); if (!lowbuf) { printk(KERN_WARNING @@ -106,6 +102,10 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) spin_unlock_irqrestore(&cpcmd_lock, flags); memcpy(response, lowbuf, rlen); kfree(lowbuf); + } else { + spin_lock_irqsave(&cpcmd_lock, flags); + len = __cpcmd(cmd, response, rlen, response_code); + spin_unlock_irqrestore(&cpcmd_lock, flags); } return len; } diff --git a/arch/s390/kernel/crash.c b/arch/s390/kernel/crash.c index 926cceeae0fa..8cc7c9fa64f5 100644 --- a/arch/s390/kernel/crash.c +++ b/arch/s390/kernel/crash.c @@ -9,6 +9,7 @@ #include #include +#include void machine_crash_shutdown(struct pt_regs *regs) { diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index bb57bc0e3fc8..f4b62df02aa2 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -120,7 +120,7 @@ struct debug_view debug_hex_ascii_view = { NULL }; -struct debug_view debug_level_view = { +static struct debug_view debug_level_view = { "level", &debug_prolog_level_fn, NULL, @@ -129,7 +129,7 @@ struct debug_view debug_level_view = { NULL }; -struct debug_view debug_pages_view = { +static struct debug_view debug_pages_view = { "pages", &debug_prolog_pages_fn, NULL, @@ -138,7 +138,7 @@ struct debug_view debug_pages_view = { NULL }; -struct debug_view debug_flush_view = { +static struct debug_view debug_flush_view = { "flush", NULL, NULL, @@ -156,14 +156,14 @@ struct debug_view debug_sprintf_view = { NULL }; - +/* used by dump analysis tools to determine version of debug feature */ unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION; /* static globals */ static debug_info_t *debug_area_first = NULL; static debug_info_t *debug_area_last = NULL; -DECLARE_MUTEX(debug_lock); +static DECLARE_MUTEX(debug_lock); static int initialized; @@ -905,7 +905,7 @@ static struct ctl_table s390dbf_dir_table[] = { { .ctl_name = 0 } }; -struct ctl_table_header *s390dbf_sysctl_header; +static struct ctl_table_header *s390dbf_sysctl_header; void debug_stop_all(void) @@ -1300,8 +1300,7 @@ out: * flushes debug areas */ -void -debug_flush(debug_info_t* id, int area) +static void debug_flush(debug_info_t* id, int area) { unsigned long flags; int i,j; @@ -1511,8 +1510,7 @@ out: /* * clean up module */ -void -__exit debug_exit(void) +static void __exit debug_exit(void) { debugfs_remove(debug_debugfs_root_entry); unregister_sysctl_table(s390dbf_sysctl_header); diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c new file mode 100644 index 000000000000..e518dd53eff5 --- /dev/null +++ b/arch/s390/kernel/early.c @@ -0,0 +1,306 @@ +/* + * arch/s390/kernel/early.c + * + * Copyright IBM Corp. 2007 + * Author(s): Hongjie Yang , + * Heiko Carstens + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Create a Kernel NSS if the SAVESYS= parameter is defined + */ +#define DEFSYS_CMD_SIZE 96 +#define SAVESYS_CMD_SIZE 32 + +char kernel_nss_name[NSS_NAME_SIZE + 1]; + +#ifdef CONFIG_SHARED_KERNEL +static noinline __init void create_kernel_nss(void) +{ + unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size; +#ifdef CONFIG_BLK_DEV_INITRD + unsigned int sinitrd_pfn, einitrd_pfn; +#endif + int response; + char *savesys_ptr; + char upper_command_line[COMMAND_LINE_SIZE]; + char defsys_cmd[DEFSYS_CMD_SIZE]; + char savesys_cmd[SAVESYS_CMD_SIZE]; + + /* Do nothing if we are not running under VM */ + if (!MACHINE_IS_VM) + return; + + /* Convert COMMAND_LINE to upper case */ + for (i = 0; i < strlen(COMMAND_LINE); i++) + upper_command_line[i] = toupper(COMMAND_LINE[i]); + + savesys_ptr = strstr(upper_command_line, "SAVESYS="); + + if (!savesys_ptr) + return; + + savesys_ptr += 8; /* Point to the beginning of the NSS name */ + for (i = 0; i < NSS_NAME_SIZE; i++) { + if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0') + break; + kernel_nss_name[i] = savesys_ptr[i]; + } + + stext_pfn = PFN_DOWN(__pa(&_stext)); + eshared_pfn = PFN_DOWN(__pa(&_eshared)); + end_pfn = PFN_UP(__pa(&_end)); + min_size = end_pfn << 2; + + sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X", + kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1, + eshared_pfn, end_pfn); + +#ifdef CONFIG_BLK_DEV_INITRD + if (INITRD_START && INITRD_SIZE) { + sinitrd_pfn = PFN_DOWN(__pa(INITRD_START)); + einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE)); + min_size = einitrd_pfn << 2; + sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd, + sinitrd_pfn, einitrd_pfn); + } +#endif + + sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size); + sprintf(savesys_cmd, "SAVESYS %s \n IPL %s", + kernel_nss_name, kernel_nss_name); + + __cpcmd(defsys_cmd, NULL, 0, &response); + + if (response != 0) + return; + + __cpcmd(savesys_cmd, NULL, 0, &response); + + if (response != strlen(savesys_cmd)) + return; + + ipl_flags = IPL_NSS_VALID; +} + +#else /* CONFIG_SHARED_KERNEL */ + +static inline void create_kernel_nss(void) { } + +#endif /* CONFIG_SHARED_KERNEL */ + +/* + * Clear bss memory + */ +static noinline __init void clear_bss_section(void) +{ + memset(__bss_start, 0, _end - __bss_start); +} + +/* + * Initialize storage key for kernel pages + */ +static noinline __init void init_kernel_storage_key(void) +{ + unsigned long end_pfn, init_pfn; + + end_pfn = PFN_UP(__pa(&_end)); + + for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++) + page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); +} + +static noinline __init void detect_machine_type(void) +{ + struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data; + + asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id)); + + /* Running under z/VM ? */ + if (cpuinfo->cpu_id.version == 0xff) + machine_flags |= 1; + + /* Running on a P/390 ? */ + if (cpuinfo->cpu_id.machine == 0x7490) + machine_flags |= 4; +} + +static noinline __init int memory_fast_detect(void) +{ + + unsigned long val0 = 0; + unsigned long val1 = 0xc; + int ret = -ENOSYS; + + if (ipl_flags & IPL_NSS_VALID) + return -ENOSYS; + + asm volatile( + " diag %1,%2,0x260\n" + "0: lhi %0,0\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (ret), "+d" (val0), "+d" (val1) : : "cc"); + + if (ret || val0 != val1) + return -ENOSYS; + + memory_chunk[0].size = val0; + return 0; +} + +#define ADDR2G (1UL << 31) + +static noinline __init unsigned long sclp_memory_detect(void) +{ + struct sclp_readinfo_sccb *sccb; + unsigned long long memsize; + + sccb = &s390_readinfo_sccb; + + if (sccb->header.response_code != 0x10) + return 0; + + if (sccb->rnsize) + memsize = sccb->rnsize << 20; + else + memsize = sccb->rnsize2 << 20; + if (sccb->rnmax) + memsize *= sccb->rnmax; + else + memsize *= sccb->rnmax2; +#ifndef CONFIG_64BIT + /* + * Can't deal with more than 2G in 31 bit addressing mode, so + * limit the value in order to avoid strange side effects. + */ + if (memsize > ADDR2G) + memsize = ADDR2G; +#endif + return (unsigned long) memsize; +} + +static inline __init unsigned long __tprot(unsigned long addr) +{ + int cc = -1; + + asm volatile( + " tprot 0(%1),0\n" + "0: ipm %0\n" + " srl %0,28\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (cc) : "a" (addr) : "cc"); + return (unsigned long)cc; +} + +/* Checking memory in 128KB increments. */ +#define CHUNK_INCR (1UL << 17) + +static noinline __init void find_memory_chunks(unsigned long memsize) +{ + unsigned long addr = 0, old_addr = 0; + unsigned long old_cc = CHUNK_READ_WRITE; + unsigned long cc; + int chunk = 0; + + while (chunk < MEMORY_CHUNKS) { + cc = __tprot(addr); + while (cc == old_cc) { + addr += CHUNK_INCR; + cc = __tprot(addr); +#ifndef CONFIG_64BIT + if (addr == ADDR2G) + break; +#endif + } + + if (old_addr != addr && + (old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) { + memory_chunk[chunk].addr = old_addr; + memory_chunk[chunk].size = addr - old_addr; + memory_chunk[chunk].type = old_cc; + chunk++; + } + + old_addr = addr; + old_cc = cc; + +#ifndef CONFIG_64BIT + if (addr == ADDR2G) + break; +#endif + /* + * Finish memory detection at the first hole, unless + * - we reached the hsa -> skip it. + * - we know there must be more. + */ + if (cc == -1UL && !memsize && old_addr != ADDR2G) + break; + if (memsize && addr >= memsize) + break; + } +} + +static __init void early_pgm_check_handler(void) +{ + unsigned long addr; + const struct exception_table_entry *fixup; + + addr = S390_lowcore.program_old_psw.addr; + fixup = search_exception_tables(addr & PSW_ADDR_INSN); + if (!fixup) + disabled_wait(0); + S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE; +} + +static noinline __init void setup_lowcore_early(void) +{ + psw_t psw; + + psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; + psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler; + S390_lowcore.external_new_psw = psw; + psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler; + S390_lowcore.program_new_psw = psw; + s390_base_pgm_handler_fn = early_pgm_check_handler; +} + +/* + * Save ipl parameters, clear bss memory, initialize storage keys + * and create a kernel NSS at startup if the SAVESYS= parm is defined + */ +void __init startup_init(void) +{ + unsigned long memsize; + + ipl_save_parameters(); + clear_bss_section(); + init_kernel_storage_key(); + lockdep_init(); + lockdep_off(); + detect_machine_type(); + create_kernel_nss(); + sort_main_extable(); + setup_lowcore_early(); + sclp_readinfo_early(); + memsize = sclp_memory_detect(); + if (memory_fast_detect() < 0) + find_memory_chunks(memsize); + lockdep_on(); +} diff --git a/arch/s390/kernel/ebcdic.c b/arch/s390/kernel/ebcdic.c index bb0f973137f0..cc0dc609d738 100644 --- a/arch/s390/kernel/ebcdic.c +++ b/arch/s390/kernel/ebcdic.c @@ -11,6 +11,7 @@ #include #include +#include /* * ASCII (IBM PC 437) -> EBCDIC 037 diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index eca507050e47..453fd3b4edea 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S @@ -51,175 +51,14 @@ startup_continue: st %r15,__LC_KERNEL_STACK # set end of kernel stack ahi %r15,-96 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain - - l %r14,.Lipl_save_parameters-.LPG1(%r13) +# +# Save ipl parameters, clear bss memory, initialize storage key for kernel pages, +# and create a kernel NSS if the SAVESYS= parm is defined +# + l %r14,.Lstartup_init-.LPG1(%r13) basr %r14,%r14 -# -# clear bss memory -# - l %r2,.Lbss_bgn-.LPG1(%r13) # start of bss - l %r3,.Lbss_end-.LPG1(%r13) # end of bss - sr %r3,%r2 # length of bss - sr %r4,%r4 - sr %r5,%r5 # set src,length and pad to zero - sr %r0,%r0 - mvcle %r2,%r4,0 # clear mem - jo .-4 # branch back, if not finish - l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word -.Lservicecall: - stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts - - stctl %r0, %r0,.Lcr-.LPG1(%r13) # get cr0 - la %r1,0x200 # set bit 22 - o %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1 - st %r1,.Lcr-.LPG1(%r13) - lctl %r0, %r0,.Lcr-.LPG1(%r13) # load modified cr0 - - mvc __LC_EXT_NEW_PSW(8),.Lpcext-.LPG1(%r13) # set postcall psw - la %r1, .Lsclph-.LPG1(%r13) - a %r1,__LC_EXT_NEW_PSW+4 # set handler - st %r1,__LC_EXT_NEW_PSW+4 - - l %r4,.Lsccbaddr-.LPG1(%r13) # %r4 is our index for sccb stuff - lr %r1,%r4 # our sccb - .insn rre,0xb2200000,%r2,%r1 # service call - ipm %r1 - srl %r1,28 # get cc code - xr %r3, %r3 - chi %r1,3 - be .Lfchunk-.LPG1(%r13) # leave - chi %r1,2 - be .Lservicecall-.LPG1(%r13) - lpsw .Lwaitsclp-.LPG1(%r13) -.Lsclph: - lh %r1,.Lsccbr-.Lsccb(%r4) - chi %r1,0x10 # 0x0010 is the sucess code - je .Lprocsccb # let's process the sccb - chi %r1,0x1f0 - bne .Lfchunk-.LPG1(%r13) # unhandled error code - c %r2, .Lrcp-.LPG1(%r13) # Did we try Read SCP forced - bne .Lfchunk-.LPG1(%r13) # if no, give up - l %r2, .Lrcp2-.LPG1(%r13) # try with Read SCP - b .Lservicecall-.LPG1(%r13) -.Lprocsccb: - lhi %r1,0 - icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0 - jnz .Lscnd - lhi %r1,0x800 # otherwise report 2GB -.Lscnd: - lhi %r3,0x800 # limit reported memory size to 2GB - cr %r1,%r3 - jl .Lno2gb - lr %r1,%r3 -.Lno2gb: - xr %r3,%r3 # same logic - ic %r3,.Lscpa1-.Lsccb(%r4) - chi %r3,0x00 - jne .Lcompmem - l %r3,.Lscpa2-.Lsccb(%r4) -.Lcompmem: - mr %r2,%r1 # mem in MB on 128-bit - l %r1,.Lonemb-.LPG1(%r13) - mr %r2,%r1 # mem size in bytes in %r3 - b .Lfchunk-.LPG1(%r13) - - .align 4 -.Lipl_save_parameters: - .long ipl_save_parameters -.Linittu: - .long init_thread_union -.Lpmask: - .byte 0 - .align 8 -.Lpcext:.long 0x00080000,0x80000000 -.Lcr: - .long 0x00 # place holder for cr0 - .align 8 -.Lwaitsclp: - .long 0x010a0000,0x80000000 + .Lsclph -.Lrcp: - .int 0x00120001 # Read SCP forced code -.Lrcp2: - .int 0x00020001 # Read SCP code -.Lonemb: - .int 0x100000 -.Lfchunk: - -# -# find memory chunks. -# - lr %r9,%r3 # end of mem - mvc __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13) - la %r1,1 # test in increments of 128KB - sll %r1,17 - l %r3,.Lmchunk-.LPG1(%r13) # get pointer to memory_chunk array - slr %r4,%r4 # set start of chunk to zero - slr %r5,%r5 # set end of chunk to zero - slr %r6,%r6 # set access code to zero - la %r10,MEMORY_CHUNKS # number of chunks -.Lloop: - tprot 0(%r5),0 # test protection of first byte - ipm %r7 - srl %r7,28 - clr %r6,%r7 # compare cc with last access code - be .Lsame-.LPG1(%r13) - lhi %r8,0 # no program checks - b .Lsavchk-.LPG1(%r13) -.Lsame: - ar %r5,%r1 # add 128KB to end of chunk - bno .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop -.Lchkmem: # > 2GB or tprot got a program check - lhi %r8,1 # set program check flag -.Lsavchk: - clr %r4,%r5 # chunk size > 0? - be .Lchkloop-.LPG1(%r13) - st %r4,0(%r3) # store start address of chunk - lr %r0,%r5 - slr %r0,%r4 - st %r0,4(%r3) # store size of chunk - st %r6,8(%r3) # store type of chunk - la %r3,12(%r3) - ahi %r10,-1 # update chunk number -.Lchkloop: - lr %r6,%r7 # set access code to last cc - # we got an exception or we're starting a new - # chunk , we must check if we should - # still try to find valid memory (if we detected - # the amount of available storage), and if we - # have chunks left - xr %r0,%r0 - clr %r0,%r9 # did we detect memory? - je .Ldonemem # if not, leave - chi %r10,0 # do we have chunks left? - je .Ldonemem - chi %r8,1 # program check ? - je .Lpgmchk - lr %r4,%r5 # potential new chunk - alr %r5,%r1 # add 128KB to end of chunk - j .Llpcnt -.Lpgmchk: - alr %r5,%r1 # add 128KB to end of chunk - lr %r4,%r5 # potential new chunk -.Llpcnt: - clr %r5,%r9 # should we go on? - jl .Lloop -.Ldonemem: l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags -# -# find out if we are running under VM -# - stidp __LC_CPUID # store cpuid - tm __LC_CPUID,0xff # running under VM ? - bno .Lnovm-.LPG1(%r13) - oi 3(%r12),1 # set VM flag -.Lnovm: - lh %r0,__LC_CPUID+4 # get cpu version - chi %r0,0x7490 # running on a P/390 ? - bne .Lnop390-.LPG1(%r13) - oi 3(%r12),4 # set P/390 flag -.Lnop390: - # # find out if we have an IEEE fpu # @@ -295,7 +134,6 @@ startup_continue: .long 0 # cr15: linkage stack operations .Lduct: .long 0,0,0,0,0,0,0,0 .long 0,0,0,0,0,0,0,0 -.Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem .Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu .Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg @@ -306,7 +144,9 @@ startup_continue: .Lbss_bgn: .long __bss_start .Lbss_end: .long _end .Lparmaddr: .long PARMAREA -.Lsccbaddr: .long .Lsccb +.Linittu: .long init_thread_union +.Lstartup_init: + .long startup_init .globl ipl_schib ipl_schib: @@ -322,26 +162,6 @@ ipl_devno: .word 0 .org 0x12000 -.globl s390_readinfo_sccb -s390_readinfo_sccb: -.Lsccb: - .hword 0x1000 # length, one page - .byte 0x00,0x00,0x00 - .byte 0x80 # variable response bit set -.Lsccbr: - .hword 0x00 # response code -.Lscpincr1: - .hword 0x00 -.Lscpa1: - .byte 0x00 - .fill 89,1,0 -.Lscpa2: - .int 0x00 -.Lscpincr2: - .quad 0x00 - .fill 3984,1,0 - .org 0x13000 - #ifdef CONFIG_SHARED_KERNEL .org 0x100000 #endif diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 6ba3f4512dd1..b8fec4e5c5d4 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -58,182 +58,14 @@ startup_continue: stg %r15,__LC_KERNEL_STACK # set end of kernel stack aghi %r15,-160 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain - - brasl %r14,ipl_save_parameters # -# clear bss memory +# Save ipl parameters, clear bss memory, initialize storage key for kernel pages, +# and create a kernel NSS if the SAVESYS= parm is defined # - larl %r2,__bss_start # start of bss segment - larl %r3,_end # end of bss segment - sgr %r3,%r2 # length of bss - sgr %r4,%r4 # - sgr %r5,%r5 # set src,length and pad to zero - mvcle %r2,%r4,0 # clear mem - jo .-4 # branch back, if not finish + brasl %r14,startup_init # set program check new psw mask mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) - larl %r1,.Lslowmemdetect # set program check address - stg %r1,__LC_PGM_NEW_PSW+8 - lghi %r1,0xc - diag %r0,%r1,0x260 # get memory size of virtual machine - cgr %r0,%r1 # different? -> old detection routine - jne .Lslowmemdetect - aghi %r1,1 # size is one more than end - larl %r2,memory_chunk - stg %r1,8(%r2) # store size of chunk - j .Ldonemem - -.Lslowmemdetect: - l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word -.Lservicecall: - stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts - - stctg %r0,%r0,.Lcr-.LPG1(%r13) # get cr0 - la %r1,0x200 # set bit 22 - og %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1 - stg %r1,.Lcr-.LPG1(%r13) - lctlg %r0,%r0,.Lcr-.LPG1(%r13) # load modified cr0 - - mvc __LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw - larl %r1,.Lsclph - stg %r1,__LC_EXT_NEW_PSW+8 # set handler - - larl %r4,.Lsccb # %r4 is our index for sccb stuff - lgr %r1,%r4 # our sccb - .insn rre,0xb2200000,%r2,%r1 # service call - ipm %r1 - srl %r1,28 # get cc code - xr %r3,%r3 - chi %r1,3 - be .Lfchunk-.LPG1(%r13) # leave - chi %r1,2 - be .Lservicecall-.LPG1(%r13) - lpswe .Lwaitsclp-.LPG1(%r13) -.Lsclph: - lh %r1,.Lsccbr-.Lsccb(%r4) - chi %r1,0x10 # 0x0010 is the sucess code - je .Lprocsccb # let's process the sccb - chi %r1,0x1f0 - bne .Lfchunk-.LPG1(%r13) # unhandled error code - c %r2,.Lrcp-.LPG1(%r13) # Did we try Read SCP forced - bne .Lfchunk-.LPG1(%r13) # if no, give up - l %r2,.Lrcp2-.LPG1(%r13) # try with Read SCP - b .Lservicecall-.LPG1(%r13) -.Lprocsccb: - lghi %r1,0 - icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0 - jnz .Lscnd - lg %r1,.Lscpincr2-.Lsccb(%r4) # otherwise use this one -.Lscnd: - xr %r3,%r3 # same logic - ic %r3,.Lscpa1-.Lsccb(%r4) - chi %r3,0x00 - jne .Lcompmem - l %r3,.Lscpa2-.Lsccb(%r4) -.Lcompmem: - mlgr %r2,%r1 # mem in MB on 128-bit - l %r1,.Lonemb-.LPG1(%r13) - mlgr %r2,%r1 # mem size in bytes in %r3 - b .Lfchunk-.LPG1(%r13) - - .align 4 -.Lpmask: - .byte 0 - .align 8 -.Lcr: - .quad 0x00 # place holder for cr0 -.Lwaitsclp: - .quad 0x0102000180000000,.Lsclph -.Lrcp: - .int 0x00120001 # Read SCP forced code -.Lrcp2: - .int 0x00020001 # Read SCP code -.Lonemb: - .int 0x100000 - -.Lfchunk: - -# -# find memory chunks. -# - lgr %r9,%r3 # end of mem - larl %r1,.Lchkmem # set program check address - stg %r1,__LC_PGM_NEW_PSW+8 - la %r1,1 # test in increments of 128KB - sllg %r1,%r1,17 - larl %r3,memory_chunk - slgr %r4,%r4 # set start of chunk to zero - slgr %r5,%r5 # set end of chunk to zero - slr %r6,%r6 # set access code to zero - la %r10,MEMORY_CHUNKS # number of chunks -.Lloop: - tprot 0(%r5),0 # test protection of first byte - ipm %r7 - srl %r7,28 - clr %r6,%r7 # compare cc with last access code - je .Lsame - lghi %r8,0 # no program checks - j .Lsavchk -.Lsame: - algr %r5,%r1 # add 128KB to end of chunk - # no need to check here, - brc 12,.Lloop # this is the same chunk -.Lchkmem: # > 16EB or tprot got a program check - lghi %r8,1 # set program check flag -.Lsavchk: - clgr %r4,%r5 # chunk size > 0? - je .Lchkloop - stg %r4,0(%r3) # store start address of chunk - lgr %r0,%r5 - slgr %r0,%r4 - stg %r0,8(%r3) # store size of chunk - st %r6,20(%r3) # store type of chunk - la %r3,24(%r3) - ahi %r10,-1 # update chunk number -.Lchkloop: - lr %r6,%r7 # set access code to last cc - # we got an exception or we're starting a new - # chunk , we must check if we should - # still try to find valid memory (if we detected - # the amount of available storage), and if we - # have chunks left - lghi %r4,1 - sllg %r4,%r4,31 - clgr %r5,%r4 - je .Lhsaskip - xr %r0, %r0 - clgr %r0, %r9 # did we detect memory? - je .Ldonemem # if not, leave - chi %r10, 0 # do we have chunks left? - je .Ldonemem -.Lhsaskip: - chi %r8,1 # program check ? - je .Lpgmchk - lgr %r4,%r5 # potential new chunk - algr %r5,%r1 # add 128KB to end of chunk - j .Llpcnt -.Lpgmchk: - algr %r5,%r1 # add 128KB to end of chunk - lgr %r4,%r5 # potential new chunk -.Llpcnt: - clgr %r5,%r9 # should we go on? - jl .Lloop -.Ldonemem: - larl %r12,machine_flags -# -# find out if we are running under VM -# - stidp __LC_CPUID # store cpuid - tm __LC_CPUID,0xff # running under VM ? - bno 0f-.LPG1(%r13) - oi 7(%r12),1 # set VM flag -0: lh %r0,__LC_CPUID+4 # get cpu version - chi %r0,0x7490 # running on a P/390 ? - bne 1f-.LPG1(%r13) - oi 7(%r12),4 # set P/390 flag -1: - # # find out if we have the MVPG instruction # @@ -336,25 +168,6 @@ ipl_devno: .word 0 .org 0x12000 -.globl s390_readinfo_sccb -s390_readinfo_sccb: -.Lsccb: - .hword 0x1000 # length, one page - .byte 0x00,0x00,0x00 - .byte 0x80 # variable response bit set -.Lsccbr: - .hword 0x00 # response code -.Lscpincr1: - .hword 0x00 -.Lscpa1: - .byte 0x00 - .fill 89,1,0 -.Lscpa2: - .int 0x00 -.Lscpincr2: - .quad 0x00 - .fill 3984,1,0 - .org 0x13000 #ifdef CONFIG_SHARED_KERNEL .org 0x100000 diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 9e9972e8a52b..052259530651 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -20,26 +20,27 @@ #include #include #include +#include #define IPL_PARM_BLOCK_VERSION 0 -#define LOADPARM_LEN 8 -extern char s390_readinfo_sccb[]; -#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010) -#define SCCB_LOADPARM (&s390_readinfo_sccb[24]) -#define SCCB_FLAG (s390_readinfo_sccb[91]) +#define SCCB_VALID (s390_readinfo_sccb.header.response_code == 0x10) +#define SCCB_LOADPARM (&s390_readinfo_sccb.loadparm) +#define SCCB_FLAG (s390_readinfo_sccb.flags) enum ipl_type { IPL_TYPE_NONE = 1, IPL_TYPE_UNKNOWN = 2, IPL_TYPE_CCW = 4, IPL_TYPE_FCP = 8, + IPL_TYPE_NSS = 16, }; #define IPL_NONE_STR "none" #define IPL_UNKNOWN_STR "unknown" #define IPL_CCW_STR "ccw" #define IPL_FCP_STR "fcp" +#define IPL_NSS_STR "nss" static char *ipl_type_str(enum ipl_type type) { @@ -50,6 +51,8 @@ static char *ipl_type_str(enum ipl_type type) return IPL_CCW_STR; case IPL_TYPE_FCP: return IPL_FCP_STR; + case IPL_TYPE_NSS: + return IPL_NSS_STR; case IPL_TYPE_UNKNOWN: default: return IPL_UNKNOWN_STR; @@ -64,6 +67,7 @@ enum ipl_method { IPL_METHOD_FCP_RO_DIAG, IPL_METHOD_FCP_RW_DIAG, IPL_METHOD_FCP_RO_VM, + IPL_METHOD_NSS, }; enum shutdown_action { @@ -114,11 +118,14 @@ enum diag308_rc { static int diag308_set_works = 0; static int reipl_capabilities = IPL_TYPE_UNKNOWN; + static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN; static enum ipl_method reipl_method = IPL_METHOD_NONE; static struct ipl_parameter_block *reipl_block_fcp; static struct ipl_parameter_block *reipl_block_ccw; +static char reipl_nss_name[NSS_NAME_SIZE + 1]; + static int dump_capabilities = IPL_TYPE_NONE; static enum ipl_type dump_type = IPL_TYPE_NONE; static enum ipl_method dump_method = IPL_METHOD_NONE; @@ -173,6 +180,24 @@ static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ sys_##_prefix##_##_name##_show, \ sys_##_prefix##_##_name##_store); +#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\ +static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \ + char *page) \ +{ \ + return sprintf(page, _fmt_out, _value); \ +} \ +static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\ + const char *buf, size_t len) \ +{ \ + if (sscanf(buf, _fmt_in, _value) != 1) \ + return -EINVAL; \ + return len; \ +} \ +static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ + __ATTR(_name,(S_IRUGO | S_IWUSR), \ + sys_##_prefix##_##_name##_show, \ + sys_##_prefix##_##_name##_store); + static void make_attrs_ro(struct attribute **attrs) { while (*attrs) { @@ -189,6 +214,8 @@ static enum ipl_type ipl_get_type(void) { struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; + if (ipl_flags & IPL_NSS_VALID) + return IPL_TYPE_NSS; if (!(ipl_flags & IPL_DEVNO_VALID)) return IPL_TYPE_UNKNOWN; if (!(ipl_flags & IPL_PARMBLOCK_VALID)) @@ -324,6 +351,20 @@ static struct attribute_group ipl_ccw_attr_group = { .attrs = ipl_ccw_attrs, }; +/* NSS ipl device attributes */ + +DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name); + +static struct attribute *ipl_nss_attrs[] = { + &sys_ipl_type_attr.attr, + &sys_ipl_nss_name_attr.attr, + NULL, +}; + +static struct attribute_group ipl_nss_attr_group = { + .attrs = ipl_nss_attrs, +}; + /* UNKNOWN ipl device attributes */ static struct attribute *ipl_unknown_attrs[] = { @@ -432,6 +473,21 @@ static struct attribute_group reipl_ccw_attr_group = { .attrs = reipl_ccw_attrs, }; + +/* NSS reipl device attributes */ + +DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name); + +static struct attribute *reipl_nss_attrs[] = { + &sys_reipl_nss_name_attr.attr, + NULL, +}; + +static struct attribute_group reipl_nss_attr_group = { + .name = IPL_NSS_STR, + .attrs = reipl_nss_attrs, +}; + /* reipl type */ static int reipl_set_type(enum ipl_type type) @@ -454,6 +510,9 @@ static int reipl_set_type(enum ipl_type type) else reipl_method = IPL_METHOD_FCP_RO_DIAG; break; + case IPL_TYPE_NSS: + reipl_method = IPL_METHOD_NSS; + break; default: reipl_method = IPL_METHOD_NONE; } @@ -475,6 +534,8 @@ static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf, rc = reipl_set_type(IPL_TYPE_CCW); else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0) rc = reipl_set_type(IPL_TYPE_FCP); + else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0) + rc = reipl_set_type(IPL_TYPE_NSS); return (rc != 0) ? rc : len; } @@ -647,6 +708,10 @@ void do_reipl(void) case IPL_METHOD_FCP_RO_VM: __cpcmd("IPL", NULL, 0, NULL); break; + case IPL_METHOD_NSS: + sprintf(buf, "IPL %s", reipl_nss_name); + __cpcmd(buf, NULL, 0, NULL); + break; case IPL_METHOD_NONE: default: if (MACHINE_IS_VM) @@ -733,6 +798,10 @@ static int __init ipl_init(void) case IPL_TYPE_FCP: rc = ipl_register_fcp_files(); break; + case IPL_TYPE_NSS: + rc = sysfs_create_group(&ipl_subsys.kset.kobj, + &ipl_nss_attr_group); + break; default: rc = sysfs_create_group(&ipl_subsys.kset.kobj, &ipl_unknown_attr_group); @@ -755,6 +824,20 @@ static void __init reipl_probe(void) free_page((unsigned long)buffer); } +static int __init reipl_nss_init(void) +{ + int rc; + + if (!MACHINE_IS_VM) + return 0; + rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group); + if (rc) + return rc; + strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1); + reipl_capabilities |= IPL_TYPE_NSS; + return 0; +} + static int __init reipl_ccw_init(void) { int rc; @@ -835,6 +918,9 @@ static int __init reipl_init(void) if (rc) return rc; rc = reipl_fcp_init(); + if (rc) + return rc; + rc = reipl_nss_init(); if (rc) return rc; rc = reipl_set_type(ipl_get_type()); @@ -993,8 +1079,6 @@ static void do_reset_calls(void) reset->fn(); } -extern void reset_mcck_handler(void); -extern void reset_pgm_handler(void); extern __u32 dump_prefix_page; void s390_reset_system(void) @@ -1016,14 +1100,14 @@ void s390_reset_system(void) __ctl_clear_bit(0,28); /* Set new machine check handler */ - S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK; + S390_lowcore.mcck_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK; S390_lowcore.mcck_new_psw.addr = - PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler; + PSW_ADDR_AMODE | (unsigned long) s390_base_mcck_handler; /* Set new program check handler */ - S390_lowcore.program_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK; + S390_lowcore.program_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK; S390_lowcore.program_new_psw.addr = - PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler; + PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler; do_reset_calls(); } diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 1eef50918615..8f0cbca31203 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -1,9 +1,9 @@ /* * arch/s390/kernel/irq.c * - * S390 version - * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2004,2007 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * Thomas Spatzier (tspat@de.ibm.com) * * This file contains interrupt related functions. */ @@ -14,6 +14,8 @@ #include #include #include +#include +#include /* * show_interrupts is needed by /proc/interrupts. @@ -93,5 +95,12 @@ asmlinkage void do_softirq(void) local_irq_restore(flags); } - EXPORT_SYMBOL(do_softirq); + +void init_irq_proc(void) +{ + struct proc_dir_entry *root_irq_dir; + + root_irq_dir = proc_mkdir("irq", NULL); + create_prof_cpu_mask(root_irq_dir); +} diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 576368c4f605..a466bab6677e 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -155,15 +155,34 @@ void __kprobes get_instruction_type(struct arch_specific_insn *ainsn) static int __kprobes swap_instruction(void *aref) { struct ins_replace_args *args = aref; + u32 *addr; + u32 instr; int err = -EFAULT; + /* + * Text segment is read-only, hence we use stura to bypass dynamic + * address translation to exchange the instruction. Since stura + * always operates on four bytes, but we only want to exchange two + * bytes do some calculations to get things right. In addition we + * shall not cross any page boundaries (vmalloc area!) when writing + * the new instruction. + */ + addr = (u32 *)ALIGN((unsigned long)args->ptr, 4); + if ((unsigned long)args->ptr & 2) + instr = ((*addr) & 0xffff0000) | args->new; + else + instr = ((*addr) & 0x0000ffff) | args->new << 16; + asm volatile( - "0: mvc 0(2,%2),0(%3)\n" - "1: la %0,0\n" + " lra %1,0(%1)\n" + "0: stura %2,%1\n" + "1: la %0,0\n" "2:\n" EX_TABLE(0b,2b) - : "+d" (err), "=m" (*args->ptr) - : "a" (args->ptr), "a" (&args->new), "m" (args->new)); + : "+d" (err) + : "a" (addr), "d" (instr) + : "memory", "cc"); + return err; } @@ -356,7 +375,7 @@ no_kprobe: * - When the probed function returns, this probe * causes the handlers to fire */ -void __kprobes kretprobe_trampoline_holder(void) +void kretprobe_trampoline_holder(void) { asm volatile(".global kretprobe_trampoline\n" "kretprobe_trampoline: bcr 0,0\n"); @@ -365,7 +384,8 @@ void __kprobes kretprobe_trampoline_holder(void) /* * Called when the probe at kretprobe trampoline is hit */ -int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) +static int __kprobes trampoline_probe_handler(struct kprobe *p, + struct pt_regs *regs) { struct kretprobe_instance *ri = NULL; struct hlist_head *head, empty_rp; diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index f6d9bcc0f75b..52f57af252b4 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index d989ed45a7aa..39d1dd752529 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -30,6 +30,7 @@ #include #include #include +#include #if 0 #define DEBUGP printk @@ -58,7 +59,7 @@ void module_free(struct module *mod, void *module_region) table entries. */ } -static inline void +static void check_rela(Elf_Rela *rela, struct module *me) { struct mod_arch_syminfo *info; @@ -181,7 +182,7 @@ apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, return -ENOEXEC; } -static inline int +static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, struct module *me) { diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 6603fbb41d07..5acfac654f9d 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -144,7 +144,7 @@ static void default_idle(void) trace_hardirqs_on(); /* Wait for external, I/O or machine check interrupt. */ - __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT | + __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_IO | PSW_MASK_EXT); } @@ -190,7 +190,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) struct pt_regs regs; memset(®s, 0, sizeof(regs)); - regs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT; + regs.psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT; regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE; regs.gprs[9] = (unsigned long) fn; regs.gprs[10] = (unsigned long) arg; diff --git a/arch/s390/kernel/profile.c b/arch/s390/kernel/profile.c deleted file mode 100644 index b81aa1f569ca..000000000000 --- a/arch/s390/kernel/profile.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * arch/s390/kernel/profile.c - * - * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Thomas Spatzier (tspat@de.ibm.com) - * - */ -#include -#include - -static struct proc_dir_entry * root_irq_dir; - -void init_irq_proc(void) -{ - /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", NULL); - - /* create /proc/irq/prof_cpu_mask */ - create_prof_cpu_mask(root_irq_dir); -} diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 8f36504075ed..2a8f0872ea8b 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -86,15 +86,13 @@ FixPerRegisters(struct task_struct *task) per_info->control_regs.bits.storage_alt_space_ctl = 0; } -void -set_single_step(struct task_struct *task) +static void set_single_step(struct task_struct *task) { task->thread.per_info.single_step = 1; FixPerRegisters(task); } -void -clear_single_step(struct task_struct *task) +static void clear_single_step(struct task_struct *task) { task->thread.per_info.single_step = 0; FixPerRegisters(task); @@ -232,9 +230,9 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data) */ if (addr == (addr_t) &dummy->regs.psw.mask && #ifdef CONFIG_COMPAT - data != PSW_MASK_MERGE(PSW_USER32_BITS, data) && + data != PSW_MASK_MERGE(psw_user32_bits, data) && #endif - data != PSW_MASK_MERGE(PSW_USER_BITS, data)) + data != PSW_MASK_MERGE(psw_user_bits, data)) /* Invalid psw mask. */ return -EINVAL; #ifndef CONFIG_64BIT @@ -309,7 +307,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data) copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) return -EIO; - return put_user(tmp, (unsigned long __user *) data); + return put_user(tmp, (unsigned long __force __user *) data); case PTRACE_PEEKUSR: /* read the word at location addr in the USER area. */ @@ -331,7 +329,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data) case PTRACE_PEEKUSR_AREA: case PTRACE_POKEUSR_AREA: - if (copy_from_user(&parea, (void __user *) addr, + if (copy_from_user(&parea, (void __force __user *) addr, sizeof(parea))) return -EFAULT; addr = parea.kernel_addr; @@ -341,10 +339,11 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data) if (request == PTRACE_PEEKUSR_AREA) ret = peek_user(child, addr, data); else { - addr_t tmp; - if (get_user (tmp, (addr_t __user *) data)) + addr_t utmp; + if (get_user(utmp, + (addr_t __force __user *) data)) return -EFAULT; - ret = poke_user(child, addr, tmp); + ret = poke_user(child, addr, utmp); } if (ret) return ret; @@ -394,7 +393,7 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data) if (addr == (addr_t) &dummy32->regs.psw.mask) { /* Fake a 31 bit psw mask. */ tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32); - tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp); + tmp = PSW32_MASK_MERGE(psw32_user_bits, tmp); } else if (addr == (addr_t) &dummy32->regs.psw.addr) { /* Fake a 31 bit psw address. */ tmp = (__u32) task_pt_regs(child)->psw.addr | @@ -469,11 +468,11 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data) */ if (addr == (addr_t) &dummy32->regs.psw.mask) { /* Build a 64 bit psw mask from 31 bit mask. */ - if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp)) + if (tmp != PSW32_MASK_MERGE(psw32_user_bits, tmp)) /* Invalid psw mask. */ return -EINVAL; task_pt_regs(child)->psw.mask = - PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32); + PSW_MASK_MERGE(psw_user32_bits, (__u64) tmp << 32); } else if (addr == (addr_t) &dummy32->regs.psw.addr) { /* Build a 64 bit psw address from 31 bit address. */ task_pt_regs(child)->psw.addr = @@ -550,7 +549,7 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data) copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) return -EIO; - return put_user(tmp, (unsigned int __user *) data); + return put_user(tmp, (unsigned int __force __user *) data); case PTRACE_PEEKUSR: /* read the word at location addr in the USER area. */ @@ -571,7 +570,7 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data) case PTRACE_PEEKUSR_AREA: case PTRACE_POKEUSR_AREA: - if (copy_from_user(&parea, (void __user *) addr, + if (copy_from_user(&parea, (void __force __user *) addr, sizeof(parea))) return -EFAULT; addr = parea.kernel_addr; @@ -581,10 +580,11 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data) if (request == PTRACE_PEEKUSR_AREA) ret = peek_user_emu31(child, addr, data); else { - __u32 tmp; - if (get_user (tmp, (__u32 __user *) data)) + __u32 utmp; + if (get_user(utmp, + (__u32 __force __user *) data)) return -EFAULT; - ret = poke_user_emu31(child, addr, tmp); + ret = poke_user_emu31(child, addr, utmp); } if (ret) return ret; @@ -595,17 +595,19 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data) return 0; case PTRACE_GETEVENTMSG: return put_user((__u32) child->ptrace_message, - (unsigned int __user *) data); + (unsigned int __force __user *) data); case PTRACE_GETSIGINFO: if (child->last_siginfo == NULL) return -EINVAL; - return copy_siginfo_to_user32((compat_siginfo_t __user *) data, + return copy_siginfo_to_user32((compat_siginfo_t + __force __user *) data, child->last_siginfo); case PTRACE_SETSIGINFO: if (child->last_siginfo == NULL) return -EINVAL; return copy_siginfo_from_user32(child->last_siginfo, - (compat_siginfo_t __user *) data); + (compat_siginfo_t + __force __user *) data); } return ptrace_request(child, request, addr, data); } diff --git a/arch/s390/kernel/reset.S b/arch/s390/kernel/reset.S deleted file mode 100644 index 8a87355161fa..000000000000 --- a/arch/s390/kernel/reset.S +++ /dev/null @@ -1,90 +0,0 @@ -/* - * arch/s390/kernel/reset.S - * - * Copyright (C) IBM Corp. 2006 - * Author(s): Heiko Carstens - * Michael Holzheu - */ - -#include -#include - -#ifdef CONFIG_64BIT - - .globl reset_mcck_handler -reset_mcck_handler: - basr %r13,0 -0: lg %r15,__LC_PANIC_STACK # load panic stack - aghi %r15,-STACK_FRAME_OVERHEAD - lg %r1,s390_reset_mcck_handler-0b(%r13) - ltgr %r1,%r1 - jz 1f - basr %r14,%r1 -1: la %r1,4095 - lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) - lpswe __LC_MCK_OLD_PSW - - .globl s390_reset_mcck_handler -s390_reset_mcck_handler: - .quad 0 - - .globl reset_pgm_handler -reset_pgm_handler: - stmg %r0,%r15,__LC_SAVE_AREA - basr %r13,0 -0: lg %r15,__LC_PANIC_STACK # load panic stack - aghi %r15,-STACK_FRAME_OVERHEAD - lg %r1,s390_reset_pgm_handler-0b(%r13) - ltgr %r1,%r1 - jz 1f - basr %r14,%r1 - lmg %r0,%r15,__LC_SAVE_AREA - lpswe __LC_PGM_OLD_PSW -1: lpswe disabled_wait_psw-0b(%r13) - .globl s390_reset_pgm_handler -s390_reset_pgm_handler: - .quad 0 - .align 8 -disabled_wait_psw: - .quad 0x0002000180000000,0x0000000000000000 + reset_pgm_handler - -#else /* CONFIG_64BIT */ - - .globl reset_mcck_handler -reset_mcck_handler: - basr %r13,0 -0: l %r15,__LC_PANIC_STACK # load panic stack - ahi %r15,-STACK_FRAME_OVERHEAD - l %r1,s390_reset_mcck_handler-0b(%r13) - ltr %r1,%r1 - jz 1f - basr %r14,%r1 -1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA - lpsw __LC_MCK_OLD_PSW - - .globl s390_reset_mcck_handler -s390_reset_mcck_handler: - .long 0 - - .globl reset_pgm_handler -reset_pgm_handler: - stm %r0,%r15,__LC_SAVE_AREA - basr %r13,0 -0: l %r15,__LC_PANIC_STACK # load panic stack - ahi %r15,-STACK_FRAME_OVERHEAD - l %r1,s390_reset_pgm_handler-0b(%r13) - ltr %r1,%r1 - jz 1f - basr %r14,%r1 - lm %r0,%r15,__LC_SAVE_AREA - lpsw __LC_PGM_OLD_PSW - -1: lpsw disabled_wait_psw-0b(%r13) - .globl s390_reset_pgm_handler -s390_reset_pgm_handler: - .long 0 -disabled_wait_psw: - .align 8 - .long 0x000a0000,0x00000000 + reset_pgm_handler - -#endif /* CONFIG_64BIT */ diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index bc5beaa8f98e..acf93dba7727 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c @@ -125,14 +125,12 @@ void do_extint(struct pt_regs *regs, unsigned short code) * Make sure that the i/o interrupt did not "overtake" * the last HZ timer interrupt. */ - account_ticks(); + account_ticks(S390_lowcore.int_clock); kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; index = ext_hash(code); for (p = ext_int_hash[index]; p; p = p->next) { - if (likely(p->code == code)) { - if (likely(p->handler)) - p->handler(code); - } + if (likely(p->code == code)) + p->handler(code); } irq_exit(); set_irq_regs(old_regs); diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 5d8ee3baac14..03739813d3bf 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #include @@ -49,6 +51,14 @@ #include #include #include +#include +#include + +long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | + PSW_MASK_MCHECK | PSW_DEFAULT_KEY); +long psw_user_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | + PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | + PSW_MASK_PSTATE | PSW_DEFAULT_KEY); /* * User copy operations. @@ -117,9 +127,9 @@ void __devinit cpu_init (void) */ char vmhalt_cmd[128] = ""; char vmpoff_cmd[128] = ""; -char vmpanic_cmd[128] = ""; +static char vmpanic_cmd[128] = ""; -static inline void strncpy_skip_quote(char *dst, char *src, int n) +static void strncpy_skip_quote(char *dst, char *src, int n) { int sx, dx; @@ -275,10 +285,6 @@ static void __init conmode_default(void) } #ifdef CONFIG_SMP -extern void machine_restart_smp(char *); -extern void machine_halt_smp(void); -extern void machine_power_off_smp(void); - void (*_machine_restart)(char *command) = machine_restart_smp; void (*_machine_halt)(void) = machine_halt_smp; void (*_machine_power_off)(void) = machine_power_off_smp; @@ -386,6 +392,84 @@ static int __init early_parse_ipldelay(char *p) } early_param("ipldelay", early_parse_ipldelay); +#ifdef CONFIG_S390_SWITCH_AMODE +unsigned int switch_amode = 0; +EXPORT_SYMBOL_GPL(switch_amode); + +static void set_amode_and_uaccess(unsigned long user_amode, + unsigned long user32_amode) +{ + psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode | + PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | + PSW_MASK_PSTATE | PSW_DEFAULT_KEY; +#ifdef CONFIG_COMPAT + psw_user32_bits = PSW_BASE32_BITS | PSW_MASK_DAT | user_amode | + PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | + PSW_MASK_PSTATE | PSW_DEFAULT_KEY; + psw32_user_bits = PSW32_BASE_BITS | PSW32_MASK_DAT | user32_amode | + PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | + PSW32_MASK_PSTATE; +#endif + psw_kernel_bits = PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | + PSW_MASK_MCHECK | PSW_DEFAULT_KEY; + + if (MACHINE_HAS_MVCOS) { + printk("mvcos available.\n"); + memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess)); + } else { + printk("mvcos not available.\n"); + memcpy(&uaccess, &uaccess_pt, sizeof(uaccess)); + } +} + +/* + * Switch kernel/user addressing modes? + */ +static int __init early_parse_switch_amode(char *p) +{ + switch_amode = 1; + return 0; +} +early_param("switch_amode", early_parse_switch_amode); + +#else /* CONFIG_S390_SWITCH_AMODE */ +static inline void set_amode_and_uaccess(unsigned long user_amode, + unsigned long user32_amode) +{ +} +#endif /* CONFIG_S390_SWITCH_AMODE */ + +#ifdef CONFIG_S390_EXEC_PROTECT +unsigned int s390_noexec = 0; +EXPORT_SYMBOL_GPL(s390_noexec); + +/* + * Enable execute protection? + */ +static int __init early_parse_noexec(char *p) +{ + if (!strncmp(p, "off", 3)) + return 0; + switch_amode = 1; + s390_noexec = 1; + return 0; +} +early_param("noexec", early_parse_noexec); +#endif /* CONFIG_S390_EXEC_PROTECT */ + +static void setup_addressing_mode(void) +{ + if (s390_noexec) { + printk("S390 execute protection active, "); + set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY); + return; + } + if (switch_amode) { + printk("S390 address spaces switched, "); + set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY); + } +} + static void __init setup_lowcore(void) { @@ -402,19 +486,21 @@ setup_lowcore(void) lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; lc->restart_psw.addr = PSW_ADDR_AMODE | (unsigned long) restart_int_handler; - lc->external_new_psw.mask = PSW_KERNEL_BITS; + if (switch_amode) + lc->restart_psw.mask |= PSW_ASC_HOME; + lc->external_new_psw.mask = psw_kernel_bits; lc->external_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) ext_int_handler; - lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT; + lc->svc_new_psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT; lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call; - lc->program_new_psw.mask = PSW_KERNEL_BITS; + lc->program_new_psw.mask = psw_kernel_bits; lc->program_new_psw.addr = PSW_ADDR_AMODE | (unsigned long)pgm_check_handler; lc->mcck_new_psw.mask = - PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT; + psw_kernel_bits & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT; lc->mcck_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; - lc->io_new_psw.mask = PSW_KERNEL_BITS; + lc->io_new_psw.mask = psw_kernel_bits; lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; lc->ipl_device = S390_lowcore.ipl_device; lc->jiffy_timer = -1LL; @@ -439,7 +525,7 @@ setup_lowcore(void) static void __init setup_resources(void) { - struct resource *res; + struct resource *res, *sub_res; int i; code_resource.start = (unsigned long) &_text; @@ -464,8 +550,38 @@ setup_resources(void) res->start = memory_chunk[i].addr; res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; request_resource(&iomem_resource, res); - request_resource(res, &code_resource); - request_resource(res, &data_resource); + + if (code_resource.start >= res->start && + code_resource.start <= res->end && + code_resource.end > res->end) { + sub_res = alloc_bootmem_low(sizeof(struct resource)); + memcpy(sub_res, &code_resource, + sizeof(struct resource)); + sub_res->end = res->end; + code_resource.start = res->end + 1; + request_resource(res, sub_res); + } + + if (code_resource.start >= res->start && + code_resource.start <= res->end && + code_resource.end <= res->end) + request_resource(res, &code_resource); + + if (data_resource.start >= res->start && + data_resource.start <= res->end && + data_resource.end > res->end) { + sub_res = alloc_bootmem_low(sizeof(struct resource)); + memcpy(sub_res, &data_resource, + sizeof(struct resource)); + sub_res->end = res->end; + data_resource.start = res->end + 1; + request_resource(res, sub_res); + } + + if (data_resource.start >= res->start && + data_resource.start <= res->end && + data_resource.end <= res->end) + request_resource(res, &data_resource); } } @@ -495,16 +611,13 @@ static void __init setup_memory_end(void) } if (!memory_end) memory_end = memory_size; - if (real_size > memory_end) - printk("More memory detected than supported. Unused: %luk\n", - (real_size - memory_end) >> 10); } static void __init setup_memory(void) { unsigned long bootmap_size; - unsigned long start_pfn, end_pfn, init_pfn; + unsigned long start_pfn, end_pfn; int i; /* @@ -514,10 +627,6 @@ setup_memory(void) start_pfn = PFN_UP(__pa(&_end)); end_pfn = max_pfn = PFN_DOWN(memory_end); - /* Initialize storage key for kernel pages */ - for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++) - page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); - #ifdef CONFIG_BLK_DEV_INITRD /* * Move the initrd in case the bitmap of the bootmem allocater @@ -651,6 +760,7 @@ setup_arch(char **cmdline_p) parse_early_param(); setup_memory_end(); + setup_addressing_mode(); setup_memory(); setup_resources(); setup_lowcore(); @@ -694,6 +804,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) struct cpuinfo_S390 *cpuinfo; unsigned long n = (unsigned long) v - 1; + s390_adjust_jiffies(); preempt_disable(); if (!n) { seq_printf(m, "vendor_id : IBM/S390\n" diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 4c8a7954ef48..554f9cf7499c 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -119,7 +119,7 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs) /* Copy a 'clean' PSW mask to the user to avoid leaking information about whether PER is currently on. */ - user_sregs.regs.psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask); + user_sregs.regs.psw.mask = PSW_MASK_MERGE(psw_user_bits, regs->psw.mask); user_sregs.regs.psw.addr = regs->psw.addr; memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs)); memcpy(&user_sregs.regs.acrs, current->thread.acrs, diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index c0cd255fddbd..65b52320d145 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -22,23 +22,23 @@ #include #include - #include #include #include #include - #include #include #include #include - +#include +#include #include #include #include #include #include #include +#include extern volatile int __cpu_logical_map[]; @@ -53,12 +53,6 @@ cpumask_t cpu_possible_map = CPU_MASK_NONE; static struct task_struct *current_set[NR_CPUS]; -/* - * Reboot, halt and power_off routines for SMP. - */ -extern char vmhalt_cmd[]; -extern char vmpoff_cmd[]; - static void smp_ext_bitcall(int, ec_bit_sig); static void smp_ext_bitcall_others(ec_bit_sig); @@ -200,7 +194,7 @@ int smp_call_function_on(void (*func) (void *info), void *info, } EXPORT_SYMBOL(smp_call_function_on); -static inline void do_send_stop(void) +static void do_send_stop(void) { int cpu, rc; @@ -214,7 +208,7 @@ static inline void do_send_stop(void) } } -static inline void do_store_status(void) +static void do_store_status(void) { int cpu, rc; @@ -230,7 +224,7 @@ static inline void do_store_status(void) } } -static inline void do_wait_for_stop(void) +static void do_wait_for_stop(void) { int cpu; @@ -250,7 +244,7 @@ static inline void do_wait_for_stop(void) void smp_send_stop(void) { /* Disable all interrupts/machine checks */ - __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK); + __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK); /* write magic number to zero page (absolute 0) */ lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC; @@ -298,7 +292,7 @@ void machine_power_off_smp(void) * cpus are handled. */ -void do_ext_call_interrupt(__u16 code) +static void do_ext_call_interrupt(__u16 code) { unsigned long bits; @@ -385,7 +379,7 @@ struct ec_creg_mask_parms { /* * callback for setting/clearing control bits */ -void smp_ctl_bit_callback(void *info) { +static void smp_ctl_bit_callback(void *info) { struct ec_creg_mask_parms *pp = info; unsigned long cregs[16]; int i; @@ -458,17 +452,15 @@ __init smp_count_cpus(void) /* * Activate a secondary processor. */ -extern void init_cpu_timer(void); -extern void init_cpu_vtimer(void); - int __devinit start_secondary(void *cpuvoid) { /* Setup the cpu */ cpu_init(); preempt_disable(); - /* init per CPU timer */ + /* Enable TOD clock interrupts on the secondary cpu. */ init_cpu_timer(); #ifdef CONFIG_VIRT_TIMER + /* Enable cpu timer interrupts on the secondary cpu. */ init_cpu_vtimer(); #endif /* Enable pfault pseudo page faults on this cpu. */ @@ -542,7 +534,7 @@ smp_put_cpu(int cpu) spin_unlock_irqrestore(&smp_reserve_lock, flags); } -static inline int +static int cpu_stopped(int cpu) { __u32 status; diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index 0d14a4789bf2..2e5c65a1863e 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -11,11 +11,11 @@ #include #include -static inline unsigned long save_context_stack(struct stack_trace *trace, - unsigned int *skip, - unsigned long sp, - unsigned long low, - unsigned long high) +static unsigned long save_context_stack(struct stack_trace *trace, + unsigned int *skip, + unsigned long sp, + unsigned long low, + unsigned long high) { struct stack_frame *sf; struct pt_regs *regs; diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 6cceed4df73e..3b91f27ab202 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -37,11 +37,15 @@ #include #include #include +#include /* change this if you have some constant time drift */ #define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12) +/* The value of the TOD clock for 1.1.1970. */ +#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL + /* * Create a small time difference between the timer interrupts * on the different cpus to avoid lock contention. @@ -51,6 +55,7 @@ #define TICK_SIZE tick static ext_int_info_t ext_int_info_cc; +static ext_int_info_t ext_int_etr_cc; static u64 init_timer_cc; static u64 jiffies_timer_cc; static u64 xtime_cc; @@ -89,29 +94,21 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime) #define s390_do_profile() do { ; } while(0) #endif /* CONFIG_PROFILING */ - /* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick + * Advance the per cpu tick counter up to the time given with the + * "time" argument. The per cpu update consists of accounting + * the virtual cpu time, calling update_process_times and calling + * the profiling hook. If xtime is before time it is advanced as well. */ -void account_ticks(void) +void account_ticks(u64 time) { - __u64 tmp; __u32 ticks; + __u64 tmp; /* Calculate how many ticks have passed. */ - if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) { - /* - * We have to program the clock comparator even if - * no tick has passed. That happens if e.g. an i/o - * interrupt wakes up an idle processor that has - * switched off its hz timer. - */ - tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION; - asm volatile ("SCKC %0" : : "m" (tmp)); + if (time < S390_lowcore.jiffy_timer) return; - } - tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer; + tmp = time - S390_lowcore.jiffy_timer; if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than two ticks ? */ ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1; S390_lowcore.jiffy_timer += @@ -124,10 +121,6 @@ void account_ticks(void) S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY; } - /* set clock comparator for next tick */ - tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION; - asm volatile ("SCKC %0" : : "m" (tmp)); - #ifdef CONFIG_SMP /* * Do not rely on the boot cpu to do the calls to do_timer. @@ -173,7 +166,7 @@ int sysctl_hz_timer = 1; * Stop the HZ tick on the current CPU. * Only cpu_idle may call this function. */ -static inline void stop_hz_timer(void) +static void stop_hz_timer(void) { unsigned long flags; unsigned long seq, next; @@ -210,20 +203,21 @@ static inline void stop_hz_timer(void) if (timer >= jiffies_timer_cc) todval = timer; } - asm volatile ("SCKC %0" : : "m" (todval)); + set_clock_comparator(todval); } /* * Start the HZ tick on the current CPU. * Only cpu_idle may call this function. */ -static inline void start_hz_timer(void) +static void start_hz_timer(void) { BUG_ON(!in_interrupt()); if (!cpu_isset(smp_processor_id(), nohz_cpu_mask)) return; - account_ticks(); + account_ticks(get_clock()); + set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION); cpu_clear(smp_processor_id(), nohz_cpu_mask); } @@ -245,7 +239,7 @@ static struct notifier_block nohz_idle_nb = { .notifier_call = nohz_idle_notify, }; -void __init nohz_init(void) +static void __init nohz_init(void) { if (register_idle_notifier(&nohz_idle_nb)) panic("Couldn't register idle notifier"); @@ -254,24 +248,57 @@ void __init nohz_init(void) #endif /* - * Start the clock comparator on the current CPU. + * Set up per cpu jiffy timer and set the clock comparator. + */ +static void setup_jiffy_timer(void) +{ + /* Set up clock comparator to next jiffy. */ + S390_lowcore.jiffy_timer = + jiffies_timer_cc + (jiffies_64 + 1) * CLK_TICKS_PER_JIFFY; + set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION); +} + +/* + * Set up lowcore and control register of the current cpu to + * enable TOD clock and clock comparator interrupts. */ void init_cpu_timer(void) { - unsigned long cr0; - __u64 timer; + setup_jiffy_timer(); - timer = jiffies_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY; - S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY; - timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION; - asm volatile ("SCKC %0" : : "m" (timer)); - /* allow clock comparator timer interrupt */ - __ctl_store(cr0, 0, 0); - cr0 |= 0x800; - __ctl_load(cr0, 0, 0); + /* Enable clock comparator timer interrupt. */ + __ctl_set_bit(0,11); + + /* Always allow ETR external interrupts, even without an ETR. */ + __ctl_set_bit(0, 4); } -extern void vtime_init(void); +static void clock_comparator_interrupt(__u16 code) +{ + /* set clock comparator for next tick */ + set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION); +} + +static void etr_reset(void); +static void etr_init(void); +static void etr_ext_handler(__u16); + +/* + * Get the TOD clock running. + */ +static u64 __init reset_tod_clock(void) +{ + u64 time; + + etr_reset(); + if (store_clock(&time) == 0) + return time; + /* TOD clock not running. Set the clock to Unix Epoch. */ + if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0) + panic("TOD clock not operational."); + + return TOD_UNIX_EPOCH; +} static cycle_t read_tod_clock(void) { @@ -295,48 +322,31 @@ static struct clocksource clocksource_tod = { */ void __init time_init(void) { - __u64 set_time_cc; - int cc; - - /* kick the TOD clock */ - asm volatile( - " stck 0(%2)\n" - " ipm %0\n" - " srl %0,28" - : "=d" (cc), "=m" (init_timer_cc) - : "a" (&init_timer_cc) : "cc"); - switch (cc) { - case 0: /* clock in set state: all is fine */ - break; - case 1: /* clock in non-set state: FIXME */ - printk("time_init: TOD clock in non-set state\n"); - break; - case 2: /* clock in error state: FIXME */ - printk("time_init: TOD clock in error state\n"); - break; - case 3: /* clock in stopped or not-operational state: FIXME */ - printk("time_init: TOD clock stopped/non-operational\n"); - break; - } + init_timer_cc = reset_tod_clock(); + xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY; jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY; /* set xtime */ - xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY; - set_time_cc = init_timer_cc - 0x8126d60e46000000LL + - (0x3c26700LL*1000000*4096); - tod_to_timeval(set_time_cc, &xtime); + tod_to_timeval(init_timer_cc - TOD_UNIX_EPOCH, &xtime); set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); /* request the clock comparator external interrupt */ - if (register_early_external_interrupt(0x1004, NULL, + if (register_early_external_interrupt(0x1004, + clock_comparator_interrupt, &ext_int_info_cc) != 0) panic("Couldn't request external interrupt 0x1004"); if (clocksource_register(&clocksource_tod) != 0) panic("Could not register TOD clock source"); - init_cpu_timer(); + /* request the etr external interrupt */ + if (register_early_external_interrupt(0x1406, etr_ext_handler, + &ext_int_etr_cc) != 0) + panic("Couldn't request external interrupt 0x1406"); + + /* Enable TOD clock interrupts on the boot cpu. */ + init_cpu_timer(); #ifdef CONFIG_NO_IDLE_HZ nohz_init(); @@ -345,5 +355,1048 @@ void __init time_init(void) #ifdef CONFIG_VIRT_TIMER vtime_init(); #endif + etr_init(); } +/* + * External Time Reference (ETR) code. + */ +static int etr_port0_online; +static int etr_port1_online; + +static int __init early_parse_etr(char *p) +{ + if (strncmp(p, "off", 3) == 0) + etr_port0_online = etr_port1_online = 0; + else if (strncmp(p, "port0", 5) == 0) + etr_port0_online = 1; + else if (strncmp(p, "port1", 5) == 0) + etr_port1_online = 1; + else if (strncmp(p, "on", 2) == 0) + etr_port0_online = etr_port1_online = 1; + return 0; +} +early_param("etr", early_parse_etr); + +enum etr_event { + ETR_EVENT_PORT0_CHANGE, + ETR_EVENT_PORT1_CHANGE, + ETR_EVENT_PORT_ALERT, + ETR_EVENT_SYNC_CHECK, + ETR_EVENT_SWITCH_LOCAL, + ETR_EVENT_UPDATE, +}; + +enum etr_flags { + ETR_FLAG_ENOSYS, + ETR_FLAG_EACCES, + ETR_FLAG_STEAI, +}; + +/* + * Valid bit combinations of the eacr register are (x = don't care): + * e0 e1 dp p0 p1 ea es sl + * 0 0 x 0 0 0 0 0 initial, disabled state + * 0 0 x 0 1 1 0 0 port 1 online + * 0 0 x 1 0 1 0 0 port 0 online + * 0 0 x 1 1 1 0 0 both ports online + * 0 1 x 0 1 1 0 0 port 1 online and usable, ETR or PPS mode + * 0 1 x 0 1 1 0 1 port 1 online, usable and ETR mode + * 0 1 x 0 1 1 1 0 port 1 online, usable, PPS mode, in-sync + * 0 1 x 0 1 1 1 1 port 1 online, usable, ETR mode, in-sync + * 0 1 x 1 1 1 0 0 both ports online, port 1 usable + * 0 1 x 1 1 1 1 0 both ports online, port 1 usable, PPS mode, in-sync + * 0 1 x 1 1 1 1 1 both ports online, port 1 usable, ETR mode, in-sync + * 1 0 x 1 0 1 0 0 port 0 online and usable, ETR or PPS mode + * 1 0 x 1 0 1 0 1 port 0 online, usable and ETR mode + * 1 0 x 1 0 1 1 0 port 0 online, usable, PPS mode, in-sync + * 1 0 x 1 0 1 1 1 port 0 online, usable, ETR mode, in-sync + * 1 0 x 1 1 1 0 0 both ports online, port 0 usable + * 1 0 x 1 1 1 1 0 both ports online, port 0 usable, PPS mode, in-sync + * 1 0 x 1 1 1 1 1 both ports online, port 0 usable, ETR mode, in-sync + * 1 1 x 1 1 1 1 0 both ports online & usable, ETR, in-sync + * 1 1 x 1 1 1 1 1 both ports online & usable, ETR, in-sync + */ +static struct etr_eacr etr_eacr; +static u64 etr_tolec; /* time of last eacr update */ +static unsigned long etr_flags; +static struct etr_aib etr_port0; +static int etr_port0_uptodate; +static struct etr_aib etr_port1; +static int etr_port1_uptodate; +static unsigned long etr_events; +static struct timer_list etr_timer; +static struct tasklet_struct etr_tasklet; +static DEFINE_PER_CPU(atomic_t, etr_sync_word); + +static void etr_timeout(unsigned long dummy); +static void etr_tasklet_fn(unsigned long dummy); + +/* + * The etr get_clock function. It will write the current clock value + * to the clock pointer and return 0 if the clock is in sync with the + * external time source. If the clock mode is local it will return + * -ENOSYS and -EAGAIN if the clock is not in sync with the external + * reference. This function is what ETR is all about.. + */ +int get_sync_clock(unsigned long long *clock) +{ + atomic_t *sw_ptr; + unsigned int sw0, sw1; + + sw_ptr = &get_cpu_var(etr_sync_word); + sw0 = atomic_read(sw_ptr); + *clock = get_clock(); + sw1 = atomic_read(sw_ptr); + put_cpu_var(etr_sync_sync); + if (sw0 == sw1 && (sw0 & 0x80000000U)) + /* Success: time is in sync. */ + return 0; + if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) + return -ENOSYS; + if (test_bit(ETR_FLAG_EACCES, &etr_flags)) + return -EACCES; + return -EAGAIN; +} +EXPORT_SYMBOL(get_sync_clock); + +/* + * Make get_sync_clock return -EAGAIN. + */ +static void etr_disable_sync_clock(void *dummy) +{ + atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word); + /* + * Clear the in-sync bit 2^31. All get_sync_clock calls will + * fail until the sync bit is turned back on. In addition + * increase the "sequence" counter to avoid the race of an + * etr event and the complete recovery against get_sync_clock. + */ + atomic_clear_mask(0x80000000, sw_ptr); + atomic_inc(sw_ptr); +} + +/* + * Make get_sync_clock return 0 again. + * Needs to be called from a context disabled for preemption. + */ +static void etr_enable_sync_clock(void) +{ + atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word); + atomic_set_mask(0x80000000, sw_ptr); +} + +/* + * Reset ETR attachment. + */ +static void etr_reset(void) +{ + etr_eacr = (struct etr_eacr) { + .e0 = 0, .e1 = 0, ._pad0 = 4, .dp = 0, + .p0 = 0, .p1 = 0, ._pad1 = 0, .ea = 0, + .es = 0, .sl = 0 }; + if (etr_setr(&etr_eacr) == 0) + etr_tolec = get_clock(); + else { + set_bit(ETR_FLAG_ENOSYS, &etr_flags); + if (etr_port0_online || etr_port1_online) { + printk(KERN_WARNING "Running on non ETR capable " + "machine, only local mode available.\n"); + etr_port0_online = etr_port1_online = 0; + } + } +} + +static void etr_init(void) +{ + struct etr_aib aib; + + if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) + return; + /* Check if this machine has the steai instruction. */ + if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0) + set_bit(ETR_FLAG_STEAI, &etr_flags); + setup_timer(&etr_timer, etr_timeout, 0UL); + tasklet_init(&etr_tasklet, etr_tasklet_fn, 0); + if (!etr_port0_online && !etr_port1_online) + set_bit(ETR_FLAG_EACCES, &etr_flags); + if (etr_port0_online) { + set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); + } + if (etr_port1_online) { + set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); + } +} + +/* + * Two sorts of ETR machine checks. The architecture reads: + * "When a machine-check niterruption occurs and if a switch-to-local or + * ETR-sync-check interrupt request is pending but disabled, this pending + * disabled interruption request is indicated and is cleared". + * Which means that we can get etr_switch_to_local events from the machine + * check handler although the interruption condition is disabled. Lovely.. + */ + +/* + * Switch to local machine check. This is called when the last usable + * ETR port goes inactive. After switch to local the clock is not in sync. + */ +void etr_switch_to_local(void) +{ + if (!etr_eacr.sl) + return; + etr_disable_sync_clock(NULL); + set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events); + tasklet_hi_schedule(&etr_tasklet); +} + +/* + * ETR sync check machine check. This is called when the ETR OTE and the + * local clock OTE are farther apart than the ETR sync check tolerance. + * After a ETR sync check the clock is not in sync. The machine check + * is broadcasted to all cpus at the same time. + */ +void etr_sync_check(void) +{ + if (!etr_eacr.es) + return; + etr_disable_sync_clock(NULL); + set_bit(ETR_EVENT_SYNC_CHECK, &etr_events); + tasklet_hi_schedule(&etr_tasklet); +} + +/* + * ETR external interrupt. There are two causes: + * 1) port state change, check the usability of the port + * 2) port alert, one of the ETR-data-validity bits (v1-v2 bits of the + * sldr-status word) or ETR-data word 1 (edf1) or ETR-data word 3 (edf3) + * or ETR-data word 4 (edf4) has changed. + */ +static void etr_ext_handler(__u16 code) +{ + struct etr_interruption_parameter *intparm = + (struct etr_interruption_parameter *) &S390_lowcore.ext_params; + + if (intparm->pc0) + /* ETR port 0 state change. */ + set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); + if (intparm->pc1) + /* ETR port 1 state change. */ + set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); + if (intparm->eai) + /* + * ETR port alert on either port 0, 1 or both. + * Both ports are not up-to-date now. + */ + set_bit(ETR_EVENT_PORT_ALERT, &etr_events); + tasklet_hi_schedule(&etr_tasklet); +} + +static void etr_timeout(unsigned long dummy) +{ + set_bit(ETR_EVENT_UPDATE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); +} + +/* + * Check if the etr mode is pss. + */ +static inline int etr_mode_is_pps(struct etr_eacr eacr) +{ + return eacr.es && !eacr.sl; +} + +/* + * Check if the etr mode is etr. + */ +static inline int etr_mode_is_etr(struct etr_eacr eacr) +{ + return eacr.es && eacr.sl; +} + +/* + * Check if the port can be used for TOD synchronization. + * For PPS mode the port has to receive OTEs. For ETR mode + * the port has to receive OTEs, the ETR stepping bit has to + * be zero and the validity bits for data frame 1, 2, and 3 + * have to be 1. + */ +static int etr_port_valid(struct etr_aib *aib, int port) +{ + unsigned int psc; + + /* Check that this port is receiving OTEs. */ + if (aib->tsp == 0) + return 0; + + psc = port ? aib->esw.psc1 : aib->esw.psc0; + if (psc == etr_lpsc_pps_mode) + return 1; + if (psc == etr_lpsc_operational_step) + return !aib->esw.y && aib->slsw.v1 && + aib->slsw.v2 && aib->slsw.v3; + return 0; +} + +/* + * Check if two ports are on the same network. + */ +static int etr_compare_network(struct etr_aib *aib1, struct etr_aib *aib2) +{ + // FIXME: any other fields we have to compare? + return aib1->edf1.net_id == aib2->edf1.net_id; +} + +/* + * Wrapper for etr_stei that converts physical port states + * to logical port states to be consistent with the output + * of stetr (see etr_psc vs. etr_lpsc). + */ +static void etr_steai_cv(struct etr_aib *aib, unsigned int func) +{ + BUG_ON(etr_steai(aib, func) != 0); + /* Convert port state to logical port state. */ + if (aib->esw.psc0 == 1) + aib->esw.psc0 = 2; + else if (aib->esw.psc0 == 0 && aib->esw.p == 0) + aib->esw.psc0 = 1; + if (aib->esw.psc1 == 1) + aib->esw.psc1 = 2; + else if (aib->esw.psc1 == 0 && aib->esw.p == 1) + aib->esw.psc1 = 1; +} + +/* + * Check if the aib a2 is still connected to the same attachment as + * aib a1, the etv values differ by one and a2 is valid. + */ +static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p) +{ + int state_a1, state_a2; + + /* Paranoia check: e0/e1 should better be the same. */ + if (a1->esw.eacr.e0 != a2->esw.eacr.e0 || + a1->esw.eacr.e1 != a2->esw.eacr.e1) + return 0; + + /* Still connected to the same etr ? */ + state_a1 = p ? a1->esw.psc1 : a1->esw.psc0; + state_a2 = p ? a2->esw.psc1 : a2->esw.psc0; + if (state_a1 == etr_lpsc_operational_step) { + if (state_a2 != etr_lpsc_operational_step || + a1->edf1.net_id != a2->edf1.net_id || + a1->edf1.etr_id != a2->edf1.etr_id || + a1->edf1.etr_pn != a2->edf1.etr_pn) + return 0; + } else if (state_a2 != etr_lpsc_pps_mode) + return 0; + + /* The ETV value of a2 needs to be ETV of a1 + 1. */ + if (a1->edf2.etv + 1 != a2->edf2.etv) + return 0; + + if (!etr_port_valid(a2, p)) + return 0; + + return 1; +} + +/* + * The time is "clock". xtime is what we think the time is. + * Adjust the value by a multiple of jiffies and add the delta to ntp. + * "delay" is an approximation how long the synchronization took. If + * the time correction is positive, then "delay" is subtracted from + * the time difference and only the remaining part is passed to ntp. + */ +static void etr_adjust_time(unsigned long long clock, unsigned long long delay) +{ + unsigned long long delta, ticks; + struct timex adjust; + + /* + * We don't have to take the xtime lock because the cpu + * executing etr_adjust_time is running disabled in + * tasklet context and all other cpus are looping in + * etr_sync_cpu_start. + */ + if (clock > xtime_cc) { + /* It is later than we thought. */ + delta = ticks = clock - xtime_cc; + delta = ticks = (delta < delay) ? 0 : delta - delay; + delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); + init_timer_cc = init_timer_cc + delta; + jiffies_timer_cc = jiffies_timer_cc + delta; + xtime_cc = xtime_cc + delta; + adjust.offset = ticks * (1000000 / HZ); + } else { + /* It is earlier than we thought. */ + delta = ticks = xtime_cc - clock; + delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); + init_timer_cc = init_timer_cc - delta; + jiffies_timer_cc = jiffies_timer_cc - delta; + xtime_cc = xtime_cc - delta; + adjust.offset = -ticks * (1000000 / HZ); + } + if (adjust.offset != 0) { + printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n", + adjust.offset); + adjust.modes = ADJ_OFFSET_SINGLESHOT; + do_adjtimex(&adjust); + } +} + +static void etr_sync_cpu_start(void *dummy) +{ + int *in_sync = dummy; + + etr_enable_sync_clock(); + /* + * This looks like a busy wait loop but it isn't. etr_sync_cpus + * is called on all other cpus while the TOD clocks is stopped. + * __udelay will stop the cpu on an enabled wait psw until the + * TOD is running again. + */ + while (*in_sync == 0) + __udelay(1); + if (*in_sync != 1) + /* Didn't work. Clear per-cpu in sync bit again. */ + etr_disable_sync_clock(NULL); + /* + * This round of TOD syncing is done. Set the clock comparator + * to the next tick and let the processor continue. + */ + setup_jiffy_timer(); +} + +static void etr_sync_cpu_end(void *dummy) +{ +} + +/* + * Sync the TOD clock using the port refered to by aibp. This port + * has to be enabled and the other port has to be disabled. The + * last eacr update has to be more than 1.6 seconds in the past. + */ +static int etr_sync_clock(struct etr_aib *aib, int port) +{ + struct etr_aib *sync_port; + unsigned long long clock, delay; + int in_sync, follows; + int rc; + + /* Check if the current aib is adjacent to the sync port aib. */ + sync_port = (port == 0) ? &etr_port0 : &etr_port1; + follows = etr_aib_follows(sync_port, aib, port); + memcpy(sync_port, aib, sizeof(*aib)); + if (!follows) + return -EAGAIN; + + /* + * Catch all other cpus and make them wait until we have + * successfully synced the clock. smp_call_function will + * return after all other cpus are in etr_sync_cpu_start. + */ + in_sync = 0; + preempt_disable(); + smp_call_function(etr_sync_cpu_start,&in_sync,0,0); + local_irq_disable(); + etr_enable_sync_clock(); + + /* Set clock to next OTE. */ + __ctl_set_bit(14, 21); + __ctl_set_bit(0, 29); + clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32; + if (set_clock(clock) == 0) { + __udelay(1); /* Wait for the clock to start. */ + __ctl_clear_bit(0, 29); + __ctl_clear_bit(14, 21); + etr_stetr(aib); + /* Adjust Linux timing variables. */ + delay = (unsigned long long) + (aib->edf2.etv - sync_port->edf2.etv) << 32; + etr_adjust_time(clock, delay); + setup_jiffy_timer(); + /* Verify that the clock is properly set. */ + if (!etr_aib_follows(sync_port, aib, port)) { + /* Didn't work. */ + etr_disable_sync_clock(NULL); + in_sync = -EAGAIN; + rc = -EAGAIN; + } else { + in_sync = 1; + rc = 0; + } + } else { + /* Could not set the clock ?!? */ + __ctl_clear_bit(0, 29); + __ctl_clear_bit(14, 21); + etr_disable_sync_clock(NULL); + in_sync = -EAGAIN; + rc = -EAGAIN; + } + local_irq_enable(); + smp_call_function(etr_sync_cpu_end,NULL,0,0); + preempt_enable(); + return rc; +} + +/* + * Handle the immediate effects of the different events. + * The port change event is used for online/offline changes. + */ +static struct etr_eacr etr_handle_events(struct etr_eacr eacr) +{ + if (test_and_clear_bit(ETR_EVENT_SYNC_CHECK, &etr_events)) + eacr.es = 0; + if (test_and_clear_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events)) + eacr.es = eacr.sl = 0; + if (test_and_clear_bit(ETR_EVENT_PORT_ALERT, &etr_events)) + etr_port0_uptodate = etr_port1_uptodate = 0; + + if (test_and_clear_bit(ETR_EVENT_PORT0_CHANGE, &etr_events)) { + if (eacr.e0) + /* + * Port change of an enabled port. We have to + * assume that this can have caused an stepping + * port switch. + */ + etr_tolec = get_clock(); + eacr.p0 = etr_port0_online; + if (!eacr.p0) + eacr.e0 = 0; + etr_port0_uptodate = 0; + } + if (test_and_clear_bit(ETR_EVENT_PORT1_CHANGE, &etr_events)) { + if (eacr.e1) + /* + * Port change of an enabled port. We have to + * assume that this can have caused an stepping + * port switch. + */ + etr_tolec = get_clock(); + eacr.p1 = etr_port1_online; + if (!eacr.p1) + eacr.e1 = 0; + etr_port1_uptodate = 0; + } + clear_bit(ETR_EVENT_UPDATE, &etr_events); + return eacr; +} + +/* + * Set up a timer that expires after the etr_tolec + 1.6 seconds if + * one of the ports needs an update. + */ +static void etr_set_tolec_timeout(unsigned long long now) +{ + unsigned long micros; + + if ((!etr_eacr.p0 || etr_port0_uptodate) && + (!etr_eacr.p1 || etr_port1_uptodate)) + return; + micros = (now > etr_tolec) ? ((now - etr_tolec) >> 12) : 0; + micros = (micros > 1600000) ? 0 : 1600000 - micros; + mod_timer(&etr_timer, jiffies + (micros * HZ) / 1000000 + 1); +} + +/* + * Set up a time that expires after 1/2 second. + */ +static void etr_set_sync_timeout(void) +{ + mod_timer(&etr_timer, jiffies + HZ/2); +} + +/* + * Update the aib information for one or both ports. + */ +static struct etr_eacr etr_handle_update(struct etr_aib *aib, + struct etr_eacr eacr) +{ + /* With both ports disabled the aib information is useless. */ + if (!eacr.e0 && !eacr.e1) + return eacr; + + /* Update port0 or port1 with aib stored in etr_tasklet_fn. */ + if (aib->esw.q == 0) { + /* Information for port 0 stored. */ + if (eacr.p0 && !etr_port0_uptodate) { + etr_port0 = *aib; + if (etr_port0_online) + etr_port0_uptodate = 1; + } + } else { + /* Information for port 1 stored. */ + if (eacr.p1 && !etr_port1_uptodate) { + etr_port1 = *aib; + if (etr_port0_online) + etr_port1_uptodate = 1; + } + } + + /* + * Do not try to get the alternate port aib if the clock + * is not in sync yet. + */ + if (!eacr.es) + return eacr; + + /* + * If steai is available we can get the information about + * the other port immediately. If only stetr is available the + * data-port bit toggle has to be used. + */ + if (test_bit(ETR_FLAG_STEAI, &etr_flags)) { + if (eacr.p0 && !etr_port0_uptodate) { + etr_steai_cv(&etr_port0, ETR_STEAI_PORT_0); + etr_port0_uptodate = 1; + } + if (eacr.p1 && !etr_port1_uptodate) { + etr_steai_cv(&etr_port1, ETR_STEAI_PORT_1); + etr_port1_uptodate = 1; + } + } else { + /* + * One port was updated above, if the other + * port is not uptodate toggle dp bit. + */ + if ((eacr.p0 && !etr_port0_uptodate) || + (eacr.p1 && !etr_port1_uptodate)) + eacr.dp ^= 1; + else + eacr.dp = 0; + } + return eacr; +} + +/* + * Write new etr control register if it differs from the current one. + * Return 1 if etr_tolec has been updated as well. + */ +static void etr_update_eacr(struct etr_eacr eacr) +{ + int dp_changed; + + if (memcmp(&etr_eacr, &eacr, sizeof(eacr)) == 0) + /* No change, return. */ + return; + /* + * The disable of an active port of the change of the data port + * bit can/will cause a change in the data port. + */ + dp_changed = etr_eacr.e0 > eacr.e0 || etr_eacr.e1 > eacr.e1 || + (etr_eacr.dp ^ eacr.dp) != 0; + etr_eacr = eacr; + etr_setr(&etr_eacr); + if (dp_changed) + etr_tolec = get_clock(); +} + +/* + * ETR tasklet. In this function you'll find the main logic. In + * particular this is the only function that calls etr_update_eacr(), + * it "controls" the etr control register. + */ +static void etr_tasklet_fn(unsigned long dummy) +{ + unsigned long long now; + struct etr_eacr eacr; + struct etr_aib aib; + int sync_port; + + /* Create working copy of etr_eacr. */ + eacr = etr_eacr; + + /* Check for the different events and their immediate effects. */ + eacr = etr_handle_events(eacr); + + /* Check if ETR is supposed to be active. */ + eacr.ea = eacr.p0 || eacr.p1; + if (!eacr.ea) { + /* Both ports offline. Reset everything. */ + eacr.dp = eacr.es = eacr.sl = 0; + on_each_cpu(etr_disable_sync_clock, NULL, 0, 1); + del_timer_sync(&etr_timer); + etr_update_eacr(eacr); + set_bit(ETR_FLAG_EACCES, &etr_flags); + return; + } + + /* Store aib to get the current ETR status word. */ + BUG_ON(etr_stetr(&aib) != 0); + etr_port0.esw = etr_port1.esw = aib.esw; /* Copy status word. */ + now = get_clock(); + + /* + * Update the port information if the last stepping port change + * or data port change is older than 1.6 seconds. + */ + if (now >= etr_tolec + (1600000 << 12)) + eacr = etr_handle_update(&aib, eacr); + + /* + * Select ports to enable. The prefered synchronization mode is PPS. + * If a port can be enabled depends on a number of things: + * 1) The port needs to be online and uptodate. A port is not + * disabled just because it is not uptodate, but it is only + * enabled if it is uptodate. + * 2) The port needs to have the same mode (pps / etr). + * 3) The port needs to be usable -> etr_port_valid() == 1 + * 4) To enable the second port the clock needs to be in sync. + * 5) If both ports are useable and are ETR ports, the network id + * has to be the same. + * The eacr.sl bit is used to indicate etr mode vs. pps mode. + */ + if (eacr.p0 && aib.esw.psc0 == etr_lpsc_pps_mode) { + eacr.sl = 0; + eacr.e0 = 1; + if (!etr_mode_is_pps(etr_eacr)) + eacr.es = 0; + if (!eacr.es || !eacr.p1 || aib.esw.psc1 != etr_lpsc_pps_mode) + eacr.e1 = 0; + // FIXME: uptodate checks ? + else if (etr_port0_uptodate && etr_port1_uptodate) + eacr.e1 = 1; + sync_port = (etr_port0_uptodate && + etr_port_valid(&etr_port0, 0)) ? 0 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); + } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_pps_mode) { + eacr.sl = 0; + eacr.e0 = 0; + eacr.e1 = 1; + if (!etr_mode_is_pps(etr_eacr)) + eacr.es = 0; + sync_port = (etr_port1_uptodate && + etr_port_valid(&etr_port1, 1)) ? 1 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); + } else if (eacr.p0 && aib.esw.psc0 == etr_lpsc_operational_step) { + eacr.sl = 1; + eacr.e0 = 1; + if (!etr_mode_is_etr(etr_eacr)) + eacr.es = 0; + if (!eacr.es || !eacr.p1 || + aib.esw.psc1 != etr_lpsc_operational_alt) + eacr.e1 = 0; + else if (etr_port0_uptodate && etr_port1_uptodate && + etr_compare_network(&etr_port0, &etr_port1)) + eacr.e1 = 1; + sync_port = (etr_port0_uptodate && + etr_port_valid(&etr_port0, 0)) ? 0 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); + } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_operational_step) { + eacr.sl = 1; + eacr.e0 = 0; + eacr.e1 = 1; + if (!etr_mode_is_etr(etr_eacr)) + eacr.es = 0; + sync_port = (etr_port1_uptodate && + etr_port_valid(&etr_port1, 1)) ? 1 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); + } else { + /* Both ports not usable. */ + eacr.es = eacr.sl = 0; + sync_port = -1; + set_bit(ETR_FLAG_EACCES, &etr_flags); + } + + /* + * If the clock is in sync just update the eacr and return. + * If there is no valid sync port wait for a port update. + */ + if (eacr.es || sync_port < 0) { + etr_update_eacr(eacr); + etr_set_tolec_timeout(now); + return; + } + + /* + * Prepare control register for clock syncing + * (reset data port bit, set sync check control. + */ + eacr.dp = 0; + eacr.es = 1; + + /* + * Update eacr and try to synchronize the clock. If the update + * of eacr caused a stepping port switch (or if we have to + * assume that a stepping port switch has occured) or the + * clock syncing failed, reset the sync check control bit + * and set up a timer to try again after 0.5 seconds + */ + etr_update_eacr(eacr); + if (now < etr_tolec + (1600000 << 12) || + etr_sync_clock(&aib, sync_port) != 0) { + /* Sync failed. Try again in 1/2 second. */ + eacr.es = 0; + etr_update_eacr(eacr); + etr_set_sync_timeout(); + } else + etr_set_tolec_timeout(now); +} + +/* + * Sysfs interface functions + */ +static struct sysdev_class etr_sysclass = { + set_kset_name("etr") +}; + +static struct sys_device etr_port0_dev = { + .id = 0, + .cls = &etr_sysclass, +}; + +static struct sys_device etr_port1_dev = { + .id = 1, + .cls = &etr_sysclass, +}; + +/* + * ETR class attributes + */ +static ssize_t etr_stepping_port_show(struct sysdev_class *class, char *buf) +{ + return sprintf(buf, "%i\n", etr_port0.esw.p); +} + +static SYSDEV_CLASS_ATTR(stepping_port, 0400, etr_stepping_port_show, NULL); + +static ssize_t etr_stepping_mode_show(struct sysdev_class *class, char *buf) +{ + char *mode_str; + + if (etr_mode_is_pps(etr_eacr)) + mode_str = "pps"; + else if (etr_mode_is_etr(etr_eacr)) + mode_str = "etr"; + else + mode_str = "local"; + return sprintf(buf, "%s\n", mode_str); +} + +static SYSDEV_CLASS_ATTR(stepping_mode, 0400, etr_stepping_mode_show, NULL); + +/* + * ETR port attributes + */ +static inline struct etr_aib *etr_aib_from_dev(struct sys_device *dev) +{ + if (dev == &etr_port0_dev) + return etr_port0_online ? &etr_port0 : NULL; + else + return etr_port1_online ? &etr_port1 : NULL; +} + +static ssize_t etr_online_show(struct sys_device *dev, char *buf) +{ + unsigned int online; + + online = (dev == &etr_port0_dev) ? etr_port0_online : etr_port1_online; + return sprintf(buf, "%i\n", online); +} + +static ssize_t etr_online_store(struct sys_device *dev, + const char *buf, size_t count) +{ + unsigned int value; + + value = simple_strtoul(buf, NULL, 0); + if (value != 0 && value != 1) + return -EINVAL; + if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) + return -ENOSYS; + if (dev == &etr_port0_dev) { + if (etr_port0_online == value) + return count; /* Nothing to do. */ + etr_port0_online = value; + set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); + } else { + if (etr_port1_online == value) + return count; /* Nothing to do. */ + etr_port1_online = value; + set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); + } + return count; +} + +static SYSDEV_ATTR(online, 0600, etr_online_show, etr_online_store); + +static ssize_t etr_stepping_control_show(struct sys_device *dev, char *buf) +{ + return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ? + etr_eacr.e0 : etr_eacr.e1); +} + +static SYSDEV_ATTR(stepping_control, 0400, etr_stepping_control_show, NULL); + +static ssize_t etr_mode_code_show(struct sys_device *dev, char *buf) +{ + if (!etr_port0_online && !etr_port1_online) + /* Status word is not uptodate if both ports are offline. */ + return -ENODATA; + return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ? + etr_port0.esw.psc0 : etr_port0.esw.psc1); +} + +static SYSDEV_ATTR(state_code, 0400, etr_mode_code_show, NULL); + +static ssize_t etr_untuned_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v1) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf1.u); +} + +static SYSDEV_ATTR(untuned, 0400, etr_untuned_show, NULL); + +static ssize_t etr_network_id_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v1) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf1.net_id); +} + +static SYSDEV_ATTR(network, 0400, etr_network_id_show, NULL); + +static ssize_t etr_id_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v1) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf1.etr_id); +} + +static SYSDEV_ATTR(id, 0400, etr_id_show, NULL); + +static ssize_t etr_port_number_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v1) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf1.etr_pn); +} + +static SYSDEV_ATTR(port, 0400, etr_port_number_show, NULL); + +static ssize_t etr_coupled_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v3) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf3.c); +} + +static SYSDEV_ATTR(coupled, 0400, etr_coupled_show, NULL); + +static ssize_t etr_local_time_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v3) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf3.blto); +} + +static SYSDEV_ATTR(local_time, 0400, etr_local_time_show, NULL); + +static ssize_t etr_utc_offset_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v3) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf3.buo); +} + +static SYSDEV_ATTR(utc_offset, 0400, etr_utc_offset_show, NULL); + +static struct sysdev_attribute *etr_port_attributes[] = { + &attr_online, + &attr_stepping_control, + &attr_state_code, + &attr_untuned, + &attr_network, + &attr_id, + &attr_port, + &attr_coupled, + &attr_local_time, + &attr_utc_offset, + NULL +}; + +static int __init etr_register_port(struct sys_device *dev) +{ + struct sysdev_attribute **attr; + int rc; + + rc = sysdev_register(dev); + if (rc) + goto out; + for (attr = etr_port_attributes; *attr; attr++) { + rc = sysdev_create_file(dev, *attr); + if (rc) + goto out_unreg; + } + return 0; +out_unreg: + for (; attr >= etr_port_attributes; attr--) + sysdev_remove_file(dev, *attr); + sysdev_unregister(dev); +out: + return rc; +} + +static void __init etr_unregister_port(struct sys_device *dev) +{ + struct sysdev_attribute **attr; + + for (attr = etr_port_attributes; *attr; attr++) + sysdev_remove_file(dev, *attr); + sysdev_unregister(dev); +} + +static int __init etr_init_sysfs(void) +{ + int rc; + + rc = sysdev_class_register(&etr_sysclass); + if (rc) + goto out; + rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_port); + if (rc) + goto out_unreg_class; + rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_mode); + if (rc) + goto out_remove_stepping_port; + rc = etr_register_port(&etr_port0_dev); + if (rc) + goto out_remove_stepping_mode; + rc = etr_register_port(&etr_port1_dev); + if (rc) + goto out_remove_port0; + return 0; + +out_remove_port0: + etr_unregister_port(&etr_port0_dev); +out_remove_stepping_mode: + sysdev_class_remove_file(&etr_sysclass, &attr_stepping_mode); +out_remove_stepping_port: + sysdev_class_remove_file(&etr_sysclass, &attr_stepping_port); +out_unreg_class: + sysdev_class_unregister(&etr_sysclass); +out: + return rc; +} + +device_initcall(etr_init_sysfs); diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 3cbb0dcf1f1d..f0e5a320e2ec 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -283,7 +283,7 @@ char *task_show_regs(struct task_struct *task, char *buffer) return buffer; } -DEFINE_SPINLOCK(die_lock); +static DEFINE_SPINLOCK(die_lock); void die(const char * str, struct pt_regs * regs, long err) { @@ -364,8 +364,7 @@ void __kprobes do_single_step(struct pt_regs *regs) force_sig(SIGTRAP, current); } -asmlinkage void -default_trap_handler(struct pt_regs * regs, long interruption_code) +static void default_trap_handler(struct pt_regs * regs, long interruption_code) { if (regs->psw.mask & PSW_MASK_PSTATE) { local_irq_enable(); @@ -376,7 +375,7 @@ default_trap_handler(struct pt_regs * regs, long interruption_code) } #define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \ -asmlinkage void name(struct pt_regs * regs, long interruption_code) \ +static void name(struct pt_regs * regs, long interruption_code) \ { \ siginfo_t info; \ info.si_signo = signr; \ @@ -442,7 +441,7 @@ do_fp_trap(struct pt_regs *regs, void __user *location, "floating point exception", regs, &si); } -asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) +static void illegal_op(struct pt_regs * regs, long interruption_code) { siginfo_t info; __u8 opcode[6]; @@ -491,8 +490,15 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) #endif } else signal = SIGILL; - } else - signal = SIGILL; + } else { + /* + * If we get an illegal op in kernel mode, send it through the + * kprobes notifier. If kprobes doesn't pick it up, SIGILL + */ + if (notify_die(DIE_BPT, "bpt", regs, interruption_code, + 3, SIGTRAP) != NOTIFY_STOP) + signal = SIGILL; + } #ifdef CONFIG_MATHEMU if (signal == SIGFPE) @@ -585,7 +591,7 @@ DO_ERROR_INFO(SIGILL, "specification exception", specification_exception, ILL_ILLOPN, get_check_address(regs)); #endif -asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) +static void data_exception(struct pt_regs * regs, long interruption_code) { __u16 __user *location; int signal = 0; @@ -675,7 +681,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) } } -asmlinkage void space_switch_exception(struct pt_regs * regs, long int_code) +static void space_switch_exception(struct pt_regs * regs, long int_code) { siginfo_t info; diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index fe0f2e97ba7b..a48907392522 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -31,19 +31,20 @@ SECTIONS _etext = .; /* End of text section */ - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; - RODATA #ifdef CONFIG_SHARED_KERNEL . = ALIGN(1048576); /* VM shared segments are 1MB aligned */ - - _eshared = .; /* End of shareable data */ #endif + . = ALIGN(4096); + _eshared = .; /* End of shareable data */ + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + .data : { /* Data */ *(.data) CONSTRUCTORS diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 21baaf5496d6..9d5b02801b46 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -25,7 +25,7 @@ #include static ext_int_info_t ext_int_info_timer; -DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); +static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); #ifdef CONFIG_VIRT_CPU_ACCOUNTING /* @@ -524,16 +524,15 @@ EXPORT_SYMBOL(del_virt_timer); void init_cpu_vtimer(void) { struct vtimer_queue *vt_list; - unsigned long cr0; /* kick the virtual timer */ S390_lowcore.exit_timer = VTIMER_MAX_SLICE; S390_lowcore.last_update_timer = VTIMER_MAX_SLICE; asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer)); asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock)); - __ctl_store(cr0, 0, 0); - cr0 |= 0x400; - __ctl_load(cr0, 0, 0); + + /* enable cpu timer interrupts */ + __ctl_set_bit(0,10); vt_list = &per_cpu(virt_cpu_timer, smp_processor_id()); INIT_LIST_HEAD(&vt_list->list); @@ -572,6 +571,7 @@ void __init vtime_init(void) if (register_idle_notifier(&vtimer_idle_nb)) panic("Couldn't register idle notifier"); + /* Enable cpu timer interrupts on the boot cpu. */ init_cpu_vtimer(); } diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index b5f94cf3bde8..7a44fed21b35 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile @@ -4,7 +4,7 @@ EXTRA_AFLAGS := -traditional -lib-y += delay.o string.o uaccess_std.o uaccess_pt.o +lib-y += delay.o string.o uaccess_std.o uaccess_pt.o qrnnd.o lib-$(CONFIG_32BIT) += div64.o lib-$(CONFIG_64BIT) += uaccess_mvcos.o lib-$(CONFIG_SMP) += spinlock.o diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index 027c4742a001..02854449b74b 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -1,5 +1,5 @@ /* - * arch/s390/kernel/delay.c + * arch/s390/lib/delay.c * Precise Delay Loops for S390 * * S390 version @@ -13,10 +13,8 @@ #include #include - -#ifdef CONFIG_SMP -#include -#endif +#include +#include void __delay(unsigned long loops) { @@ -31,17 +29,39 @@ void __delay(unsigned long loops) } /* - * Waits for 'usecs' microseconds using the tod clock, giving up the time slice - * of the virtual PU inbetween to avoid congestion. + * Waits for 'usecs' microseconds using the TOD clock comparator. */ void __udelay(unsigned long usecs) { - uint64_t start_cc; + u64 end, time, jiffy_timer = 0; + unsigned long flags, cr0, mask, dummy; - if (usecs == 0) - return; - start_cc = get_clock(); - do { - cpu_relax(); - } while (((get_clock() - start_cc)/4096) < usecs); + local_irq_save(flags); + if (raw_irqs_disabled_flags(flags)) { + jiffy_timer = S390_lowcore.jiffy_timer; + S390_lowcore.jiffy_timer = -1ULL - (4096 << 12); + __ctl_store(cr0, 0, 0); + dummy = (cr0 & 0xffff00e0) | 0x00000800; + __ctl_load(dummy , 0, 0); + mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT; + } else + mask = psw_kernel_bits | PSW_MASK_WAIT | + PSW_MASK_EXT | PSW_MASK_IO; + + end = get_clock() + ((u64) usecs << 12); + do { + time = end < S390_lowcore.jiffy_timer ? + end : S390_lowcore.jiffy_timer; + set_clock_comparator(time); + trace_hardirqs_on(); + __load_psw_mask(mask); + local_irq_disable(); + } while (get_clock() < end); + + if (raw_irqs_disabled_flags(flags)) { + __ctl_load(cr0, 0, 0); + S390_lowcore.jiffy_timer = jiffy_timer; + } + set_clock_comparator(S390_lowcore.jiffy_timer); + local_irq_restore(flags); } diff --git a/arch/s390/lib/qrnnd.S b/arch/s390/lib/qrnnd.S new file mode 100644 index 000000000000..eb1df632e749 --- /dev/null +++ b/arch/s390/lib/qrnnd.S @@ -0,0 +1,77 @@ +# S/390 __udiv_qrnnd + +# r2 : &__r +# r3 : upper half of 64 bit word n +# r4 : lower half of 64 bit word n +# r5 : divisor d +# the reminder r of the division is to be stored to &__r and +# the quotient q is to be returned + + .text + .globl __udiv_qrnnd +__udiv_qrnnd: + st %r2,24(%r15) # store pointer to reminder for later + lr %r0,%r3 # reload n + lr %r1,%r4 + ltr %r2,%r5 # reload and test divisor + jp 5f + # divisor >= 0x80000000 + srdl %r0,2 # n/4 + srl %r2,1 # d/2 + slr %r1,%r2 # special case if last bit of d is set + brc 3,0f # (n/4) div (n/2) can overflow by 1 + ahi %r0,-1 # trick: subtract n/2, then divide +0: dr %r0,%r2 # signed division + ahi %r1,1 # trick part 2: add 1 to the quotient + # now (n >> 2) = (d >> 1) * %r1 + %r0 + lhi %r3,1 + nr %r3,%r1 # test last bit of q + jz 1f + alr %r0,%r2 # add (d>>1) to r +1: srl %r1,1 # q >>= 1 + # now (n >> 2) = (d&-2) * %r1 + %r0 + lhi %r3,1 + nr %r3,%r5 # test last bit of d + jz 2f + slr %r0,%r1 # r -= q + brc 3,2f # borrow ? + alr %r0,%r5 # r += d + ahi %r1,-1 +2: # now (n >> 2) = d * %r1 + %r0 + alr %r1,%r1 # q <<= 1 + alr %r0,%r0 # r <<= 1 + brc 12,3f # overflow on r ? + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +3: lhi %r3,2 + nr %r3,%r4 # test next to last bit of n + jz 4f + ahi %r0,1 # r += 1 +4: clr %r0,%r5 # r >= d ? + jl 6f + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 + # now (n >> 1) = d * %r1 + %r0 + j 6f +5: # divisor < 0x80000000 + srdl %r0,1 + dr %r0,%r2 # signed division + # now (n >> 1) = d * %r1 + %r0 +6: alr %r1,%r1 # q <<= 1 + alr %r0,%r0 # r <<= 1 + brc 12,7f # overflow on r ? + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +7: lhi %r3,1 + nr %r3,%r4 # isolate last bit of n + alr %r0,%r3 # r += (n & 1) + clr %r0,%r5 # r >= d ? + jl 8f + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +8: # now n = d * %r1 + %r0 + l %r2,24(%r15) + st %r0,0(%r2) + lr %r2,%r1 + br %r14 + .end __udiv_qrnnd diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h new file mode 100644 index 000000000000..126011df14f1 --- /dev/null +++ b/arch/s390/lib/uaccess.h @@ -0,0 +1,23 @@ +/* + * arch/s390/uaccess.h + * + * Copyright IBM Corp. 2007 + * + */ + +#ifndef __ARCH_S390_LIB_UACCESS_H +#define __ARCH_S390_LIB_UACCESS_H + +extern size_t copy_from_user_std(size_t, const void __user *, void *); +extern size_t copy_to_user_std(size_t, void __user *, const void *); +extern size_t strnlen_user_std(size_t, const char __user *); +extern size_t strncpy_from_user_std(size_t, const char __user *, char *); +extern int futex_atomic_cmpxchg_std(int __user *, int, int); +extern int futex_atomic_op_std(int, int __user *, int, int *); + +extern size_t copy_from_user_pt(size_t, const void __user *, void *); +extern size_t copy_to_user_pt(size_t, void __user *, const void *); +extern int futex_atomic_op_pt(int, int __user *, int, int *); +extern int futex_atomic_cmpxchg_pt(int __user *, int, int); + +#endif /* __ARCH_S390_LIB_UACCESS_H */ diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c index f9a23d57eb79..6d8772339d76 100644 --- a/arch/s390/lib/uaccess_mvcos.c +++ b/arch/s390/lib/uaccess_mvcos.c @@ -12,6 +12,7 @@ #include #include #include +#include "uaccess.h" #ifndef __s390x__ #define AHI "ahi" @@ -27,10 +28,7 @@ #define SLR "slgr" #endif -extern size_t copy_from_user_std(size_t, const void __user *, void *); -extern size_t copy_to_user_std(size_t, void __user *, const void *); - -size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) +static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) { register unsigned long reg0 asm("0") = 0x81UL; unsigned long tmp1, tmp2; @@ -69,14 +67,14 @@ size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) return size; } -size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x) +static size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x) { if (size <= 256) return copy_from_user_std(size, ptr, x); return copy_from_user_mvcos(size, ptr, x); } -size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) +static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) { register unsigned long reg0 asm("0") = 0x810000UL; unsigned long tmp1, tmp2; @@ -105,14 +103,16 @@ size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) return size; } -size_t copy_to_user_mvcos_check(size_t size, void __user *ptr, const void *x) +static size_t copy_to_user_mvcos_check(size_t size, void __user *ptr, + const void *x) { if (size <= 256) return copy_to_user_std(size, ptr, x); return copy_to_user_mvcos(size, ptr, x); } -size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from) +static size_t copy_in_user_mvcos(size_t size, void __user *to, + const void __user *from) { register unsigned long reg0 asm("0") = 0x810081UL; unsigned long tmp1, tmp2; @@ -134,7 +134,7 @@ size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from) return size; } -size_t clear_user_mvcos(size_t size, void __user *to) +static size_t clear_user_mvcos(size_t size, void __user *to) { register unsigned long reg0 asm("0") = 0x810000UL; unsigned long tmp1, tmp2; @@ -162,10 +162,43 @@ size_t clear_user_mvcos(size_t size, void __user *to) return size; } -extern size_t strnlen_user_std(size_t, const char __user *); -extern size_t strncpy_from_user_std(size_t, const char __user *, char *); -extern int futex_atomic_op(int, int __user *, int, int *); -extern int futex_atomic_cmpxchg(int __user *, int, int); +static size_t strnlen_user_mvcos(size_t count, const char __user *src) +{ + char buf[256]; + int rc; + size_t done, len, len_str; + + done = 0; + do { + len = min(count - done, (size_t) 256); + rc = uaccess.copy_from_user(len, src + done, buf); + if (unlikely(rc == len)) + return 0; + len -= rc; + len_str = strnlen(buf, len); + done += len_str; + } while ((len_str == len) && (done < count)); + return done + 1; +} + +static size_t strncpy_from_user_mvcos(size_t count, const char __user *src, + char *dst) +{ + int rc; + size_t done, len, len_str; + + done = 0; + do { + len = min(count - done, (size_t) 4096); + rc = uaccess.copy_from_user(len, src + done, dst); + if (unlikely(rc == len)) + return -EFAULT; + len -= rc; + len_str = strnlen(dst, len); + done += len_str; + } while ((len_str == len) && (done < count)); + return done; +} struct uaccess_ops uaccess_mvcos = { .copy_from_user = copy_from_user_mvcos_check, @@ -176,6 +209,21 @@ struct uaccess_ops uaccess_mvcos = { .clear_user = clear_user_mvcos, .strnlen_user = strnlen_user_std, .strncpy_from_user = strncpy_from_user_std, - .futex_atomic_op = futex_atomic_op, - .futex_atomic_cmpxchg = futex_atomic_cmpxchg, + .futex_atomic_op = futex_atomic_op_std, + .futex_atomic_cmpxchg = futex_atomic_cmpxchg_std, }; + +#ifdef CONFIG_S390_SWITCH_AMODE +struct uaccess_ops uaccess_mvcos_switch = { + .copy_from_user = copy_from_user_mvcos, + .copy_from_user_small = copy_from_user_mvcos, + .copy_to_user = copy_to_user_mvcos, + .copy_to_user_small = copy_to_user_mvcos, + .copy_in_user = copy_in_user_mvcos, + .clear_user = clear_user_mvcos, + .strnlen_user = strnlen_user_mvcos, + .strncpy_from_user = strncpy_from_user_mvcos, + .futex_atomic_op = futex_atomic_op_pt, + .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt, +}; +#endif diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index 49c3e46b4065..63181671e3e3 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c @@ -1,7 +1,8 @@ /* * arch/s390/lib/uaccess_pt.c * - * User access functions based on page table walks. + * User access functions based on page table walks for enhanced + * system layout without hardware support. * * Copyright IBM Corp. 2006 * Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com) @@ -12,9 +13,10 @@ #include #include #include +#include "uaccess.h" -static inline int __handle_fault(struct mm_struct *mm, unsigned long address, - int write_access) +static int __handle_fault(struct mm_struct *mm, unsigned long address, + int write_access) { struct vm_area_struct *vma; int ret = -EFAULT; @@ -79,8 +81,8 @@ out_sigbus: return ret; } -static inline size_t __user_copy_pt(unsigned long uaddr, void *kptr, - size_t n, int write_user) +static size_t __user_copy_pt(unsigned long uaddr, void *kptr, + size_t n, int write_user) { struct mm_struct *mm = current->mm; unsigned long offset, pfn, done, size; @@ -133,6 +135,49 @@ fault: goto retry; } +/* + * Do DAT for user address by page table walk, return kernel address. + * This function needs to be called with current->mm->page_table_lock held. + */ +static unsigned long __dat_user_addr(unsigned long uaddr) +{ + struct mm_struct *mm = current->mm; + unsigned long pfn, ret; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + int rc; + + ret = 0; +retry: + pgd = pgd_offset(mm, uaddr); + if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) + goto fault; + + pmd = pmd_offset(pgd, uaddr); + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + goto fault; + + pte = pte_offset_map(pmd, uaddr); + if (!pte || !pte_present(*pte)) + goto fault; + + pfn = pte_pfn(*pte); + if (!pfn_valid(pfn)) + goto out; + + ret = (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1)); +out: + return ret; +fault: + spin_unlock(&mm->page_table_lock); + rc = __handle_fault(mm, uaddr, 0); + spin_lock(&mm->page_table_lock); + if (rc) + goto out; + goto retry; +} + size_t copy_from_user_pt(size_t n, const void __user *from, void *to) { size_t rc; @@ -155,3 +200,277 @@ size_t copy_to_user_pt(size_t n, void __user *to, const void *from) } return __user_copy_pt((unsigned long) to, (void *) from, n, 1); } + +static size_t clear_user_pt(size_t n, void __user *to) +{ + long done, size, ret; + + if (segment_eq(get_fs(), KERNEL_DS)) { + memset((void __kernel __force *) to, 0, n); + return 0; + } + done = 0; + do { + if (n - done > PAGE_SIZE) + size = PAGE_SIZE; + else + size = n - done; + ret = __user_copy_pt((unsigned long) to + done, + &empty_zero_page, size, 1); + done += size; + if (ret) + return ret + n - done; + } while (done < n); + return 0; +} + +static size_t strnlen_user_pt(size_t count, const char __user *src) +{ + char *addr; + unsigned long uaddr = (unsigned long) src; + struct mm_struct *mm = current->mm; + unsigned long offset, pfn, done, len; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + size_t len_str; + + if (segment_eq(get_fs(), KERNEL_DS)) + return strnlen((const char __kernel __force *) src, count) + 1; + done = 0; +retry: + spin_lock(&mm->page_table_lock); + do { + pgd = pgd_offset(mm, uaddr); + if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) + goto fault; + + pmd = pmd_offset(pgd, uaddr); + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + goto fault; + + pte = pte_offset_map(pmd, uaddr); + if (!pte || !pte_present(*pte)) + goto fault; + + pfn = pte_pfn(*pte); + if (!pfn_valid(pfn)) { + done = -1; + goto out; + } + + offset = uaddr & (PAGE_SIZE-1); + addr = (char *)(pfn << PAGE_SHIFT) + offset; + len = min(count - done, PAGE_SIZE - offset); + len_str = strnlen(addr, len); + done += len_str; + uaddr += len_str; + } while ((len_str == len) && (done < count)); +out: + spin_unlock(&mm->page_table_lock); + return done + 1; +fault: + spin_unlock(&mm->page_table_lock); + if (__handle_fault(mm, uaddr, 0)) { + return 0; + } + goto retry; +} + +static size_t strncpy_from_user_pt(size_t count, const char __user *src, + char *dst) +{ + size_t n = strnlen_user_pt(count, src); + + if (!n) + return -EFAULT; + if (n > count) + n = count; + if (segment_eq(get_fs(), KERNEL_DS)) { + memcpy(dst, (const char __kernel __force *) src, n); + if (dst[n-1] == '\0') + return n-1; + else + return n; + } + if (__user_copy_pt((unsigned long) src, dst, n, 0)) + return -EFAULT; + if (dst[n-1] == '\0') + return n-1; + else + return n; +} + +static size_t copy_in_user_pt(size_t n, void __user *to, + const void __user *from) +{ + struct mm_struct *mm = current->mm; + unsigned long offset_from, offset_to, offset_max, pfn_from, pfn_to, + uaddr, done, size; + unsigned long uaddr_from = (unsigned long) from; + unsigned long uaddr_to = (unsigned long) to; + pgd_t *pgd_from, *pgd_to; + pmd_t *pmd_from, *pmd_to; + pte_t *pte_from, *pte_to; + int write_user; + + done = 0; +retry: + spin_lock(&mm->page_table_lock); + do { + pgd_from = pgd_offset(mm, uaddr_from); + if (pgd_none(*pgd_from) || unlikely(pgd_bad(*pgd_from))) { + uaddr = uaddr_from; + write_user = 0; + goto fault; + } + pgd_to = pgd_offset(mm, uaddr_to); + if (pgd_none(*pgd_to) || unlikely(pgd_bad(*pgd_to))) { + uaddr = uaddr_to; + write_user = 1; + goto fault; + } + + pmd_from = pmd_offset(pgd_from, uaddr_from); + if (pmd_none(*pmd_from) || unlikely(pmd_bad(*pmd_from))) { + uaddr = uaddr_from; + write_user = 0; + goto fault; + } + pmd_to = pmd_offset(pgd_to, uaddr_to); + if (pmd_none(*pmd_to) || unlikely(pmd_bad(*pmd_to))) { + uaddr = uaddr_to; + write_user = 1; + goto fault; + } + + pte_from = pte_offset_map(pmd_from, uaddr_from); + if (!pte_from || !pte_present(*pte_from)) { + uaddr = uaddr_from; + write_user = 0; + goto fault; + } + pte_to = pte_offset_map(pmd_to, uaddr_to); + if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) { + uaddr = uaddr_to; + write_user = 1; + goto fault; + } + + pfn_from = pte_pfn(*pte_from); + if (!pfn_valid(pfn_from)) + goto out; + pfn_to = pte_pfn(*pte_to); + if (!pfn_valid(pfn_to)) + goto out; + + offset_from = uaddr_from & (PAGE_SIZE-1); + offset_to = uaddr_from & (PAGE_SIZE-1); + offset_max = max(offset_from, offset_to); + size = min(n - done, PAGE_SIZE - offset_max); + + memcpy((void *)(pfn_to << PAGE_SHIFT) + offset_to, + (void *)(pfn_from << PAGE_SHIFT) + offset_from, size); + done += size; + uaddr_from += size; + uaddr_to += size; + } while (done < n); +out: + spin_unlock(&mm->page_table_lock); + return n - done; +fault: + spin_unlock(&mm->page_table_lock); + if (__handle_fault(mm, uaddr, write_user)) + return n - done; + goto retry; +} + +#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \ + asm volatile("0: l %1,0(%6)\n" \ + "1: " insn \ + "2: cs %1,%2,0(%6)\n" \ + "3: jl 1b\n" \ + " lhi %0,0\n" \ + "4:\n" \ + EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b) \ + : "=d" (ret), "=&d" (oldval), "=&d" (newval), \ + "=m" (*uaddr) \ + : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \ + "m" (*uaddr) : "cc" ); + +int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old) +{ + int oldval = 0, newval, ret; + + spin_lock(¤t->mm->page_table_lock); + uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr); + if (!uaddr) { + spin_unlock(¤t->mm->page_table_lock); + return -EFAULT; + } + get_page(virt_to_page(uaddr)); + spin_unlock(¤t->mm->page_table_lock); + switch (op) { + case FUTEX_OP_SET: + __futex_atomic_op("lr %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + case FUTEX_OP_ADD: + __futex_atomic_op("lr %2,%1\nar %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + case FUTEX_OP_OR: + __futex_atomic_op("lr %2,%1\nor %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + case FUTEX_OP_ANDN: + __futex_atomic_op("lr %2,%1\nnr %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + case FUTEX_OP_XOR: + __futex_atomic_op("lr %2,%1\nxr %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + default: + ret = -ENOSYS; + } + put_page(virt_to_page(uaddr)); + *old = oldval; + return ret; +} + +int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval) +{ + int ret; + + spin_lock(¤t->mm->page_table_lock); + uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr); + if (!uaddr) { + spin_unlock(¤t->mm->page_table_lock); + return -EFAULT; + } + get_page(virt_to_page(uaddr)); + spin_unlock(¤t->mm->page_table_lock); + asm volatile(" cs %1,%4,0(%5)\n" + "0: lr %0,%1\n" + "1:\n" + EX_TABLE(0b,1b) + : "=d" (ret), "+d" (oldval), "=m" (*uaddr) + : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr) + : "cc", "memory" ); + put_page(virt_to_page(uaddr)); + return ret; +} + +struct uaccess_ops uaccess_pt = { + .copy_from_user = copy_from_user_pt, + .copy_from_user_small = copy_from_user_pt, + .copy_to_user = copy_to_user_pt, + .copy_to_user_small = copy_to_user_pt, + .copy_in_user = copy_in_user_pt, + .clear_user = clear_user_pt, + .strnlen_user = strnlen_user_pt, + .strncpy_from_user = strncpy_from_user_pt, + .futex_atomic_op = futex_atomic_op_pt, + .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt, +}; diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c index 56a0214e9928..28c4500a58d0 100644 --- a/arch/s390/lib/uaccess_std.c +++ b/arch/s390/lib/uaccess_std.c @@ -13,6 +13,7 @@ #include #include #include +#include "uaccess.h" #ifndef __s390x__ #define AHI "ahi" @@ -28,9 +29,6 @@ #define SLR "slgr" #endif -extern size_t copy_from_user_pt(size_t n, const void __user *from, void *to); -extern size_t copy_to_user_pt(size_t n, void __user *to, const void *from); - size_t copy_from_user_std(size_t size, const void __user *ptr, void *x) { unsigned long tmp1, tmp2; @@ -72,7 +70,8 @@ size_t copy_from_user_std(size_t size, const void __user *ptr, void *x) return size; } -size_t copy_from_user_std_check(size_t size, const void __user *ptr, void *x) +static size_t copy_from_user_std_check(size_t size, const void __user *ptr, + void *x) { if (size <= 1024) return copy_from_user_std(size, ptr, x); @@ -110,14 +109,16 @@ size_t copy_to_user_std(size_t size, void __user *ptr, const void *x) return size; } -size_t copy_to_user_std_check(size_t size, void __user *ptr, const void *x) +static size_t copy_to_user_std_check(size_t size, void __user *ptr, + const void *x) { if (size <= 1024) return copy_to_user_std(size, ptr, x); return copy_to_user_pt(size, ptr, x); } -size_t copy_in_user_std(size_t size, void __user *to, const void __user *from) +static size_t copy_in_user_std(size_t size, void __user *to, + const void __user *from) { unsigned long tmp1; @@ -148,7 +149,7 @@ size_t copy_in_user_std(size_t size, void __user *to, const void __user *from) return size; } -size_t clear_user_std(size_t size, void __user *to) +static size_t clear_user_std(size_t size, void __user *to) { unsigned long tmp1, tmp2; @@ -254,7 +255,7 @@ size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst) : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \ "m" (*uaddr) : "cc"); -int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old) +int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old) { int oldval = 0, newval, ret; @@ -286,7 +287,7 @@ int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old) return ret; } -int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval) +int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval) { int ret; @@ -311,6 +312,6 @@ struct uaccess_ops uaccess_std = { .clear_user = clear_user_std, .strnlen_user = strnlen_user_std, .strncpy_from_user = strncpy_from_user_std, - .futex_atomic_op = futex_atomic_op, - .futex_atomic_cmpxchg = futex_atomic_cmpxchg, + .futex_atomic_op = futex_atomic_op_std, + .futex_atomic_cmpxchg = futex_atomic_cmpxchg_std, }; diff --git a/arch/s390/math-emu/Makefile b/arch/s390/math-emu/Makefile index c10df144f2ab..73b3e72efc46 100644 --- a/arch/s390/math-emu/Makefile +++ b/arch/s390/math-emu/Makefile @@ -2,7 +2,7 @@ # Makefile for the FPU instruction emulation. # -obj-$(CONFIG_MATHEMU) := math.o qrnnd.o +obj-$(CONFIG_MATHEMU) := math.o EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w EXTRA_AFLAGS := -traditional diff --git a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c index 6b9aec5a2c18..3ee78ccb617d 100644 --- a/arch/s390/math-emu/math.c +++ b/arch/s390/math-emu/math.c @@ -15,7 +15,7 @@ #include #include -#include "sfp-util.h" +#include #include #include #include diff --git a/arch/s390/math-emu/qrnnd.S b/arch/s390/math-emu/qrnnd.S deleted file mode 100644 index b01c2b648e22..000000000000 --- a/arch/s390/math-emu/qrnnd.S +++ /dev/null @@ -1,77 +0,0 @@ -# S/390 __udiv_qrnnd - -# r2 : &__r -# r3 : upper half of 64 bit word n -# r4 : lower half of 64 bit word n -# r5 : divisor d -# the reminder r of the division is to be stored to &__r and -# the quotient q is to be returned - - .text - .globl __udiv_qrnnd -__udiv_qrnnd: - st %r2,24(%r15) # store pointer to reminder for later - lr %r0,%r3 # reload n - lr %r1,%r4 - ltr %r2,%r5 # reload and test divisor - jp 5f - # divisor >= 0x80000000 - srdl %r0,2 # n/4 - srl %r2,1 # d/2 - slr %r1,%r2 # special case if last bit of d is set - brc 3,0f # (n/4) div (n/2) can overflow by 1 - ahi %r0,-1 # trick: subtract n/2, then divide -0: dr %r0,%r2 # signed division - ahi %r1,1 # trick part 2: add 1 to the quotient - # now (n >> 2) = (d >> 1) * %r1 + %r0 - lhi %r3,1 - nr %r3,%r1 # test last bit of q - jz 1f - alr %r0,%r2 # add (d>>1) to r -1: srl %r1,1 # q >>= 1 - # now (n >> 2) = (d&-2) * %r1 + %r0 - lhi %r3,1 - nr %r3,%r5 # test last bit of d - jz 2f - slr %r0,%r1 # r -= q - brc 3,2f # borrow ? - alr %r0,%r5 # r += d - ahi %r1,-1 -2: # now (n >> 2) = d * %r1 + %r0 - alr %r1,%r1 # q <<= 1 - alr %r0,%r0 # r <<= 1 - brc 12,3f # overflow on r ? - slr %r0,%r5 # r -= d - ahi %r1,1 # q += 1 -3: lhi %r3,2 - nr %r3,%r4 # test next to last bit of n - jz 4f - ahi %r0,1 # r += 1 -4: clr %r0,%r5 # r >= d ? - jl 6f - slr %r0,%r5 # r -= d - ahi %r1,1 # q += 1 - # now (n >> 1) = d * %r1 + %r0 - j 6f -5: # divisor < 0x80000000 - srdl %r0,1 - dr %r0,%r2 # signed division - # now (n >> 1) = d * %r1 + %r0 -6: alr %r1,%r1 # q <<= 1 - alr %r0,%r0 # r <<= 1 - brc 12,7f # overflow on r ? - slr %r0,%r5 # r -= d - ahi %r1,1 # q += 1 -7: lhi %r3,1 - nr %r3,%r4 # isolate last bit of n - alr %r0,%r3 # r += (n & 1) - clr %r0,%r5 # r >= d ? - jl 8f - slr %r0,%r5 # r -= d - ahi %r1,1 # q += 1 -8: # now n = d * %r1 + %r0 - l %r2,24(%r15) - st %r0,0(%r2) - lr %r2,%r1 - br %r14 - .end __udiv_qrnnd diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index 607f50ead1fd..f93a056869bc 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -245,7 +245,7 @@ cmm_set_timeout(long nr, long seconds) cmm_set_timer(); } -static inline int +static int cmm_skip_blanks(char *cp, char **endp) { char *str; @@ -414,7 +414,7 @@ cmm_smsg_target(char *from, char *msg) } #endif -struct ctl_table_header *cmm_sysctl_header; +static struct ctl_table_header *cmm_sysctl_header; static int cmm_init (void) diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 775bf19e742b..394980b05e6f 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,7 @@ struct qin64 { struct dcss_segment { struct list_head list; char dcss_name[8]; + char res_name[15]; unsigned long start_addr; unsigned long end; atomic_t ref_count; @@ -77,6 +79,7 @@ struct dcss_segment { unsigned int vm_segtype; struct qrange range[6]; int segcnt; + struct resource *res; }; static DEFINE_MUTEX(dcss_lock); @@ -88,7 +91,7 @@ static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", * Create the 8 bytes, ebcdic VM segment name from * an ascii name. */ -static void inline +static void dcss_mkname(char *name, char *dcss_name) { int i; @@ -303,6 +306,29 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long goto out_free; } + seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL); + if (seg->res == NULL) { + rc = -ENOMEM; + goto out_shared; + } + seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; + seg->res->start = seg->start_addr; + seg->res->end = seg->end; + memcpy(&seg->res_name, seg->dcss_name, 8); + EBCASC(seg->res_name, 8); + seg->res_name[8] = '\0'; + strncat(seg->res_name, " (DCSS)", 7); + seg->res->name = seg->res_name; + rc = seg->vm_segtype; + if (rc == SEG_TYPE_SC || + ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared)) + seg->res->flags |= IORESOURCE_READONLY; + if (request_resource(&iomem_resource, seg->res)) { + rc = -EBUSY; + kfree(seg->res); + goto out_shared; + } + if (do_nonshared) dcss_command = DCSS_LOADNSR; else @@ -316,12 +342,11 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long rc = dcss_diag_translate_rc (seg->end); dcss_diag(DCSS_PURGESEG, seg->dcss_name, &seg->start_addr, &seg->end); - goto out_shared; + goto out_resource; } seg->do_nonshared = do_nonshared; atomic_set(&seg->ref_count, 1); list_add(&seg->list, &dcss_list); - rc = seg->vm_segtype; *addr = seg->start_addr; *end = seg->end; if (do_nonshared) @@ -329,12 +354,16 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long "type %s in non-shared mode\n", name, (void*)seg->start_addr, (void*)seg->end, segtype_string[seg->vm_segtype]); - else + else { PRINT_INFO ("segment_load: loaded segment %s range %p .. %p " "type %s in shared mode\n", name, (void*)seg->start_addr, (void*)seg->end, segtype_string[seg->vm_segtype]); + } goto out; + out_resource: + release_resource(seg->res); + kfree(seg->res); out_shared: remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1); out_free: @@ -401,6 +430,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr, * -ENOENT : no such segment (segment gone!) * -EAGAIN : segment is in use by other exploiters, try later * -EINVAL : no segment with the given name is currently loaded - name invalid + * -EBUSY : segment can temporarily not be used (overlaps with dcss) * 0 : operation succeeded */ int @@ -428,12 +458,24 @@ segment_modify_shared (char *name, int do_nonshared) rc = -EAGAIN; goto out_unlock; } - dcss_diag(DCSS_PURGESEG, seg->dcss_name, - &dummy, &dummy); - if (do_nonshared) + release_resource(seg->res); + if (do_nonshared) { dcss_command = DCSS_LOADNSR; - else - dcss_command = DCSS_LOADNOLY; + seg->res->flags &= ~IORESOURCE_READONLY; + } else { + dcss_command = DCSS_LOADNOLY; + if (seg->vm_segtype == SEG_TYPE_SR || + seg->vm_segtype == SEG_TYPE_ER) + seg->res->flags |= IORESOURCE_READONLY; + } + if (request_resource(&iomem_resource, seg->res)) { + PRINT_WARN("segment_modify_shared: could not reload segment %s" + " - overlapping resources\n", name); + rc = -EBUSY; + kfree(seg->res); + goto out_del; + } + dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); diag_cc = dcss_diag(dcss_command, seg->dcss_name, &seg->start_addr, &seg->end); if (diag_cc > 1) { @@ -446,9 +488,9 @@ segment_modify_shared (char *name, int do_nonshared) rc = 0; goto out_unlock; out_del: + remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1); list_del(&seg->list); - dcss_diag(DCSS_PURGESEG, seg->dcss_name, - &dummy, &dummy); + dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); kfree(seg); out_unlock: mutex_unlock(&dcss_lock); @@ -478,6 +520,8 @@ segment_unload(char *name) } if (atomic_dec_return(&seg->ref_count) != 0) goto out_unlock; + release_resource(seg->res); + kfree(seg->res); remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1); list_del(&seg->list); dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index cd85e34d8703..9ff143e87746 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -52,7 +52,7 @@ extern int sysctl_userprocess_debug; extern void die(const char *,struct pt_regs *,long); #ifdef CONFIG_KPROBES -ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); +static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); int register_page_fault_notifier(struct notifier_block *nb) { return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); @@ -137,7 +137,9 @@ static int __check_access_register(struct pt_regs *regs, int error_code) /* * Check which address space the address belongs to. - * Returns 1 for user space and 0 for kernel space. + * May return 1 or 2 for user space and 0 for kernel space. + * Returns 2 for user space in primary addressing mode with + * CONFIG_S390_EXEC_PROTECT on and kernel parameter noexec=on. */ static inline int check_user_space(struct pt_regs *regs, int error_code) { @@ -154,7 +156,7 @@ static inline int check_user_space(struct pt_regs *regs, int error_code) return __check_access_register(regs, error_code); if (descriptor == 2) return current->thread.mm_segment.ar4; - return descriptor != 0; + return ((descriptor != 0) ^ (switch_amode)) << s390_noexec; } /* @@ -183,6 +185,77 @@ static void do_sigsegv(struct pt_regs *regs, unsigned long error_code, force_sig_info(SIGSEGV, &si, current); } +#ifdef CONFIG_S390_EXEC_PROTECT +extern long sys_sigreturn(struct pt_regs *regs); +extern long sys_rt_sigreturn(struct pt_regs *regs); +extern long sys32_sigreturn(struct pt_regs *regs); +extern long sys32_rt_sigreturn(struct pt_regs *regs); + +static inline void do_sigreturn(struct mm_struct *mm, struct pt_regs *regs, + int rt) +{ + up_read(&mm->mmap_sem); + clear_tsk_thread_flag(current, TIF_SINGLE_STEP); +#ifdef CONFIG_COMPAT + if (test_tsk_thread_flag(current, TIF_31BIT)) { + if (rt) + sys32_rt_sigreturn(regs); + else + sys32_sigreturn(regs); + return; + } +#endif /* CONFIG_COMPAT */ + if (rt) + sys_rt_sigreturn(regs); + else + sys_sigreturn(regs); + return; +} + +static int signal_return(struct mm_struct *mm, struct pt_regs *regs, + unsigned long address, unsigned long error_code) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + u16 *instruction; + unsigned long pfn, uaddr = regs->psw.addr; + + spin_lock(&mm->page_table_lock); + pgd = pgd_offset(mm, uaddr); + if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) + goto out_fault; + pmd = pmd_offset(pgd, uaddr); + if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) + goto out_fault; + pte = pte_offset_map(pmd_offset(pgd_offset(mm, uaddr), uaddr), uaddr); + if (!pte || !pte_present(*pte)) + goto out_fault; + pfn = pte_pfn(*pte); + if (!pfn_valid(pfn)) + goto out_fault; + spin_unlock(&mm->page_table_lock); + + instruction = (u16 *) ((pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE-1))); + if (*instruction == 0x0a77) + do_sigreturn(mm, regs, 0); + else if (*instruction == 0x0aad) + do_sigreturn(mm, regs, 1); + else { + printk("- XXX - do_exception: task = %s, primary, NO EXEC " + "-> SIGSEGV\n", current->comm); + up_read(&mm->mmap_sem); + current->thread.prot_addr = address; + current->thread.trap_no = error_code; + do_sigsegv(regs, error_code, SEGV_MAPERR, address); + } + return 0; +out_fault: + spin_unlock(&mm->page_table_lock); + return -EFAULT; +} +#endif /* CONFIG_S390_EXEC_PROTECT */ + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -260,6 +333,17 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection) vma = find_vma(mm, address); if (!vma) goto bad_area; + +#ifdef CONFIG_S390_EXEC_PROTECT + if (unlikely((user_address == 2) && !(vma->vm_flags & VM_EXEC))) + if (!signal_return(mm, regs, address, error_code)) + /* + * signal_return() has done an up_read(&mm->mmap_sem) + * if it returns 0. + */ + return; +#endif + if (vma->vm_start <= address) goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) @@ -452,8 +536,7 @@ void pfault_fini(void) : : "a" (&refbk), "m" (refbk) : "cc"); } -asmlinkage void -pfault_interrupt(__u16 error_code) +static void pfault_interrupt(__u16 error_code) { struct task_struct *tsk; __u16 subcode; diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 4bb21be3b007..b3e7c45efb63 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -25,7 +25,7 @@ #include #include #include - +#include #include #include #include @@ -95,20 +95,18 @@ static void __init setup_ro_region(void) pte_t new_pte; unsigned long address, end; - address = ((unsigned long)&__start_rodata) & PAGE_MASK; - end = PFN_ALIGN((unsigned long)&__end_rodata); + address = ((unsigned long)&_stext) & PAGE_MASK; + end = PFN_ALIGN((unsigned long)&_eshared); for (; address < end; address += PAGE_SIZE) { pgd = pgd_offset_k(address); pmd = pmd_offset(pgd, address); pte = pte_offset_kernel(pmd, address); new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO)); - set_pte(pte, new_pte); + *pte = new_pte; } } -extern void vmem_map_init(void); - /* * paging_init() sets up the page tables */ @@ -125,11 +123,11 @@ void __init paging_init(void) #ifdef CONFIG_64BIT pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE; for (i = 0; i < PTRS_PER_PGD; i++) - pgd_clear(pg_dir + i); + pgd_clear_kernel(pg_dir + i); #else pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE; for (i = 0; i < PTRS_PER_PGD; i++) - pmd_clear((pmd_t *)(pg_dir + i)); + pmd_clear_kernel((pmd_t *)(pg_dir + i)); #endif vmem_map_init(); setup_ro_region(); @@ -174,10 +172,8 @@ void __init mem_init(void) datasize >>10, initsize >> 10); printk("Write protected kernel read-only data: %#lx - %#lx\n", - (unsigned long)&__start_rodata, - PFN_ALIGN((unsigned long)&__end_rodata) - 1); - printk("Virtual memmap size: %ldk\n", - (max_pfn * sizeof(struct page)) >> 10); + (unsigned long)&_stext, + PFN_ALIGN((unsigned long)&_eshared) - 1); } void free_initmem(void) diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index cd3d93e8c211..92a565190028 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -82,7 +82,7 @@ static inline pmd_t *vmem_pmd_alloc(void) if (!pmd) return NULL; for (i = 0; i < PTRS_PER_PMD; i++) - pmd_clear(pmd + i); + pmd_clear_kernel(pmd + i); return pmd; } @@ -97,7 +97,7 @@ static inline pte_t *vmem_pte_alloc(void) return NULL; pte_val(empty_pte) = _PAGE_TYPE_EMPTY; for (i = 0; i < PTRS_PER_PTE; i++) - set_pte(pte + i, empty_pte); + pte[i] = empty_pte; return pte; } @@ -119,7 +119,7 @@ static int vmem_add_range(unsigned long start, unsigned long size) pm_dir = vmem_pmd_alloc(); if (!pm_dir) goto out; - pgd_populate(&init_mm, pg_dir, pm_dir); + pgd_populate_kernel(&init_mm, pg_dir, pm_dir); } pm_dir = pmd_offset(pg_dir, address); @@ -132,7 +132,7 @@ static int vmem_add_range(unsigned long start, unsigned long size) pt_dir = pte_offset_kernel(pm_dir, address); pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL); - set_pte(pt_dir, pte); + *pt_dir = pte; } ret = 0; out: @@ -161,7 +161,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size) if (pmd_none(*pm_dir)) continue; pt_dir = pte_offset_kernel(pm_dir, address); - set_pte(pt_dir, pte); + *pt_dir = pte; } flush_tlb_kernel_range(start, start + size); } @@ -191,7 +191,7 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size) pm_dir = vmem_pmd_alloc(); if (!pm_dir) goto out; - pgd_populate(&init_mm, pg_dir, pm_dir); + pgd_populate_kernel(&init_mm, pg_dir, pm_dir); } pm_dir = pmd_offset(pg_dir, address); @@ -210,7 +210,7 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size) if (!new_page) goto out; pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL); - set_pte(pt_dir, pte); + *pt_dir = pte; } } ret = 0; 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/kernel/genapic.c b/arch/x86_64/kernel/genapic.c index b007433f96bb..0b3603adf56d 100644 --- a/arch/x86_64/kernel/genapic.c +++ b/arch/x86_64/kernel/genapic.c @@ -58,8 +58,8 @@ void __init clustered_apic_check(void) * Some x86_64 machines use physical APIC mode regardless of how many * procs/clusters are present (x86_64 ES7000 is an example). */ - if (acpi_fadt.revision > FADT2_REVISION_ID) - if (acpi_fadt.force_apic_physical_destination_mode) { + if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID) + if (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) { genapic = &apic_cluster; goto print; } 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/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c index 08072568847d..50dd8bef850e 100644 --- a/arch/x86_64/kernel/mpparse.c +++ b/arch/x86_64/kernel/mpparse.c @@ -798,7 +798,7 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity) return gsi; /* Don't set up the ACPI SCI because it's already set up */ - if (acpi_fadt.sci_int == gsi) + if (acpi_gbl_FADT.sci_interrupt == gsi) return gsi; ioapic = mp_find_ioapic(gsi); diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb.c index 697f0aa794b9..eb18be5a6569 100644 --- a/arch/x86_64/kernel/pci-swiotlb.c +++ b/arch/x86_64/kernel/pci-swiotlb.c @@ -29,7 +29,7 @@ struct dma_mapping_ops swiotlb_dma_ops = { .dma_supported = NULL, }; -void pci_swiotlb_init(void) +void __init pci_swiotlb_init(void) { /* don't initialize swiotlb if iommu=off (no_iommu=1) */ if (!iommu_detected && !no_iommu && end_pfn > MAX_DMA32_PFN) 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/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/crypto/Kconfig b/crypto/Kconfig index 92ba249f3a5b..918b4d845f93 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -74,14 +74,6 @@ config CRYPTO_SHA1 help SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). -config CRYPTO_SHA1_S390 - tristate "SHA1 digest algorithm (s390)" - depends on S390 - select CRYPTO_ALGAPI - help - This is the s390 hardware accelerated implementation of the - SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). - config CRYPTO_SHA256 tristate "SHA256 digest algorithm" select CRYPTO_ALGAPI @@ -91,17 +83,6 @@ config CRYPTO_SHA256 This version of SHA implements a 256 bit hash with 128 bits of security against collision attacks. -config CRYPTO_SHA256_S390 - tristate "SHA256 digest algorithm (s390)" - depends on S390 - select CRYPTO_ALGAPI - help - This is the s390 hardware accelerated implementation of the - SHA256 secure hash standard (DFIPS 180-2). - - This version of SHA implements a 256 bit hash with 128 bits of - security against collision attacks. - config CRYPTO_SHA512 tristate "SHA384 and SHA512 digest algorithms" select CRYPTO_ALGAPI @@ -187,14 +168,6 @@ config CRYPTO_DES help DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). -config CRYPTO_DES_S390 - tristate "DES and Triple DES cipher algorithms (s390)" - depends on S390 - select CRYPTO_ALGAPI - select CRYPTO_BLKCIPHER - help - DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). - config CRYPTO_BLOWFISH tristate "Blowfish cipher algorithm" select CRYPTO_ALGAPI @@ -336,28 +309,6 @@ config CRYPTO_AES_X86_64 See for more information. -config CRYPTO_AES_S390 - tristate "AES cipher algorithms (s390)" - depends on S390 - select CRYPTO_ALGAPI - select CRYPTO_BLKCIPHER - help - This is the s390 hardware accelerated implementation of the - AES cipher algorithms (FIPS-197). AES uses the Rijndael - algorithm. - - Rijndael appears to be consistently a very good performer in - both hardware and software across a wide range of computing - environments regardless of its use in feedback or non-feedback - modes. Its key setup time is excellent, and its key agility is - good. Rijndael's very low memory requirements make it very well - suited for restricted-space environments, in which it also - demonstrates excellent performance. Rijndael's operations are - among the easiest to defend against power and timing attacks. - - On s390 the System z9-109 currently only supports the key size - of 128 bit. - config CRYPTO_CAST5 tristate "CAST5 (CAST-128) cipher algorithm" select CRYPTO_ALGAPI diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index f4f000abc4e9..20eacc2c9e0e 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -3,6 +3,7 @@ # menu "ACPI (Advanced Configuration and Power Interface) Support" + depends on !X86_NUMAQ depends on !X86_VISWS depends on !IA64_HP_SIM depends on IA64 || X86 @@ -77,6 +78,20 @@ config ACPI_SLEEP_PROC_SLEEP Create /proc/acpi/sleep Deprecated by /sys/power/state +config ACPI_PROCFS + bool "Procfs interface (deprecated)" + depends on ACPI + default y + ---help--- + Procfs interface for ACPI is made optional for back-compatible. + As the same functions are duplicated in sysfs interface + and this proc interface will be removed some time later, + it's marked as deprecated. + ( /proc/acpi/debug_layer && debug_level are deprecated by + /sys/module/acpi/parameters/debug_layer && debug_level. + /proc/acpi/info is deprecated by + /sys/module/acpi/parameters/acpica_version ) + config ACPI_AC tristate "AC Adapter" depends on X86 @@ -107,7 +122,7 @@ config ACPI_BUTTON config ACPI_VIDEO tristate "Video" - depends on X86 + depends on X86 && BACKLIGHT_CLASS_DEVICE help This driver implement the ACPI Extensions For Display Adapters for integrated graphics devices on motherboard, as specified in @@ -139,6 +154,13 @@ config ACPI_DOCK help This driver adds support for ACPI controlled docking stations +config ACPI_BAY + tristate "Removable Drive Bay (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + This driver adds support for ACPI controlled removable drive + bays such as the IBM ultrabay or the Dell Module Bay. + config ACPI_PROCESSOR tristate "Processor" default y @@ -186,19 +208,22 @@ config ACPI_ASUS Note: display switching code is currently considered EXPERIMENTAL, toying with these values may even lock your machine. - + All settings are changed via /proc/acpi/asus directory entries. Owner and group for these entries can be set with asus_uid and asus_gid parameters. - + More information and a userspace daemon for handling the extra buttons at . - + If you have an ACPI-compatible ASUS laptop, say Y or M here. This driver is still under development, so if your laptop is unsupported or something works not quite as expected, please use the mailing list - available on the above page (acpi4asus-user@lists.sourceforge.net) - + available on the above page (acpi4asus-user@lists.sourceforge.net). + + NOTE: This driver is deprecated and will probably be removed soon, + use asus-laptop instead. + config ACPI_IBM tristate "IBM ThinkPad Laptop Extras" depends on X86 diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index bce7ca27b429..856c32bccacb 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -37,13 +37,15 @@ endif obj-y += sleep/ obj-y += bus.o glue.o +obj-y += scan.o obj-$(CONFIG_ACPI_AC) += ac.o obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BUTTON) += button.o obj-$(CONFIG_ACPI_EC) += ec.o obj-$(CONFIG_ACPI_FAN) += fan.o obj-$(CONFIG_ACPI_DOCK) += dock.o -obj-$(CONFIG_ACPI_VIDEO) += video.o +obj-$(CONFIG_ACPI_BAY) += bay.o +obj-$(CONFIG_ACPI_VIDEO) += video.o obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o obj-$(CONFIG_ACPI_POWER) += power.o @@ -56,7 +58,6 @@ obj-$(CONFIG_ACPI_NUMA) += numa.o obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o -obj-y += scan.o motherboard.o obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o obj-y += cm_sbs.o obj-$(CONFIG_ACPI_SBS) += i2c_ec.o sbs.o 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/battery.c b/drivers/acpi/battery.c index 5f43e0d14899..2f4521a48fe7 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -64,7 +64,7 @@ extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); static int acpi_battery_add(struct acpi_device *device); static int acpi_battery_remove(struct acpi_device *device, int type); -static int acpi_battery_resume(struct acpi_device *device, int status); +static int acpi_battery_resume(struct acpi_device *device); static struct acpi_driver acpi_battery_driver = { .name = ACPI_BATTERY_DRIVER_NAME, @@ -753,7 +753,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type) } /* this is needed to learn about changes made in suspended state */ -static int acpi_battery_resume(struct acpi_device *device, int state) +static int acpi_battery_resume(struct acpi_device *device) { struct acpi_battery *battery; diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c new file mode 100644 index 000000000000..667fa1dfa1a3 --- /dev/null +++ b/drivers/acpi/bay.c @@ -0,0 +1,490 @@ +/* + * bay.c - ACPI removable drive bay driver + * + * Copyright (C) 2006 Kristen Carlson Accardi + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ACPI_BAY_DRIVER_NAME "ACPI Removable Drive Bay Driver" + +ACPI_MODULE_NAME("bay") +MODULE_AUTHOR("Kristen Carlson Accardi"); +MODULE_DESCRIPTION(ACPI_BAY_DRIVER_NAME); +MODULE_LICENSE("GPL"); +#define ACPI_BAY_CLASS "bay" +#define ACPI_BAY_COMPONENT 0x10000000 +#define _COMPONENT ACPI_BAY_COMPONENT +#define bay_dprintk(h,s) {\ + char prefix[80] = {'\0'};\ + struct acpi_buffer buffer = {sizeof(prefix), prefix};\ + acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\ + printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); } +static void bay_notify(acpi_handle handle, u32 event, void *data); +static int acpi_bay_add(struct acpi_device *device); +static int acpi_bay_remove(struct acpi_device *device, int type); + +static struct acpi_driver acpi_bay_driver = { + .name = ACPI_BAY_DRIVER_NAME, + .class = ACPI_BAY_CLASS, + .ids = ACPI_BAY_HID, + .ops = { + .add = acpi_bay_add, + .remove = acpi_bay_remove, + }, +}; + +struct bay { + acpi_handle handle; + char *name; + struct list_head list; + struct platform_device *pdev; +}; + +static LIST_HEAD(drive_bays); + + +/***************************************************************************** + * Drive Bay functions * + *****************************************************************************/ +/** + * is_ejectable - see if a device is ejectable + * @handle: acpi handle of the device + * + * If an acpi object has a _EJ0 method, then it is ejectable + */ +static int is_ejectable(acpi_handle handle) +{ + acpi_status status; + acpi_handle tmp; + + status = acpi_get_handle(handle, "_EJ0", &tmp); + if (ACPI_FAILURE(status)) + return 0; + return 1; +} + +/** + * bay_present - see if the bay device is present + * @bay: the drive bay + * + * execute the _STA method. + */ +static int bay_present(struct bay *bay) +{ + unsigned long sta; + acpi_status status; + + if (bay) { + status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta); + if (ACPI_SUCCESS(status) && sta) + return 1; + } + return 0; +} + +/** + * eject_device - respond to an eject request + * @handle - the device to eject + * + * Call this devices _EJ0 method. + */ +static void eject_device(acpi_handle handle) +{ + struct acpi_object_list arg_list; + union acpi_object arg; + + bay_dprintk(handle, "Ejecting device"); + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; + + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0", + &arg_list, NULL))) + pr_debug("Failed to evaluate _EJ0!\n"); +} + +/* + * show_present - read method for "present" file in sysfs + */ +static ssize_t show_present(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bay *bay = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay)); + +} +DEVICE_ATTR(present, S_IRUGO, show_present, NULL); + +/* + * write_eject - write method for "eject" file in sysfs + */ +static ssize_t write_eject(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bay *bay = dev_get_drvdata(dev); + + if (!count) + return -EINVAL; + + eject_device(bay->handle); + return count; +} +DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject); + +/** + * is_ata - see if a device is an ata device + * @handle: acpi handle of the device + * + * If an acpi object has one of 4 ATA ACPI methods defined, + * then it is an ATA device + */ +static int is_ata(acpi_handle handle) +{ + acpi_handle tmp; + + if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) + return 1; + + return 0; +} + +/** + * parent_is_ata(acpi_handle handle) + * + */ +static int parent_is_ata(acpi_handle handle) +{ + acpi_handle phandle; + + if (acpi_get_parent(handle, &phandle)) + return 0; + + return is_ata(phandle); +} + +/** + * is_ejectable_bay - see if a device is an ejectable drive bay + * @handle: acpi handle of the device + * + * If an acpi object is ejectable and has one of the ACPI ATA + * methods defined, then we can safely call it an ejectable + * drive bay + */ +static int is_ejectable_bay(acpi_handle handle) +{ + if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle)) + return 1; + return 0; +} + +/** + * eject_removable_drive - try to eject this drive + * @dev : the device structure of the drive + * + * If a device is a removable drive that requires an _EJ0 method + * to be executed in order to safely remove from the system, do + * it. ATM - always returns success + */ +int eject_removable_drive(struct device *dev) +{ + acpi_handle handle = DEVICE_ACPI_HANDLE(dev); + + if (handle) { + bay_dprintk(handle, "Got device handle"); + if (is_ejectable_bay(handle)) + eject_device(handle); + } else { + printk("No acpi handle for device\n"); + } + + /* should I return an error code? */ + return 0; +} +EXPORT_SYMBOL_GPL(eject_removable_drive); + +static int acpi_bay_add(struct acpi_device *device) +{ + bay_dprintk(device->handle, "adding bay device"); + strcpy(acpi_device_name(device), "Dockable Bay"); + strcpy(acpi_device_class(device), "bay"); + return 0; +} + +static int acpi_bay_add_fs(struct bay *bay) +{ + int ret; + struct device *dev = &bay->pdev->dev; + + ret = device_create_file(dev, &dev_attr_present); + if (ret) + goto add_fs_err; + ret = device_create_file(dev, &dev_attr_eject); + if (ret) { + device_remove_file(dev, &dev_attr_present); + goto add_fs_err; + } + return 0; + + add_fs_err: + bay_dprintk(bay->handle, "Error adding sysfs files\n"); + return ret; +} + +static void acpi_bay_remove_fs(struct bay *bay) +{ + struct device *dev = &bay->pdev->dev; + + /* cleanup sysfs */ + device_remove_file(dev, &dev_attr_present); + device_remove_file(dev, &dev_attr_eject); +} + +static int bay_is_dock_device(acpi_handle handle) +{ + acpi_handle parent; + + acpi_get_parent(handle, &parent); + + /* if the device or it's parent is dependent on the + * dock, then we are a dock device + */ + return (is_dock_device(handle) || is_dock_device(parent)); +} + +static int bay_add(acpi_handle handle, int id) +{ + acpi_status status; + struct bay *new_bay; + struct platform_device *pdev; + struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer); + + bay_dprintk(handle, "Adding notify handler"); + + /* + * Initialize bay device structure + */ + new_bay = kzalloc(GFP_ATOMIC, sizeof(*new_bay)); + INIT_LIST_HEAD(&new_bay->list); + new_bay->handle = handle; + new_bay->name = (char *)nbuffer.pointer; + + /* initialize platform device stuff */ + pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0); + if (pdev == NULL) { + printk(KERN_ERR PREFIX "Error registering bay device\n"); + goto bay_add_err; + } + new_bay->pdev = pdev; + platform_set_drvdata(pdev, new_bay); + + if (acpi_bay_add_fs(new_bay)) { + platform_device_unregister(new_bay->pdev); + goto bay_add_err; + } + + /* register for events on this device */ + status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + bay_notify, new_bay); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Error installing bay notify handler\n"); + } + + /* if we are on a dock station, we should register for dock + * notifications. + */ + if (bay_is_dock_device(handle)) { + bay_dprintk(handle, "Is dependent on dock\n"); + register_hotplug_dock_device(handle, bay_notify, new_bay); + } + list_add(&new_bay->list, &drive_bays); + printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name); + return 0; + +bay_add_err: + kfree(new_bay->name); + kfree(new_bay); + return -ENODEV; +} + +static int acpi_bay_remove(struct acpi_device *device, int type) +{ + /*** FIXME: do something here */ + return 0; +} + +/** + * bay_create_acpi_device - add new devices to acpi + * @handle - handle of the device to add + * + * This function will create a new acpi_device for the given + * handle if one does not exist already. This should cause + * acpi to scan for drivers for the given devices, and call + * matching driver's add routine. + * + * Returns a pointer to the acpi_device corresponding to the handle. + */ +static struct acpi_device * bay_create_acpi_device(acpi_handle handle) +{ + struct acpi_device *device = NULL; + struct acpi_device *parent_device; + acpi_handle parent; + int ret; + + bay_dprintk(handle, "Trying to get device"); + if (acpi_bus_get_device(handle, &device)) { + /* + * no device created for this object, + * so we should create one. + */ + bay_dprintk(handle, "No device for handle"); + acpi_get_parent(handle, &parent); + if (acpi_bus_get_device(parent, &parent_device)) + parent_device = NULL; + + ret = acpi_bus_add(&device, parent_device, handle, + ACPI_BUS_TYPE_DEVICE); + if (ret) { + pr_debug("error adding bus, %x\n", + -ret); + return NULL; + } + } + return device; +} + +/** + * bay_notify - act upon an acpi bay notification + * @handle: the bay handle + * @event: the acpi event + * @data: our driver data struct + * + */ +static void bay_notify(acpi_handle handle, u32 event, void *data) +{ + struct acpi_device *dev; + + bay_dprintk(handle, "Bay event"); + + switch(event) { + case ACPI_NOTIFY_BUS_CHECK: + printk("Bus Check\n"); + case ACPI_NOTIFY_DEVICE_CHECK: + printk("Device Check\n"); + dev = bay_create_acpi_device(handle); + if (dev) + acpi_bus_generate_event(dev, event, 0); + else + printk("No device for generating event\n"); + /* wouldn't it be a good idea to just rescan SATA + * right here? + */ + break; + case ACPI_NOTIFY_EJECT_REQUEST: + printk("Eject request\n"); + dev = bay_create_acpi_device(handle); + if (dev) + acpi_bus_generate_event(dev, event, 0); + else + printk("No device for generating eventn"); + + /* wouldn't it be a good idea to just call the + * eject_device here if we were a SATA device? + */ + break; + default: + printk("unknown event %d\n", event); + } +} + +static acpi_status +find_bay(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *count = (int *)context; + + /* + * there could be more than one ejectable bay. + * so, just return AE_OK always so that every object + * will be checked. + */ + if (is_ejectable_bay(handle)) { + bay_dprintk(handle, "found ejectable bay"); + if (!bay_add(handle, *count)) + (*count)++; + } + return AE_OK; +} + +static int __init bay_init(void) +{ + int bays = 0; + + INIT_LIST_HEAD(&drive_bays); + + /* look for dockable drive bays */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, find_bay, &bays, NULL); + + if (bays) + if ((acpi_bus_register_driver(&acpi_bay_driver) < 0)) + printk(KERN_ERR "Unable to register bay driver\n"); + + if (!bays) + return -ENODEV; + + return 0; +} + +static void __exit bay_exit(void) +{ + struct bay *bay, *tmp; + + list_for_each_entry_safe(bay, tmp, &drive_bays, list) { + if (is_dock_device(bay->handle)) + unregister_hotplug_dock_device(bay->handle); + acpi_bay_remove_fs(bay); + acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY, + bay_notify); + platform_device_unregister(bay->pdev); + kfree(bay->name); + kfree(bay); + } + + acpi_bus_unregister_driver(&acpi_bay_driver); +} + +postcore_initcall(bay_init); +module_exit(bay_exit); + diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index f9c972b26f4f..f289fd41e77d 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}, {""} @@ -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) @@ -103,22 +103,21 @@ int __init acpi_blacklisted(void) { int i = 0; int blacklisted = 0; - struct acpi_table_header *table_header; + 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; } - if (strncmp(acpi_blacklist[i].oem_id, table_header->oem_id, 6)) { + if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) { i++; continue; } if (strncmp - (acpi_blacklist[i].oem_table_id, table_header->oem_table_id, + (acpi_blacklist[i].oem_table_id, table_header.oem_table_id, 8)) { i++; continue; @@ -127,14 +126,14 @@ int __init acpi_blacklisted(void) if ((acpi_blacklist[i].oem_revision_predicate == all_versions) || (acpi_blacklist[i].oem_revision_predicate == less_than_or_equal - && table_header->oem_revision <= + && table_header.oem_revision <= acpi_blacklist[i].oem_revision) || (acpi_blacklist[i].oem_revision_predicate == greater_than_or_equal - && table_header->oem_revision >= + && table_header.oem_revision >= acpi_blacklist[i].oem_revision) || (acpi_blacklist[i].oem_revision_predicate == equal - && table_header->oem_revision == + && table_header.oem_revision == acpi_blacklist[i].oem_revision)) { printk(KERN_ERR PREFIX diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 766332e45592..c26468da4295 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); @@ -195,7 +192,7 @@ int acpi_bus_set_power(acpi_handle handle, int state) if (!device->flags.power_manageable) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", - device->kobj.name)); + device->dev.kobj.name)); return -ENODEV; } /* @@ -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,32 +618,25 @@ 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; + 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_fadt.sci_int, - acpi_sci_flags.trigger); + acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt, + (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2); } else { extern int acpi_sci_override_gsi; /* - * now that acpi_fadt is initialized, + * now that acpi_gbl_FADT is initialized, * update it with result from INT_SRC_OVR parsing */ - acpi_fadt.sci_int = acpi_sci_override_gsi; + acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi; } #endif diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index ac860583c203..c726612fafb6 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -75,7 +75,7 @@ static int acpi_button_state_open_fs(struct inode *inode, struct file *file); static struct acpi_driver acpi_button_driver = { .name = ACPI_BUTTON_DRIVER_NAME, .class = ACPI_BUTTON_CLASS, - .ids = "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E", + .ids = "button_power,button_sleep,PNP0C0D,PNP0C0C,PNP0C0E", .ops = { .add = acpi_button_add, .remove = acpi_button_remove, diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 0a1863ec91f3..69a68fd394cf 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -167,7 +167,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context) if (ACPI_FAILURE(status) || !device) { result = container_device_add(&device, handle); if (!result) - kobject_uevent(&device->kobj, + kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); else printk("Failed to add container\n"); @@ -175,13 +175,13 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context) } else { if (ACPI_SUCCESS(status)) { /* device exist and this is a remove request */ - kobject_uevent(&device->kobj, KOBJ_OFFLINE); + kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); } } break; case ACPI_NOTIFY_EJECT_REQUEST: if (!acpi_bus_get_device(handle, &device) && device) { - kobject_uevent(&device->kobj, KOBJ_OFFLINE); + kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); } break; default: diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c index 35c6af8a83cd..d48f65a8f658 100644 --- a/drivers/acpi/debug.c +++ b/drivers/acpi/debug.c @@ -13,14 +13,11 @@ #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("debug") -#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer" -#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level" + #ifdef MODULE_PARAM_PREFIX #undef MODULE_PARAM_PREFIX #endif -#define MODULE_PARAM_PREFIX - module_param(acpi_dbg_layer, uint, 0400); -module_param(acpi_dbg_level, uint, 0400); +#define MODULE_PARAM_PREFIX "acpi." struct acpi_dlayer { const char *name; @@ -86,6 +83,60 @@ static const struct acpi_dlevel acpi_debug_levels[] = { ACPI_DEBUG_INIT(ACPI_LV_EVENTS), }; +/* -------------------------------------------------------------------------- + FS Interface (/sys) + -------------------------------------------------------------------------- */ +static int param_get_debug_layer(char *buffer, struct kernel_param *kp) { + int result = 0; + int i; + + result = sprintf(buffer, "%-25s\tHex SET\n", "Description"); + + for(i = 0; i common.next; - info.bank_value = (u32) arg->common.value.integer; + + /* Currently, only the following constants are supported */ + + switch (arg->common.aml_opcode) { + case AML_ZERO_OP: + info.bank_value = 0; + break; + + case AML_ONE_OP: + info.bank_value = 1; + break; + + case AML_BYTE_OP: + case AML_WORD_OP: + case AML_DWORD_OP: + case AML_QWORD_OP: + info.bank_value = (u32) arg->common.value.integer; + break; + + default: + info.bank_value = 0; + ACPI_ERROR((AE_INFO, + "Non-constant BankValue for BankField is not implemented")); + } /* Fourth arg is the field flags */ diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c index 1888c055d10f..af923c388520 100644 --- a/drivers/acpi/dispatcher/dsinit.c +++ b/drivers/acpi/dispatcher/dsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,6 +44,7 @@ #include #include #include +#include #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsinit") @@ -90,7 +91,7 @@ acpi_ds_init_one_object(acpi_handle obj_handle, * We are only interested in NS nodes owned by the table that * was just loaded */ - if (node->owner_id != info->table_desc->owner_id) { + if (node->owner_id != info->owner_id) { return (AE_OK); } @@ -150,14 +151,21 @@ acpi_ds_init_one_object(acpi_handle obj_handle, ******************************************************************************/ acpi_status -acpi_ds_initialize_objects(struct acpi_table_desc * table_desc, +acpi_ds_initialize_objects(acpi_native_uint table_index, struct acpi_namespace_node * start_node) { acpi_status status; struct acpi_init_walk_info info; + struct acpi_table_header *table; + acpi_owner_id owner_id; ACPI_FUNCTION_TRACE(ds_initialize_objects); + status = acpi_tb_get_owner_id(table_index, &owner_id); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "**** Starting initialization of namespace objects ****\n")); ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:")); @@ -166,7 +174,8 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc, info.op_region_count = 0; info.object_count = 0; info.device_count = 0; - info.table_desc = table_desc; + info.table_index = table_index; + info.owner_id = owner_id; /* Walk entire namespace from the supplied root */ @@ -176,10 +185,14 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc, ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); } + status = acpi_get_table_by_index(table_index, &table); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n", - table_desc->pointer->signature, - table_desc->owner_id, info.object_count, + table->signature, owner_id, info.object_count, info.device_count, info.method_count, info.op_region_count)); diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index cf888add3191..1cbe61905824 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -327,7 +327,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Execute method %p, currentstate=%p\n", + "Calling method %p, currentstate=%p\n", this_walk_state->prev_op, this_walk_state)); /* @@ -351,49 +351,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, return_ACPI_STATUS(status); } - /* - * 1) Parse the method. All "normal" methods are parsed for each execution. - * Internal methods (_OSI, etc.) do not require parsing. - */ - if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) { - - /* Create a new walk state for the parse */ - - next_walk_state = - acpi_ds_create_walk_state(obj_desc->method.owner_id, op, - obj_desc, NULL); - if (!next_walk_state) { - status = AE_NO_MEMORY; - goto cleanup; - } - - /* Create and init a parse tree root */ - - op = acpi_ps_create_scope_op(); - if (!op) { - status = AE_NO_MEMORY; - goto cleanup; - } - - status = acpi_ds_init_aml_walk(next_walk_state, op, method_node, - obj_desc->method.aml_start, - obj_desc->method.aml_length, - NULL, 1); - if (ACPI_FAILURE(status)) { - acpi_ps_delete_parse_tree(op); - goto cleanup; - } - - /* Begin AML parse (deletes next_walk_state) */ - - status = acpi_ps_parse_aml(next_walk_state); - acpi_ps_delete_parse_tree(op); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - } - - /* 2) Begin method execution. Create a new walk state */ + /* Begin method parse/execution. Create a new walk state */ next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, obj_desc, thread); @@ -424,7 +382,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node, obj_desc->method.aml_start, - obj_desc->method.aml_length, info, 3); + obj_desc->method.aml_length, info, + ACPI_IMODE_EXECUTE); ACPI_FREE(info); if (ACPI_FAILURE(status)) { @@ -445,8 +404,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, this_walk_state->num_operands = 0; ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Starting nested execution, newstate=%p\n", - next_walk_state)); + "**** Begin nested execution of [%4.4s] **** WalkState=%p\n", + method_node->name.ascii, next_walk_state)); /* Invoke an internal method if necessary */ diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c index 459160ff9058..ba4626e06a5e 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c index 72190abb1d59..a474ca2334d5 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/dispatcher/dsobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -260,7 +260,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, } obj_desc->buffer.flags |= AOPOBJ_DATA_VALID; - op->common.node = (struct acpi_namespace_node *)obj_desc; + op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc); return_ACPI_STATUS(AE_OK); } @@ -270,7 +270,8 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, * * PARAMETERS: walk_state - Current walk state * Op - Parser object to be translated - * package_length - Number of elements in the package + * element_count - Number of elements in the package - this is + * the num_elements argument to Package() * obj_desc_ptr - Where the ACPI internal object is returned * * RETURN: Status @@ -278,18 +279,29 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, * DESCRIPTION: Translate a parser Op package object to the equivalent * namespace object * + * NOTE: The number of elements in the package will be always be the num_elements + * count, regardless of the number of elements in the package list. If + * num_elements is smaller, only that many package list elements are used. + * if num_elements is larger, the Package object is padded out with + * objects of type Uninitialized (as per ACPI spec.) + * + * Even though the ASL compilers do not allow num_elements to be smaller + * than the Package list length (for the fixed length package opcode), some + * BIOS code modifies the AML on the fly to adjust the num_elements, and + * this code compensates for that. This also provides compatibility with + * other AML interpreters. + * ******************************************************************************/ acpi_status acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, union acpi_parse_object *op, - u32 package_length, + u32 element_count, union acpi_operand_object **obj_desc_ptr) { union acpi_parse_object *arg; union acpi_parse_object *parent; union acpi_operand_object *obj_desc = NULL; - u32 package_list_length; acpi_status status = AE_OK; acpi_native_uint i; @@ -318,32 +330,13 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, obj_desc->package.node = parent->common.node; } - obj_desc->package.count = package_length; - - /* Count the number of items in the package list */ - - arg = op->common.value.arg; - arg = arg->common.next; - for (package_list_length = 0; arg; package_list_length++) { - arg = arg->common.next; - } - /* - * The package length (number of elements) will be the greater - * of the specified length and the length of the initializer list - */ - if (package_list_length > package_length) { - obj_desc->package.count = package_list_length; - } - - /* - * Allocate the pointer array (array of pointers to the - * individual objects). Add an extra pointer slot so - * that the list is always null terminated. + * Allocate the element array (array of pointers to the individual + * objects) based on the num_elements parameter. Add an extra pointer slot + * so that the list is always null terminated. */ obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) - obj_desc->package. - count + + element_count + 1) * sizeof(void *)); if (!obj_desc->package.elements) { @@ -351,15 +344,20 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_NO_MEMORY); } + obj_desc->package.count = element_count; + /* - * Initialize all elements of the package + * Initialize the elements of the package, up to the num_elements count. + * Package is automatically padded with uninitialized (NULL) elements + * if num_elements is greater than the package list length. Likewise, + * Package is truncated if num_elements is less than the list length. */ arg = op->common.value.arg; arg = arg->common.next; - for (i = 0; arg; i++) { + for (i = 0; arg && (i < element_count); i++) { if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { - /* Object (package or buffer) is already built */ + /* This package element is already built, just get it */ obj_desc->package.elements[i] = ACPI_CAST_PTR(union acpi_operand_object, @@ -373,8 +371,14 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, arg = arg->common.next; } + if (!arg) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Package List length larger than NumElements count (%X), truncated\n", + element_count)); + } + obj_desc->package.flags |= AOPOBJ_DATA_VALID; - op->common.node = (struct acpi_namespace_node *)obj_desc; + op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc); return_ACPI_STATUS(status); } @@ -488,8 +492,9 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, /* * Defer evaluation of Buffer term_arg operand */ - obj_desc->buffer.node = (struct acpi_namespace_node *) - walk_state->operands[0]; + obj_desc->buffer.node = + ACPI_CAST_PTR(struct acpi_namespace_node, + walk_state->operands[0]); obj_desc->buffer.aml_start = op->named.data; obj_desc->buffer.aml_length = op->named.length; break; @@ -499,8 +504,9 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, /* * Defer evaluation of Package term_arg operand */ - obj_desc->package.node = (struct acpi_namespace_node *) - walk_state->operands[0]; + obj_desc->package.node = + ACPI_CAST_PTR(struct acpi_namespace_node, + walk_state->operands[0]); obj_desc->package.aml_start = op->named.data; obj_desc->package.aml_length = op->named.length; break; diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c index 5b974a8fe614..6c6104a7a247 100644 --- a/drivers/acpi/dispatcher/dsopcode.c +++ b/drivers/acpi/dispatcher/dsopcode.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -114,7 +114,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node, } status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start, - aml_length, NULL, 1); + aml_length, NULL, ACPI_IMODE_LOAD_PASS1); if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); goto cleanup; @@ -157,7 +157,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node, /* Execute the opcode and arguments */ status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start, - aml_length, NULL, 3); + aml_length, NULL, ACPI_IMODE_EXECUTE); if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); goto cleanup; diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c index 05230baf5de8..e4073e05a75c 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/dispatcher/dsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c index d7a616c3104e..69693fa07224 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/dispatcher/dswexec.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -219,7 +219,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, if (!op) { status = acpi_ds_load2_begin_op(walk_state, out_op); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_exit; } op = *out_op; @@ -238,7 +238,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, status = acpi_ds_scope_stack_pop(walk_state); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_exit; } } } @@ -287,7 +287,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, status = acpi_ds_result_stack_push(walk_state); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto error_exit; } status = acpi_ds_exec_begin_control_op(walk_state, op); @@ -328,6 +328,10 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, /* Nothing to do here during method execution */ return_ACPI_STATUS(status); + + error_exit: + status = acpi_ds_method_error(status, walk_state); + return_ACPI_STATUS(status); } /***************************************************************************** diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c index e3ca7f6539c1..8ab9d1b29a4c 100644 --- a/drivers/acpi/dispatcher/dswload.c +++ b/drivers/acpi/dispatcher/dswload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -196,6 +196,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, * one of the opcodes that actually opens a scope */ switch (node->type) { + case ACPI_TYPE_ANY: case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ case ACPI_TYPE_DEVICE: case ACPI_TYPE_POWER: @@ -546,6 +547,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, acpi_status status; acpi_object_type object_type; char *buffer_ptr; + u32 flags; ACPI_FUNCTION_TRACE(ds_load2_begin_op); @@ -669,6 +671,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, * one of the opcodes that actually opens a scope */ switch (node->type) { + case ACPI_TYPE_ANY: case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ case ACPI_TYPE_DEVICE: case ACPI_TYPE_POWER: @@ -750,12 +753,20 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, break; } - /* Add new entry into namespace */ + flags = ACPI_NS_NO_UPSEARCH; + if (walk_state->pass_number == ACPI_IMODE_EXECUTE) { + + /* Execution mode, node cannot already exist, node is temporary */ + + flags |= (ACPI_NS_ERROR_IF_FOUND | ACPI_NS_TEMPORARY); + } + + /* Add new entry or lookup existing entry */ status = acpi_ns_lookup(walk_state->scope_info, buffer_ptr, - object_type, ACPI_IMODE_LOAD_PASS2, - ACPI_NS_NO_UPSEARCH, walk_state, &(node)); + object_type, ACPI_IMODE_LOAD_PASS2, flags, + walk_state, &node); break; } diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c index c9228972f5f6..3927c495e4bf 100644 --- a/drivers/acpi/dispatcher/dswscope.c +++ b/drivers/acpi/dispatcher/dswscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c index 7817e5522679..16c8e38b51ef 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/dispatcher/dswstate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 90990a4b6526..688e83a16906 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -615,20 +615,28 @@ static acpi_status find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) { acpi_status status; - acpi_handle tmp; + acpi_handle tmp, parent; struct dock_station *ds = context; struct dock_dependent_device *dd; status = acpi_bus_get_ejd(handle, &tmp); - if (ACPI_FAILURE(status)) - return AE_OK; + if (ACPI_FAILURE(status)) { + /* try the parent device as well */ + status = acpi_get_parent(handle, &parent); + if (ACPI_FAILURE(status)) + goto fdd_out; + /* see if parent is dependent on dock */ + status = acpi_bus_get_ejd(parent, &tmp); + if (ACPI_FAILURE(status)) + goto fdd_out; + } if (tmp == ds->handle) { dd = alloc_dock_dependent_device(handle); if (dd) add_dock_dependent_device(ds, dd); } - +fdd_out: return AE_OK; } diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index cbdf031f3c09..743ce27fa0bb 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -872,9 +872,8 @@ 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(ACPI_SIG_ECDT, 1, + (struct acpi_table_header **)&ecdt_ptr); if (ACPI_FAILURE(status)) return -ENODEV; @@ -891,14 +890,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/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c index 919037d6acff..a1f87b5def2a 100644 --- a/drivers/acpi/events/evevent.c +++ b/drivers/acpi/events/evevent.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -70,13 +70,6 @@ acpi_status acpi_ev_initialize_events(void) ACPI_FUNCTION_TRACE(ev_initialize_events); - /* Make sure we have ACPI tables */ - - if (!acpi_gbl_DSDT) { - ACPI_WARNING((AE_INFO, "No ACPI tables present!")); - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - /* * Initialize the Fixed and General Purpose Events. This is done prior to * enabling SCIs to prevent interrupts from occurring before the handlers are @@ -211,8 +204,7 @@ static acpi_status acpi_ev_fixed_event_initialize(void) if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) { status = acpi_set_register(acpi_gbl_fixed_event_info[i]. - enable_register_id, 0, - ACPI_MTX_LOCK); + enable_register_id, 0); if (ACPI_FAILURE(status)) { return (status); } @@ -298,7 +290,7 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event) /* Clear the status bit */ (void)acpi_set_register(acpi_gbl_fixed_event_info[event]. - status_register_id, 1, ACPI_MTX_DO_NOT_LOCK); + status_register_id, 1); /* * Make sure we've got a handler. If not, report an error. @@ -306,8 +298,7 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event) */ if (NULL == acpi_gbl_fixed_event_handlers[event].handler) { (void)acpi_set_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, 0, - ACPI_MTX_DO_NOT_LOCK); + enable_register_id, 0); ACPI_ERROR((AE_INFO, "No installed handler for fixed event [%08X]", diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index c76c0583ca6a..dfac3ecc596e 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -121,7 +121,9 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info, if (!gpe_register_info) { return_ACPI_STATUS(AE_NOT_EXIST); } - register_bit = gpe_event_info->register_bit; + register_bit = (u8) + (1 << + (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number)); /* 1) Disable case. Simply clear all enable bits */ @@ -458,8 +460,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) /* Examine one GPE bit */ - if (enabled_status_byte & - acpi_gbl_decode_to8bit[j]) { + if (enabled_status_byte & (1 << j)) { /* * Found an active GPE. Dispatch the event to a handler * or method. @@ -570,7 +571,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "While evaluating GPE method [%4.4s]", + "while evaluating GPE method [%4.4s]", acpi_ut_get_node_name (local_gpe_event_info.dispatch. method_node))); @@ -618,6 +619,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) ACPI_FUNCTION_TRACE(ev_gpe_dispatch); + acpi_gpe_count++; + /* * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. @@ -633,20 +636,23 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) } } - /* Save current system state */ - - if (acpi_gbl_system_awake_and_running) { - ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING); - } else { - ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING); + if (!acpi_gbl_system_awake_and_running) { + /* + * We just woke up because of a wake GPE. Disable any further GPEs + * until we are fully up and running (Only wake GPEs should be enabled + * at this time, but we just brute-force disable them all.) + * 1) We must disable this particular wake GPE so it won't fire again + * 2) We want to disable all wake GPEs, since we are now awake + */ + (void)acpi_hw_disable_all_gpes(); } /* - * Dispatch the GPE to either an installed handler, or the control - * method associated with this GPE (_Lxx or _Exx). - * If a handler exists, we invoke it and do not attempt to run the method. - * If there is neither a handler nor a method, we disable the level to - * prevent further events from coming in here. + * Dispatch the GPE to either an installed handler, or the control method + * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke + * it and do not attempt to run the method. If there is neither a handler + * nor a method, we disable this GPE to prevent further such pointless + * events from firing. */ switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { case ACPI_GPE_DISPATCH_HANDLER: @@ -677,8 +683,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) case ACPI_GPE_DISPATCH_METHOD: /* - * Disable GPE, so it doesn't keep firing before the method has a - * chance to run. + * Disable the GPE, so it doesn't keep firing before the method has a + * chance to run (it runs asynchronously with interrupts enabled). */ status = acpi_ev_disable_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { @@ -711,7 +717,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) gpe_number)); /* - * Disable the GPE. The GPE will remain disabled until the ACPI + * Disable the GPE. The GPE will remain disabled until the ACPI * Core Subsystem is restarted, or a handler is installed. */ status = acpi_ev_disable_gpe(gpe_event_info); @@ -726,50 +732,3 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) return_UINT32(ACPI_INTERRUPT_HANDLED); } - -#ifdef ACPI_GPE_NOTIFY_CHECK -/******************************************************************************* - * TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED - * - * FUNCTION: acpi_ev_check_for_wake_only_gpe - * - * PARAMETERS: gpe_event_info - info for this GPE - * - * RETURN: Status - * - * DESCRIPTION: Determine if a a GPE is "wake-only". - * - * Called from Notify() code in interpreter when a "DeviceWake" - * Notify comes in. - * - ******************************************************************************/ - -acpi_status -acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info) -{ - acpi_status status; - - ACPI_FUNCTION_TRACE(ev_check_for_wake_only_gpe); - - if ((gpe_event_info) && /* Only >0 for _Lxx/_Exx */ - ((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) { /* System state at GPE time */ - /* This must be a wake-only GPE, disable it */ - - status = acpi_ev_disable_gpe(gpe_event_info); - - /* Set GPE to wake-only. Do not change wake disabled/enabled status */ - - acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE); - - ACPI_INFO((AE_INFO, - "GPE %p was updated from wake/run to wake-only", - gpe_event_info)); - - /* This was a wake-only GPE */ - - return_ACPI_STATUS(AE_WAKE_ONLY_GPE); - } - - return_ACPI_STATUS(AE_OK); -} -#endif diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index 95ddeb48bc0f..ad5bc76edf46 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -529,7 +529,7 @@ static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 /* Install new interrupt handler if not SCI_INT */ - if (interrupt_number != acpi_gbl_FADT->sci_int) { + if (interrupt_number != acpi_gbl_FADT.sci_interrupt) { status = acpi_os_install_interrupt_handler(interrupt_number, acpi_ev_gpe_xrupt_handler, gpe_xrupt); @@ -567,7 +567,7 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt) /* We never want to remove the SCI interrupt handler */ - if (gpe_xrupt->interrupt_number == acpi_gbl_FADT->sci_int) { + if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) { gpe_xrupt->gpe_block_list_head = NULL; return_ACPI_STATUS(AE_OK); } @@ -796,30 +796,31 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) (u8) (gpe_block->block_base_number + (i * ACPI_GPE_REGISTER_WIDTH)); - ACPI_STORE_ADDRESS(this_register->status_address.address, - (gpe_block->block_address.address + i)); + this_register->status_address.address = + gpe_block->block_address.address + i; - ACPI_STORE_ADDRESS(this_register->enable_address.address, - (gpe_block->block_address.address - + i + gpe_block->register_count)); + this_register->enable_address.address = + gpe_block->block_address.address + i + + gpe_block->register_count; - this_register->status_address.address_space_id = - gpe_block->block_address.address_space_id; - this_register->enable_address.address_space_id = - gpe_block->block_address.address_space_id; - this_register->status_address.register_bit_width = + this_register->status_address.space_id = + gpe_block->block_address.space_id; + this_register->enable_address.space_id = + gpe_block->block_address.space_id; + this_register->status_address.bit_width = ACPI_GPE_REGISTER_WIDTH; - this_register->enable_address.register_bit_width = + this_register->enable_address.bit_width = ACPI_GPE_REGISTER_WIDTH; - this_register->status_address.register_bit_offset = + this_register->status_address.bit_offset = ACPI_GPE_REGISTER_WIDTH; - this_register->enable_address.register_bit_offset = + this_register->enable_address.bit_offset = ACPI_GPE_REGISTER_WIDTH; /* Init the event_info for each GPE within this register */ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { - this_event->register_bit = acpi_gbl_decode_to8bit[j]; + this_event->gpe_number = + (u8) (this_register->base_gpe_number + j); this_event->register_info = this_register; this_event++; } @@ -1109,11 +1110,12 @@ acpi_status acpi_ev_gpe_initialize(void) * If EITHER the register length OR the block address are zero, then that * particular block is not supported. */ - if (acpi_gbl_FADT->gpe0_blk_len && acpi_gbl_FADT->xgpe0_blk.address) { + if (acpi_gbl_FADT.gpe0_block_length && + acpi_gbl_FADT.xgpe0_block.address) { /* GPE block 0 exists (has both length and address > 0) */ - register_count0 = (u16) (acpi_gbl_FADT->gpe0_blk_len / 2); + register_count0 = (u16) (acpi_gbl_FADT.gpe0_block_length / 2); gpe_number_max = (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1; @@ -1121,9 +1123,9 @@ acpi_status acpi_ev_gpe_initialize(void) /* Install GPE Block 0 */ status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, - &acpi_gbl_FADT->xgpe0_blk, + &acpi_gbl_FADT.xgpe0_block, register_count0, 0, - acpi_gbl_FADT->sci_int, + acpi_gbl_FADT.sci_interrupt, &acpi_gbl_gpe_fadt_blocks[0]); if (ACPI_FAILURE(status)) { @@ -1132,20 +1134,21 @@ acpi_status acpi_ev_gpe_initialize(void) } } - if (acpi_gbl_FADT->gpe1_blk_len && acpi_gbl_FADT->xgpe1_blk.address) { + if (acpi_gbl_FADT.gpe1_block_length && + acpi_gbl_FADT.xgpe1_block.address) { /* GPE block 1 exists (has both length and address > 0) */ - register_count1 = (u16) (acpi_gbl_FADT->gpe1_blk_len / 2); + register_count1 = (u16) (acpi_gbl_FADT.gpe1_block_length / 2); /* Check for GPE0/GPE1 overlap (if both banks exist) */ if ((register_count0) && - (gpe_number_max >= acpi_gbl_FADT->gpe1_base)) { + (gpe_number_max >= acpi_gbl_FADT.gpe1_base)) { ACPI_ERROR((AE_INFO, "GPE0 block (GPE 0 to %d) overlaps the GPE1 block (GPE %d to %d) - Ignoring GPE1", - gpe_number_max, acpi_gbl_FADT->gpe1_base, - acpi_gbl_FADT->gpe1_base + + gpe_number_max, acpi_gbl_FADT.gpe1_base, + acpi_gbl_FADT.gpe1_base + ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1))); @@ -1157,10 +1160,11 @@ acpi_status acpi_ev_gpe_initialize(void) status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, - &acpi_gbl_FADT->xgpe1_blk, + &acpi_gbl_FADT.xgpe1_block, register_count1, - acpi_gbl_FADT->gpe1_base, - acpi_gbl_FADT->sci_int, + acpi_gbl_FADT.gpe1_base, + acpi_gbl_FADT. + sci_interrupt, &acpi_gbl_gpe_fadt_blocks [1]); @@ -1173,7 +1177,7 @@ acpi_status acpi_ev_gpe_initialize(void) * GPE0 and GPE1 do not have to be contiguous in the GPE number * space. However, GPE0 always starts at GPE number zero. */ - gpe_number_max = acpi_gbl_FADT->gpe1_base + + gpe_number_max = acpi_gbl_FADT.gpe1_base + ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1); } } diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index bf63edc6608d..1b784ffe54c3 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,14 +63,18 @@ static const char *acpi_notify_value_names[] = { }; #endif +/* Pointer to FACS needed for the Global Lock */ + +static struct acpi_table_facs *facs = NULL; + /* Local prototypes */ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context); -static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context); - static u32 acpi_ev_global_lock_handler(void *context); +static acpi_status acpi_ev_remove_global_lock_handler(void); + /******************************************************************************* * * FUNCTION: acpi_ev_is_notify_object @@ -280,51 +284,21 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context) acpi_ut_delete_generic_state(notify_info); } -/******************************************************************************* - * - * FUNCTION: acpi_ev_global_lock_thread - * - * PARAMETERS: Context - From thread interface, not used - * - * RETURN: None - * - * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the - * Global Lock. Simply signal all threads that are waiting - * for the lock. - * - ******************************************************************************/ - -static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context) -{ - acpi_status status; - - /* Signal threads that are waiting for the lock */ - - if (acpi_gbl_global_lock_thread_count) { - - /* Send sufficient units to the semaphore */ - - status = - acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, - acpi_gbl_global_lock_thread_count); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not signal Global Lock semaphore")); - } - } -} - /******************************************************************************* * * FUNCTION: acpi_ev_global_lock_handler * * PARAMETERS: Context - From thread interface, not used * - * RETURN: ACPI_INTERRUPT_HANDLED or ACPI_INTERRUPT_NOT_HANDLED + * RETURN: ACPI_INTERRUPT_HANDLED * * DESCRIPTION: Invoked directly from the SCI handler when a global lock - * release interrupt occurs. Grab the global lock and queue - * the global lock thread for execution + * release interrupt occurs. Attempt to acquire the global lock, + * if successful, signal the thread waiting for the lock. + * + * NOTE: Assumes that the semaphore can be signaled from interrupt level. If + * this is not possible for some reason, a separate thread will have to be + * scheduled to do this. * ******************************************************************************/ @@ -333,16 +307,24 @@ static u32 acpi_ev_global_lock_handler(void *context) u8 acquired = FALSE; /* - * Attempt to get the lock + * Attempt to get the lock. + * * If we don't get it now, it will be marked pending and we will * take another interrupt when it becomes free. */ - ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired); + ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired); if (acquired) { /* Got the lock, now wake all threads waiting for it */ + acpi_gbl_global_lock_acquired = TRUE; - acpi_ev_global_lock_thread(context); + /* Send a unit to the semaphore */ + + if (ACPI_FAILURE(acpi_os_signal_semaphore( + acpi_gbl_global_lock_semaphore, 1))) { + ACPI_ERROR((AE_INFO, + "Could not signal Global Lock semaphore")); + } } return (ACPI_INTERRUPT_HANDLED); @@ -366,6 +348,13 @@ acpi_status acpi_ev_init_global_lock_handler(void) ACPI_FUNCTION_TRACE(ev_init_global_lock_handler); + status = + acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + (struct acpi_table_header **)&facs); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + acpi_gbl_global_lock_present = TRUE; status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL, acpi_ev_global_lock_handler, @@ -389,6 +378,31 @@ acpi_status acpi_ev_init_global_lock_handler(void) return_ACPI_STATUS(status); } +/******************************************************************************* + * + * FUNCTION: acpi_ev_remove_global_lock_handler + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Remove the handler for the Global Lock + * + ******************************************************************************/ + +static acpi_status acpi_ev_remove_global_lock_handler(void) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler); + + acpi_gbl_global_lock_present = FALSE; + status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL, + acpi_ev_global_lock_handler); + + return_ACPI_STATUS(status); +} + /****************************************************************************** * * FUNCTION: acpi_ev_acquire_global_lock @@ -399,6 +413,16 @@ acpi_status acpi_ev_init_global_lock_handler(void) * * DESCRIPTION: Attempt to gain ownership of the Global Lock. * + * MUTEX: Interpreter must be locked + * + * Note: The original implementation allowed multiple threads to "acquire" the + * Global Lock, and the OS would hold the lock until the last thread had + * released it. However, this could potentially starve the BIOS out of the + * lock, especially in the case where there is a tight handshake between the + * Embedded Controller driver and the BIOS. Therefore, this implementation + * allows only one thread to acquire the HW Global Lock at a time, and makes + * the global lock appear as a standard mutex on the OS side. + * *****************************************************************************/ acpi_status acpi_ev_acquire_global_lock(u16 timeout) @@ -408,53 +432,51 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) ACPI_FUNCTION_TRACE(ev_acquire_global_lock); -#ifndef ACPI_APPLICATION - /* Make sure that we actually have a global lock */ - - if (!acpi_gbl_global_lock_present) { - return_ACPI_STATUS(AE_NO_GLOBAL_LOCK); + /* + * Only one thread can acquire the GL at a time, the global_lock_mutex + * enforces this. This interface releases the interpreter if we must wait. + */ + status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); } -#endif - - /* One more thread wants the global lock */ - - acpi_gbl_global_lock_thread_count++; /* - * If we (OS side vs. BIOS side) have the hardware lock already, - * we are done + * Make sure that a global lock actually exists. If not, just treat + * the lock as a standard mutex. */ - if (acpi_gbl_global_lock_acquired) { + if (!acpi_gbl_global_lock_present) { + acpi_gbl_global_lock_acquired = TRUE; return_ACPI_STATUS(AE_OK); } - /* We must acquire the actual hardware lock */ + /* Attempt to acquire the actual hardware lock */ - ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired); + ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired); if (acquired) { /* We got the lock */ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Acquired the HW Global Lock\n")); + "Acquired hardware Global Lock\n")); acpi_gbl_global_lock_acquired = TRUE; return_ACPI_STATUS(AE_OK); } /* - * Did not get the lock. The pending bit was set above, and we must now + * Did not get the lock. The pending bit was set above, and we must now * wait until we get the global lock released interrupt. */ - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for the HW Global Lock\n")); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n")); /* - * Acquire the global lock semaphore first. - * Since this wait will block, we must release the interpreter + * Wait for handshake with the global lock interrupt handler. + * This interface releases the interpreter if we must wait. */ - status = - acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore, - timeout); + status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore, + ACPI_WAIT_FOREVER); + return_ACPI_STATUS(status); } @@ -477,38 +499,39 @@ acpi_status acpi_ev_release_global_lock(void) ACPI_FUNCTION_TRACE(ev_release_global_lock); - if (!acpi_gbl_global_lock_thread_count) { + /* Lock must be already acquired */ + + if (!acpi_gbl_global_lock_acquired) { ACPI_WARNING((AE_INFO, - "Cannot release HW Global Lock, it has not been acquired")); + "Cannot release the ACPI Global Lock, it has not been acquired")); return_ACPI_STATUS(AE_NOT_ACQUIRED); } - /* One fewer thread has the global lock */ + if (acpi_gbl_global_lock_present) { - acpi_gbl_global_lock_thread_count--; - if (acpi_gbl_global_lock_thread_count) { + /* Allow any thread to release the lock */ - /* There are still some threads holding the lock, cannot release */ + ACPI_RELEASE_GLOBAL_LOCK(facs, pending); - return_ACPI_STATUS(AE_OK); + /* + * If the pending bit was set, we must write GBL_RLS to the control + * register + */ + if (pending) { + status = + acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE, + 1); + } + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Released hardware Global Lock\n")); } - /* - * No more threads holding lock, we can do the actual hardware - * release - */ - ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, pending); acpi_gbl_global_lock_acquired = FALSE; - /* - * If the pending bit was set, we must write GBL_RLS to the control - * register - */ - if (pending) { - status = acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE, - 1, ACPI_MTX_LOCK); - } + /* Release the local GL mutex */ + acpi_os_release_mutex(acpi_gbl_global_lock_mutex); return_ACPI_STATUS(status); } @@ -558,6 +581,12 @@ void acpi_ev_terminate(void) if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not remove SCI handler")); } + + status = acpi_ev_remove_global_lock_handler(); + if (ACPI_FAILURE(status)) { + ACPI_ERROR((AE_INFO, + "Could not remove Global Lock handler")); + } } /* Deallocate all handler objects installed within GPE info structs */ diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c index 21caae04fe85..e99f0c435a47 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/events/evregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -291,7 +291,6 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, u32 bit_width, acpi_integer * value) { acpi_status status; - acpi_status status2; acpi_adr_space_handler handler; acpi_adr_space_setup region_setup; union acpi_operand_object *handler_desc; @@ -345,7 +344,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, * setup will potentially execute control methods * (e.g., _REG method for this region) */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); status = region_setup(region_obj, ACPI_REGION_ACTIVATE, handler_desc->address_space.context, @@ -353,10 +352,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, /* Re-enter the interpreter */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } + acpi_ex_reacquire_interpreter(); /* Check for failure of the Region Setup */ @@ -409,7 +405,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, * exit the interpreter because the handler *might* block -- we don't * know what it will do, so we can't hold the lock on the intepreter. */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); } /* Call the handler */ @@ -430,10 +426,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, * We just returned from a non-default handler, we must re-enter the * interpreter */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } + acpi_ex_reacquire_interpreter(); } return_ACPI_STATUS(status); diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index 203d1359190a..a4fa7e6822a3 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,6 +48,11 @@ #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evrgnini") +/* Local prototypes */ +static u8 acpi_ev_match_pci_root_bridge(char *id); + +static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node); + /******************************************************************************* * * FUNCTION: acpi_ev_system_memory_region_setup @@ -62,6 +67,7 @@ ACPI_MODULE_NAME("evrgnini") * DESCRIPTION: Setup a system_memory operation region * ******************************************************************************/ + acpi_status acpi_ev_system_memory_region_setup(acpi_handle handle, u32 function, @@ -168,9 +174,9 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, union acpi_operand_object *handler_obj; struct acpi_namespace_node *parent_node; struct acpi_namespace_node *pci_root_node; + struct acpi_namespace_node *pci_device_node; union acpi_operand_object *region_obj = (union acpi_operand_object *)handle; - struct acpi_device_id object_hID; ACPI_FUNCTION_TRACE(ev_pci_config_region_setup); @@ -215,45 +221,30 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, pci_root_node = parent_node; while (pci_root_node != acpi_gbl_root_node) { - status = - acpi_ut_execute_HID(pci_root_node, &object_hID); - if (ACPI_SUCCESS(status)) { - /* - * Got a valid _HID string, check if this is a PCI root. - * New for ACPI 3.0: check for a PCI Express root also. - */ - if (! - (ACPI_STRNCMP - (object_hID.value, PCI_ROOT_HID_STRING, - sizeof(PCI_ROOT_HID_STRING))) - || - !(ACPI_STRNCMP - (object_hID.value, - PCI_EXPRESS_ROOT_HID_STRING, - sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) { - /* Install a handler for this PCI root bridge */ + /* Get the _HID/_CID in order to detect a root_bridge */ - status = - acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); - if (ACPI_FAILURE(status)) { - if (status == AE_SAME_HANDLER) { - /* - * It is OK if the handler is already installed on the root - * bridge. Still need to return a context object for the - * new PCI_Config operation region, however. - */ - status = AE_OK; - } else { - ACPI_EXCEPTION((AE_INFO, - status, - "Could not install PciConfig handler for Root Bridge %4.4s", - acpi_ut_get_node_name - (pci_root_node))); - } + if (acpi_ev_is_pci_root_bridge(pci_root_node)) { + + /* Install a handler for this PCI root bridge */ + + status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); + if (ACPI_FAILURE(status)) { + if (status == AE_SAME_HANDLER) { + /* + * It is OK if the handler is already installed on the root + * bridge. Still need to return a context object for the + * new PCI_Config operation region, however. + */ + status = AE_OK; + } else { + ACPI_EXCEPTION((AE_INFO, status, + "Could not install PciConfig handler for Root Bridge %4.4s", + acpi_ut_get_node_name + (pci_root_node))); } - break; } + break; } pci_root_node = acpi_ns_get_parent_node(pci_root_node); @@ -282,14 +273,25 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, /* * For PCI_Config space access, we need the segment, bus, * device and function numbers. Acquire them here. + * + * Find the parent device object. (This allows the operation region to be + * within a subscope under the device, such as a control method.) */ + pci_device_node = region_obj->region.node; + while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) { + pci_device_node = acpi_ns_get_parent_node(pci_device_node); + } + + if (!pci_device_node) { + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); + } /* * Get the PCI device and function numbers from the _ADR object * contained in the parent's scope. */ status = - acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, parent_node, + acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, pci_device_node, &pci_value); /* @@ -327,6 +329,91 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, return_ACPI_STATUS(AE_OK); } +/******************************************************************************* + * + * FUNCTION: acpi_ev_match_pci_root_bridge + * + * PARAMETERS: Id - The HID/CID in string format + * + * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge + * + * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID. + * + ******************************************************************************/ + +static u8 acpi_ev_match_pci_root_bridge(char *id) +{ + + /* + * Check if this is a PCI root. + * ACPI 3.0+: check for a PCI Express root also. + */ + if (!(ACPI_STRNCMP(id, + PCI_ROOT_HID_STRING, + sizeof(PCI_ROOT_HID_STRING))) || + !(ACPI_STRNCMP(id, + PCI_EXPRESS_ROOT_HID_STRING, + sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) { + return (TRUE); + } + + return (FALSE); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ev_is_pci_root_bridge + * + * PARAMETERS: Node - Device node being examined + * + * RETURN: TRUE if device is a PCI/PCI-Express Root Bridge + * + * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by + * examining the _HID and _CID for the device. + * + ******************************************************************************/ + +static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) +{ + acpi_status status; + struct acpi_device_id hid; + struct acpi_compatible_id_list *cid; + acpi_native_uint i; + + /* + * Get the _HID and check for a PCI Root Bridge + */ + status = acpi_ut_execute_HID(node, &hid); + if (ACPI_FAILURE(status)) { + return (FALSE); + } + + if (acpi_ev_match_pci_root_bridge(hid.value)) { + return (TRUE); + } + + /* + * The _HID did not match. + * Get the _CID and check for a PCI Root Bridge + */ + status = acpi_ut_execute_CID(node, &cid); + if (ACPI_FAILURE(status)) { + return (FALSE); + } + + /* Check all _CIDs in the returned list */ + + for (i = 0; i < cid->count; i++) { + if (acpi_ev_match_pci_root_bridge(cid->id[i].value)) { + ACPI_FREE(cid); + return (TRUE); + } + } + + ACPI_FREE(cid); + return (FALSE); +} + /******************************************************************************* * * FUNCTION: acpi_ev_pci_bar_region_setup @@ -432,6 +519,9 @@ acpi_ev_default_region_setup(acpi_handle handle, * a PCI address in the scope of the definition. This address is * required to perform an access to PCI config space. * + * MUTEX: Interpreter should be unlocked, because we may run the _REG + * method for this region. + * ******************************************************************************/ acpi_status diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c index 8106215ad554..7e5d15ce2395 100644 --- a/drivers/acpi/events/evsci.c +++ b/drivers/acpi/events/evsci.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -142,9 +142,10 @@ u32 acpi_ev_install_sci_handler(void) ACPI_FUNCTION_TRACE(ev_install_sci_handler); - status = acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT->sci_int, - acpi_ev_sci_xrupt_handler, - acpi_gbl_gpe_xrupt_list_head); + status = + acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt, + acpi_ev_sci_xrupt_handler, + acpi_gbl_gpe_xrupt_list_head); return_ACPI_STATUS(status); } @@ -175,8 +176,9 @@ acpi_status acpi_ev_remove_sci_handler(void) /* Just let the OS remove the handler and disable the level */ - status = acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT->sci_int, - acpi_ev_sci_xrupt_handler); + status = + acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt, + acpi_ev_sci_xrupt_handler); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c index 923fd2b46955..685a103a3587 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/events/evxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -768,11 +768,9 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle) return (AE_BAD_PARAMETER); } - status = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status)) { - return (status); - } + /* Must lock interpreter to prevent race conditions */ + acpi_ex_enter_interpreter(); status = acpi_ev_acquire_global_lock(timeout); acpi_ex_exit_interpreter(); diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c index 7ebc2efac936..17065e98807c 100644 --- a/drivers/acpi/events/evxfevnt.c +++ b/drivers/acpi/events/evxfevnt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,6 +44,7 @@ #include #include #include +#include #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evxfevnt") @@ -65,13 +66,14 @@ acpi_status acpi_enable(void) ACPI_FUNCTION_TRACE(acpi_enable); - /* Make sure we have the FADT */ + /* ACPI tables must be present */ - if (!acpi_gbl_FADT) { - ACPI_WARNING((AE_INFO, "No FADT information present!")); + if (!acpi_tb_tables_loaded()) { return_ACPI_STATUS(AE_NO_ACPI_TABLES); } + /* Check current mode */ + if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) { ACPI_DEBUG_PRINT((ACPI_DB_INIT, "System is already in ACPI mode\n")); @@ -111,11 +113,6 @@ acpi_status acpi_disable(void) ACPI_FUNCTION_TRACE(acpi_disable); - if (!acpi_gbl_FADT) { - ACPI_WARNING((AE_INFO, "No FADT information present!")); - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) { ACPI_DEBUG_PRINT((ACPI_DB_INIT, "System is already in legacy (non-ACPI) mode\n")); @@ -169,7 +166,7 @@ acpi_status acpi_enable_event(u32 event, u32 flags) */ status = acpi_set_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, 1, ACPI_MTX_LOCK); + enable_register_id, 1); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -178,7 +175,7 @@ acpi_status acpi_enable_event(u32 event, u32 flags) status = acpi_get_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, &value, ACPI_MTX_LOCK); + enable_register_id, &value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -368,14 +365,14 @@ acpi_status acpi_disable_event(u32 event, u32 flags) */ status = acpi_set_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, 0, ACPI_MTX_LOCK); + enable_register_id, 0); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } status = acpi_get_register(acpi_gbl_fixed_event_info[event]. - enable_register_id, &value, ACPI_MTX_LOCK); + enable_register_id, &value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -421,7 +418,7 @@ acpi_status acpi_clear_event(u32 event) */ status = acpi_set_register(acpi_gbl_fixed_event_info[event]. - status_register_id, 1, ACPI_MTX_LOCK); + status_register_id, 1); return_ACPI_STATUS(status); } @@ -510,7 +507,7 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status) status = acpi_get_register(acpi_gbl_fixed_event_info[event]. - status_register_id, event_status, ACPI_MTX_LOCK); + status_register_id, event_status); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c index 83b12a9afa32..7bf09c5fb242 100644 --- a/drivers/acpi/events/evxfregn.c +++ b/drivers/acpi/events/evxfregn.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index c8341fa5fe01..25802f302ffe 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,7 +54,7 @@ ACPI_MODULE_NAME("exconfig") /* Local prototypes */ static acpi_status -acpi_ex_add_table(struct acpi_table_header *table, +acpi_ex_add_table(acpi_native_uint table_index, struct acpi_namespace_node *parent_node, union acpi_operand_object **ddb_handle); @@ -74,12 +74,11 @@ acpi_ex_add_table(struct acpi_table_header *table, ******************************************************************************/ static acpi_status -acpi_ex_add_table(struct acpi_table_header *table, +acpi_ex_add_table(acpi_native_uint table_index, struct acpi_namespace_node *parent_node, union acpi_operand_object **ddb_handle) { acpi_status status; - struct acpi_table_desc table_info; union acpi_operand_object *obj_desc; ACPI_FUNCTION_TRACE(ex_add_table); @@ -98,42 +97,16 @@ acpi_ex_add_table(struct acpi_table_header *table, /* Install the new table into the local data structures */ - ACPI_MEMSET(&table_info, 0, sizeof(struct acpi_table_desc)); - - table_info.type = ACPI_TABLE_ID_SSDT; - table_info.pointer = table; - table_info.length = (acpi_size) table->length; - table_info.allocation = ACPI_MEM_ALLOCATED; - - status = acpi_tb_install_table(&table_info); - obj_desc->reference.object = table_info.installed_desc; - - if (ACPI_FAILURE(status)) { - if (status == AE_ALREADY_EXISTS) { - - /* Table already exists, just return the handle */ - - return_ACPI_STATUS(AE_OK); - } - goto cleanup; - } + obj_desc->reference.object = ACPI_CAST_PTR(void, table_index); /* Add the table to the namespace */ - status = acpi_ns_load_table(table_info.installed_desc, parent_node); + status = acpi_ns_load_table(table_index, parent_node); if (ACPI_FAILURE(status)) { - - /* Uninstall table on error */ - - (void)acpi_tb_uninstall_table(table_info.installed_desc); - goto cleanup; + acpi_ut_remove_reference(obj_desc); + *ddb_handle = NULL; } - return_ACPI_STATUS(AE_OK); - - cleanup: - acpi_ut_remove_reference(obj_desc); - *ddb_handle = NULL; return_ACPI_STATUS(status); } @@ -146,7 +119,7 @@ acpi_ex_add_table(struct acpi_table_header *table, * * RETURN: Status * - * DESCRIPTION: Load an ACPI table + * DESCRIPTION: Load an ACPI table from the RSDT/XSDT * ******************************************************************************/ @@ -156,33 +129,20 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, { acpi_status status; union acpi_operand_object **operand = &walk_state->operands[0]; - struct acpi_table_header *table; + acpi_native_uint table_index; struct acpi_namespace_node *parent_node; struct acpi_namespace_node *start_node; struct acpi_namespace_node *parameter_node = NULL; union acpi_operand_object *ddb_handle; + struct acpi_table_header *table; ACPI_FUNCTION_TRACE(ex_load_table_op); -#if 0 - /* - * Make sure that the signature does not match one of the tables that - * is already loaded. - */ - status = acpi_tb_match_signature(operand[0]->string.pointer, NULL); - if (status == AE_OK) { - - /* Signature matched -- don't allow override */ - - return_ACPI_STATUS(AE_ALREADY_EXISTS); - } -#endif - - /* Find the ACPI table */ + /* Find the ACPI table in the RSDT/XSDT */ status = acpi_tb_find_table(operand[0]->string.pointer, operand[1]->string.pointer, - operand[2]->string.pointer, &table); + operand[2]->string.pointer, &table_index); if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) { return_ACPI_STATUS(status); @@ -245,7 +205,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, /* Load the table into the namespace */ - status = acpi_ex_add_table(table, parent_node, &ddb_handle); + status = acpi_ex_add_table(table_index, parent_node, &ddb_handle); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -266,9 +226,13 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, } } - ACPI_INFO((AE_INFO, - "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]", - table->signature, table->oem_id, table->oem_table_id)); + status = acpi_get_table_by_index(table_index, &table); + if (ACPI_SUCCESS(status)) { + ACPI_INFO((AE_INFO, + "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]", + table->signature, table->oem_id, + table->oem_table_id)); + } *return_desc = ddb_handle; return_ACPI_STATUS(status); @@ -278,7 +242,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, * * FUNCTION: acpi_ex_load_op * - * PARAMETERS: obj_desc - Region or Field where the table will be + * PARAMETERS: obj_desc - Region or Buffer/Field where the table will be * obtained * Target - Where a handle to the table will be stored * walk_state - Current state @@ -287,6 +251,12 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, * * DESCRIPTION: Load an ACPI table from a field or operation region * + * NOTE: Region Fields (Field, bank_field, index_fields) are resolved to buffer + * objects before this code is reached. + * + * If source is an operation region, it must refer to system_memory, as + * per the ACPI specification. + * ******************************************************************************/ acpi_status @@ -294,22 +264,26 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, union acpi_operand_object *target, struct acpi_walk_state *walk_state) { - acpi_status status; union acpi_operand_object *ddb_handle; - union acpi_operand_object *buffer_desc = NULL; - struct acpi_table_header *table_ptr = NULL; - acpi_physical_address address; - struct acpi_table_header table_header; - acpi_integer temp; - u32 i; + struct acpi_table_desc table_desc; + acpi_native_uint table_index; + acpi_status status; ACPI_FUNCTION_TRACE(ex_load_op); - /* Object can be either an op_region or a Field */ + ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc)); + + /* Source Object can be either an op_region or a Buffer/Field */ switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { case ACPI_TYPE_REGION: + /* Region must be system_memory (from ACPI spec) */ + + if (obj_desc->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) { + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); + } + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n", obj_desc, acpi_ut_get_object_type_name(obj_desc))); @@ -325,113 +299,41 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, } } - /* Get the base physical address of the region */ - - address = obj_desc->region.address; - - /* Get part of the table header to get the table length */ - - table_header.length = 0; - for (i = 0; i < 8; i++) { - status = - acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, - (acpi_physical_address) - (i + address), 8, - &temp); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Get the one valid byte of the returned 64-bit value */ - - ACPI_CAST_PTR(u8, &table_header)[i] = (u8) temp; - } - - /* Sanity check the table length */ - - if (table_header.length < sizeof(struct acpi_table_header)) { - return_ACPI_STATUS(AE_BAD_HEADER); - } - - /* Allocate a buffer for the entire table */ - - table_ptr = ACPI_ALLOCATE(table_header.length); - if (!table_ptr) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* Get the entire table from the op region */ - - for (i = 0; i < table_header.length; i++) { - status = - acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, - (acpi_physical_address) - (i + address), 8, - &temp); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - /* Get the one valid byte of the returned 64-bit value */ - - ACPI_CAST_PTR(u8, table_ptr)[i] = (u8) temp; - } + table_desc.address = obj_desc->region.address; + table_desc.length = obj_desc->region.length; + table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED; break; - case ACPI_TYPE_LOCAL_REGION_FIELD: - case ACPI_TYPE_LOCAL_BANK_FIELD: - case ACPI_TYPE_LOCAL_INDEX_FIELD: + case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */ - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Field %p %s\n", - obj_desc, + /* Simply extract the buffer from the buffer object */ + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Load from Buffer or Field %p %s\n", obj_desc, acpi_ut_get_object_type_name(obj_desc))); - /* - * The length of the field must be at least as large as the table. - * Read the entire field and thus the entire table. Buffer is - * allocated during the read. - */ - status = - acpi_ex_read_data_from_field(walk_state, obj_desc, - &buffer_desc); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + table_desc.pointer = ACPI_CAST_PTR(struct acpi_table_header, + obj_desc->buffer.pointer); + table_desc.length = table_desc.pointer->length; + table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED; - table_ptr = ACPI_CAST_PTR(struct acpi_table_header, - buffer_desc->buffer.pointer); - - /* All done with the buffer_desc, delete it */ - - buffer_desc->buffer.pointer = NULL; - acpi_ut_remove_reference(buffer_desc); - - /* Sanity check the table length */ - - if (table_ptr->length < sizeof(struct acpi_table_header)) { - status = AE_BAD_HEADER; - goto cleanup; - } + obj_desc->buffer.pointer = NULL; break; default: return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } - /* The table must be either an SSDT or a PSDT */ - - if ((!ACPI_COMPARE_NAME(table_ptr->signature, PSDT_SIG)) && - (!ACPI_COMPARE_NAME(table_ptr->signature, SSDT_SIG))) { - ACPI_ERROR((AE_INFO, - "Table has invalid signature [%4.4s], must be SSDT or PSDT", - table_ptr->signature)); - status = AE_BAD_SIGNATURE; + /* + * Install the new table into the local data structures + */ + status = acpi_tb_add_table(&table_desc, &table_index); + if (ACPI_FAILURE(status)) { goto cleanup; } - /* Install the new table into the local data structures */ - - status = acpi_ex_add_table(table_ptr, acpi_gbl_root_node, &ddb_handle); + status = + acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle); if (ACPI_FAILURE(status)) { /* On error, table_ptr was deallocated above */ @@ -450,13 +352,9 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, return_ACPI_STATUS(status); } - ACPI_INFO((AE_INFO, - "Dynamic SSDT Load - OemId [%6.6s] OemTableId [%8.8s]", - table_ptr->oem_id, table_ptr->oem_table_id)); - cleanup: if (ACPI_FAILURE(status)) { - ACPI_FREE(table_ptr); + acpi_tb_delete_table(&table_desc); } return_ACPI_STATUS(status); } @@ -477,7 +375,7 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) { acpi_status status = AE_OK; union acpi_operand_object *table_desc = ddb_handle; - struct acpi_table_desc *table_info; + acpi_native_uint table_index; ACPI_FUNCTION_TRACE(ex_unload_table); @@ -493,19 +391,18 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Get the actual table descriptor from the ddb_handle */ + /* Get the table index from the ddb_handle */ - table_info = (struct acpi_table_desc *)table_desc->reference.object; + table_index = (acpi_native_uint) table_desc->reference.object; /* * Delete the entire namespace under this table Node * (Offset contains the table_id) */ - acpi_ns_delete_namespace_by_owner(table_info->owner_id); + acpi_tb_delete_namespace_by_owner(table_index); + acpi_tb_release_owner_id(table_index); - /* Delete the table itself */ - - (void)acpi_tb_uninstall_table(table_info->installed_desc); + acpi_tb_set_table_loaded_flag(table_index, FALSE); /* Delete the table descriptor (ddb_handle) */ diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c index 544e81a6a438..d470e8b1f4ea 100644 --- a/drivers/acpi/executer/exconvrt.c +++ b/drivers/acpi/executer/exconvrt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c index 34eec82c1b1e..7c38528a7e83 100644 --- a/drivers/acpi/executer/excreate.c +++ b/drivers/acpi/executer/excreate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -359,8 +359,9 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state) union acpi_operand_object **operand = &walk_state->operands[0]; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; - struct acpi_table_header *table; union acpi_operand_object *region_obj2; + acpi_native_uint table_index; + struct acpi_table_header *table; ACPI_FUNCTION_TRACE(ex_create_table_region); @@ -380,7 +381,7 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state) status = acpi_tb_find_table(operand[1]->string.pointer, operand[2]->string.pointer, - operand[3]->string.pointer, &table); + operand[3]->string.pointer, &table_index); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -395,6 +396,11 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state) region_obj2 = obj_desc->common.next_object; region_obj2->extra.region_context = NULL; + status = acpi_get_table_by_index(table_index, &table); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + /* Init the region from the operands */ obj_desc->region.space_id = REGION_DATA_TABLE; @@ -553,7 +559,8 @@ acpi_ex_create_method(u8 * aml_start, obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); if (!obj_desc) { - return_ACPI_STATUS(AE_NO_MEMORY); + status = AE_NO_MEMORY; + goto exit; } /* Save the method's AML pointer and length */ @@ -576,10 +583,7 @@ acpi_ex_create_method(u8 * aml_start, * Get the sync_level. If method is serialized, a mutex will be * created for this method when it is parsed. */ - if (acpi_gbl_all_methods_serialized) { - obj_desc->method.sync_level = 0; - obj_desc->method.method_flags |= AML_METHOD_SERIALIZED; - } else if (method_flags & AML_METHOD_SERIALIZED) { + if (method_flags & AML_METHOD_SERIALIZED) { /* * ACPI 1.0: sync_level = 0 * ACPI 2.0: sync_level = sync_level in method declaration @@ -597,6 +601,7 @@ acpi_ex_create_method(u8 * aml_start, acpi_ut_remove_reference(obj_desc); + exit: /* Remove a reference to the operand */ acpi_ut_remove_reference(operand[1]); diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c index 2450943add33..68d283fd60e7 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/executer/exdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -59,8 +59,6 @@ static void acpi_ex_out_string(char *title, char *value); static void acpi_ex_out_pointer(char *title, void *value); -static void acpi_ex_out_address(char *title, acpi_physical_address value); - static void acpi_ex_dump_object(union acpi_operand_object *obj_desc, struct acpi_exdump_info *info); @@ -92,10 +90,11 @@ static struct acpi_exdump_info acpi_ex_dump_string[4] = { {ACPI_EXD_STRING, 0, NULL} }; -static struct acpi_exdump_info acpi_ex_dump_buffer[4] = { +static struct acpi_exdump_info acpi_ex_dump_buffer[5] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_buffer), NULL}, {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(buffer.length), "Length"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.pointer), "Pointer"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.node), "Parent Node"}, {ACPI_EXD_BUFFER, 0, NULL} }; @@ -165,8 +164,8 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = { static struct acpi_exdump_info acpi_ex_dump_processor[7] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_processor), NULL}, - {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"}, - {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.length), "Length"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.length), "Length"}, {ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(processor.address), "Address"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.system_notify), "System Notify"}, @@ -379,18 +378,12 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc, break; case ACPI_EXD_POINTER: + case ACPI_EXD_ADDRESS: acpi_ex_out_pointer(name, *ACPI_CAST_PTR(void *, target)); break; - case ACPI_EXD_ADDRESS: - - acpi_ex_out_address(name, - *ACPI_CAST_PTR - (acpi_physical_address, target)); - break; - case ACPI_EXD_STRING: acpi_ut_print_string(obj_desc->string.pointer, @@ -834,16 +827,6 @@ static void acpi_ex_out_pointer(char *title, void *value) acpi_os_printf("%20s : %p\n", title, value); } -static void acpi_ex_out_address(char *title, acpi_physical_address value) -{ - -#if ACPI_MACHINE_WIDTH == 16 - acpi_os_printf("%20s : %p\n", title, value); -#else - acpi_os_printf("%20s : %8.8X%8.8X\n", title, ACPI_FORMAT_UINT64(value)); -#endif -} - /******************************************************************************* * * FUNCTION: acpi_ex_dump_namespace_node diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c index 9ea9c3a67ca9..2d88a3d8d1ad 100644 --- a/drivers/acpi/executer/exfield.c +++ b/drivers/acpi/executer/exfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c index 40f0bee6faa5..65a48b6170ee 100644 --- a/drivers/acpi/executer/exfldio.c +++ b/drivers/acpi/executer/exfldio.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -257,14 +257,13 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, } ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD, - " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n", + " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n", acpi_ut_get_region_name(rgn_desc->region. space_id), rgn_desc->region.space_id, obj_desc->common_field.access_byte_width, obj_desc->common_field.base_byte_offset, - field_datum_byte_offset, - ACPI_FORMAT_UINT64(address))); + field_datum_byte_offset, (void *)address)); /* Invoke the appropriate address_space/op_region handler */ diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c index bd98aab017cf..f13d1cec2d6d 100644 --- a/drivers/acpi/executer/exmisc.c +++ b/drivers/acpi/executer/exmisc.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c index bf90f04f2c60..5101bad5baf8 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/executer/exmutex.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,6 +44,7 @@ #include #include +#include #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exmutex") @@ -150,7 +151,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Sanity check -- we must have a valid thread ID */ + /* Sanity check: we must have a valid thread ID */ if (!walk_state->thread) { ACPI_ERROR((AE_INFO, @@ -174,24 +175,28 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, /* Support for multiple acquires by the owning thread */ if (obj_desc->mutex.owner_thread) { - - /* Special case for Global Lock, allow all threads */ - - if ((obj_desc->mutex.owner_thread->thread_id == - walk_state->thread->thread_id) || - (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK)) { + if (obj_desc->mutex.owner_thread->thread_id == + walk_state->thread->thread_id) { /* - * The mutex is already owned by this thread, - * just increment the acquisition depth + * The mutex is already owned by this thread, just increment the + * acquisition depth */ obj_desc->mutex.acquisition_depth++; return_ACPI_STATUS(AE_OK); } } - /* Acquire the mutex, wait if necessary */ + /* Acquire the mutex, wait if necessary. Special case for Global Lock */ + + if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) { + status = + acpi_ev_acquire_global_lock((u16) time_desc->integer.value); + } else { + status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex, + (u16) time_desc->integer. + value); + } - status = acpi_ex_system_acquire_mutex(time_desc, obj_desc); if (ACPI_FAILURE(status)) { /* Includes failure from a timeout on time_desc */ @@ -211,7 +216,6 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, /* Link the mutex to the current thread for force-unlock at method exit */ acpi_ex_link_mutex(obj_desc, walk_state->thread); - return_ACPI_STATUS(AE_OK); } @@ -232,7 +236,7 @@ acpi_status acpi_ex_release_mutex(union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { - acpi_status status; + acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(ex_release_mutex); @@ -249,7 +253,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED); } - /* Sanity check -- we must have a valid thread ID */ + /* Sanity check: we must have a valid thread ID */ if (!walk_state->thread) { ACPI_ERROR((AE_INFO, @@ -264,7 +268,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, */ if ((obj_desc->mutex.owner_thread->thread_id != walk_state->thread->thread_id) - && (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) { + && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) { ACPI_ERROR((AE_INFO, "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", (unsigned long)walk_state->thread->thread_id, @@ -274,8 +278,8 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, } /* - * The sync level of the mutex must be less than or - * equal to the current sync level + * The sync level of the mutex must be less than or equal to the current + * sync level */ if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { ACPI_ERROR((AE_INFO, @@ -298,11 +302,15 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, acpi_ex_unlink_mutex(obj_desc); - /* Release the mutex */ + /* Release the mutex, special case for Global Lock */ - status = acpi_ex_system_release_mutex(obj_desc); + if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) { + status = acpi_ev_release_global_lock(); + } else { + acpi_os_release_mutex(obj_desc->mutex.os_mutex); + } - /* Update the mutex and walk state, restore sync_level before acquire */ + /* Update the mutex and restore sync_level */ obj_desc->mutex.owner_thread = NULL; walk_state->thread->current_sync_level = @@ -321,39 +329,49 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, * * DESCRIPTION: Release all mutexes held by this thread * + * NOTE: This function is called as the thread is exiting the interpreter. + * Mutexes are not released when an individual control method is exited, but + * only when the parent thread actually exits the interpreter. This allows one + * method to acquire a mutex, and a different method to release it, as long as + * this is performed underneath a single parent control method. + * ******************************************************************************/ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) { union acpi_operand_object *next = thread->acquired_mutex_list; - union acpi_operand_object *this; - acpi_status status; + union acpi_operand_object *obj_desc; ACPI_FUNCTION_ENTRY(); /* Traverse the list of owned mutexes, releasing each one */ while (next) { - this = next; - next = this->mutex.next; + obj_desc = next; + next = obj_desc->mutex.next; - this->mutex.acquisition_depth = 1; - this->mutex.prev = NULL; - this->mutex.next = NULL; + obj_desc->mutex.prev = NULL; + obj_desc->mutex.next = NULL; + obj_desc->mutex.acquisition_depth = 0; - /* Release the mutex */ + /* Release the mutex, special case for Global Lock */ - status = acpi_ex_system_release_mutex(this); - if (ACPI_FAILURE(status)) { - continue; + if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) { + + /* Ignore errors */ + + (void)acpi_ev_release_global_lock(); + } else { + acpi_os_release_mutex(obj_desc->mutex.os_mutex); } /* Mark mutex unowned */ - this->mutex.owner_thread = NULL; + obj_desc->mutex.owner_thread = NULL; /* Update Thread sync_level (Last mutex is the important one) */ - thread->current_sync_level = this->mutex.original_sync_level; + thread->current_sync_level = + obj_desc->mutex.original_sync_level; } } diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c index d3d70364626c..1ee4fb1175c6 100644 --- a/drivers/acpi/executer/exnames.c +++ b/drivers/acpi/executer/exnames.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c index 6374d8be88e0..252f10acbbcc 100644 --- a/drivers/acpi/executer/exoparg1.c +++ b/drivers/acpi/executer/exoparg1.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -104,9 +104,7 @@ acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state) status = AE_NO_MEMORY; goto cleanup; } -#if ACPI_MACHINE_WIDTH != 16 return_desc->integer.value = acpi_os_get_timer(); -#endif break; default: /* Unknown opcode */ diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c index 7d2cbc113160..17e652e65379 100644 --- a/drivers/acpi/executer/exoparg2.c +++ b/drivers/acpi/executer/exoparg2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c index e2d945dfd509..7fe67cf82cee 100644 --- a/drivers/acpi/executer/exoparg3.c +++ b/drivers/acpi/executer/exoparg3.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c index f0c0ba6eb408..bd80a9cb3d65 100644 --- a/drivers/acpi/executer/exoparg6.c +++ b/drivers/acpi/executer/exoparg6.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c index 44d064f427b9..a6696621ff1b 100644 --- a/drivers/acpi/executer/exprep.c +++ b/drivers/acpi/executer/exprep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c index 3cc97ba48b36..2e9ce94798c7 100644 --- a/drivers/acpi/executer/exregion.c +++ b/drivers/acpi/executer/exregion.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -155,16 +155,15 @@ acpi_ex_system_memory_space_handler(u32 function, /* Create a new mapping starting at the address given */ - status = acpi_os_map_memory(address, window_size, - (void **)&mem_info-> - mapped_logical_address); - if (ACPI_FAILURE(status)) { + mem_info->mapped_logical_address = + acpi_os_map_memory((acpi_native_uint) address, window_size); + if (!mem_info->mapped_logical_address) { ACPI_ERROR((AE_INFO, "Could not map memory at %8.8X%8.8X, size %X", ACPI_FORMAT_UINT64(address), (u32) window_size)); mem_info->mapped_length = 0; - return_ACPI_STATUS(status); + return_ACPI_STATUS(AE_NO_MEMORY); } /* Save the physical address and mapping size */ @@ -210,11 +209,10 @@ acpi_ex_system_memory_space_handler(u32 function, *value = (acpi_integer) ACPI_GET32(logical_addr_ptr); break; -#if ACPI_MACHINE_WIDTH != 16 case 64: *value = (acpi_integer) ACPI_GET64(logical_addr_ptr); break; -#endif + default: /* bit_width was already validated */ break; @@ -236,11 +234,9 @@ acpi_ex_system_memory_space_handler(u32 function, ACPI_SET32(logical_addr_ptr) = (u32) * value; break; -#if ACPI_MACHINE_WIDTH != 16 case 64: ACPI_SET64(logical_addr_ptr) = (u64) * value; break; -#endif default: /* bit_width was already validated */ diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c index 3089b05a1368..2b3a01cc4929 100644 --- a/drivers/acpi/executer/exresnte.c +++ b/drivers/acpi/executer/exresnte.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c index 6499de878017..6c64e55dab0e 100644 --- a/drivers/acpi/executer/exresolv.c +++ b/drivers/acpi/executer/exresolv.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -141,7 +141,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, acpi_status status = AE_OK; union acpi_operand_object *stack_desc; void *temp_node; - union acpi_operand_object *obj_desc; + union acpi_operand_object *obj_desc = NULL; u16 opcode; ACPI_FUNCTION_TRACE(ex_resolve_object_to_value); @@ -299,8 +299,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, status = acpi_ds_get_package_arguments(stack_desc); break; - /* These cases may never happen here, but just in case.. */ - case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: case ACPI_TYPE_LOCAL_BANK_FIELD: @@ -314,6 +312,10 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, status = acpi_ex_read_data_from_field(walk_state, stack_desc, &obj_desc); + + /* Remove a reference to the original operand, then override */ + + acpi_ut_remove_reference(*stack_ptr); *stack_ptr = (void *)obj_desc; break; diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c index 4c93d0972333..ba761862a599 100644 --- a/drivers/acpi/executer/exresop.c +++ b/drivers/acpi/executer/exresop.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -611,22 +611,20 @@ acpi_ex_resolve_operands(u16 opcode, } goto next_operand; - case ARGI_REGION_OR_FIELD: + case ARGI_REGION_OR_BUFFER: /* Used by Load() only */ - /* Need an operand of type REGION or a FIELD in a region */ + /* Need an operand of type REGION or a BUFFER (which could be a resolved region field) */ switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { + case ACPI_TYPE_BUFFER: case ACPI_TYPE_REGION: - case ACPI_TYPE_LOCAL_REGION_FIELD: - case ACPI_TYPE_LOCAL_BANK_FIELD: - case ACPI_TYPE_LOCAL_INDEX_FIELD: /* Valid operand */ break; default: ACPI_ERROR((AE_INFO, - "Needed [Region/RegionField], found [%s] %p", + "Needed [Region/Buffer], found [%s] %p", acpi_ut_get_object_type_name (obj_desc), obj_desc)); diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c index 0456405ba019..f4b69a637820 100644 --- a/drivers/acpi/executer/exstore.c +++ b/drivers/acpi/executer/exstore.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c index 591aaf0e18b3..1d622c625c64 100644 --- a/drivers/acpi/executer/exstoren.c +++ b/drivers/acpi/executer/exstoren.c @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c index 99ebe5adfcda..8233d40178ee 100644 --- a/drivers/acpi/executer/exstorob.c +++ b/drivers/acpi/executer/exstorob.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c index 28aef3e69ecc..9460baff3032 100644 --- a/drivers/acpi/executer/exsystem.c +++ b/drivers/acpi/executer/exsystem.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,6 @@ ACPI_MODULE_NAME("exsystem") acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) { acpi_status status; - acpi_status status2; ACPI_FUNCTION_TRACE(ex_system_wait_semaphore); @@ -79,7 +78,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) /* We must wait, so unlock the interpreter */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); status = acpi_os_wait_semaphore(semaphore, 1, timeout); @@ -89,13 +88,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) /* Reacquire the interpreter */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status2)) { - - /* Report fatal error, could not acquire interpreter */ - - return_ACPI_STATUS(status2); - } + acpi_ex_reacquire_interpreter(); } return_ACPI_STATUS(status); @@ -119,7 +112,6 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout) { acpi_status status; - acpi_status status2; ACPI_FUNCTION_TRACE(ex_system_wait_mutex); @@ -132,7 +124,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout) /* We must wait, so unlock the interpreter */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); status = acpi_os_acquire_mutex(mutex, timeout); @@ -142,13 +134,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout) /* Reacquire the interpreter */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status2)) { - - /* Report fatal error, could not acquire interpreter */ - - return_ACPI_STATUS(status2); - } + acpi_ex_reacquire_interpreter(); } return_ACPI_STATUS(status); @@ -209,96 +195,18 @@ acpi_status acpi_ex_system_do_stall(u32 how_long) acpi_status acpi_ex_system_do_suspend(acpi_integer how_long) { - acpi_status status; - ACPI_FUNCTION_ENTRY(); /* Since this thread will sleep, we must release the interpreter */ - acpi_ex_exit_interpreter(); + acpi_ex_relinquish_interpreter(); acpi_os_sleep(how_long); /* And now we must get the interpreter again */ - status = acpi_ex_enter_interpreter(); - return (status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ex_system_acquire_mutex - * - * PARAMETERS: time_desc - Maximum time to wait for the mutex - * obj_desc - The object descriptor for this op - * - * RETURN: Status - * - * DESCRIPTION: Provides an access point to perform synchronization operations - * within the AML. This function will cause a lock to be generated - * for the Mutex pointed to by obj_desc. - * - ******************************************************************************/ - -acpi_status -acpi_ex_system_acquire_mutex(union acpi_operand_object * time_desc, - union acpi_operand_object * obj_desc) -{ - acpi_status status = AE_OK; - - ACPI_FUNCTION_TRACE_PTR(ex_system_acquire_mutex, obj_desc); - - if (!obj_desc) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Support for the _GL_ Mutex object -- go get the global lock */ - - if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) { - status = - acpi_ev_acquire_global_lock((u16) time_desc->integer.value); - return_ACPI_STATUS(status); - } - - status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex, - (u16) time_desc->integer.value); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ex_system_release_mutex - * - * PARAMETERS: obj_desc - The object descriptor for this op - * - * RETURN: Status - * - * DESCRIPTION: Provides an access point to perform synchronization operations - * within the AML. This operation is a request to release a - * previously acquired Mutex. If the Mutex variable is set then - * it will be decremented. - * - ******************************************************************************/ - -acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc) -{ - acpi_status status = AE_OK; - - ACPI_FUNCTION_TRACE(ex_system_release_mutex); - - if (!obj_desc) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Support for the _GL_ Mutex object -- release the global lock */ - - if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) { - status = acpi_ev_release_global_lock(); - return_ACPI_STATUS(status); - } - - acpi_os_release_mutex(obj_desc->mutex.os_mutex); - return_ACPI_STATUS(AE_OK); + acpi_ex_reacquire_interpreter(); + return (AE_OK); } /******************************************************************************* @@ -314,7 +222,7 @@ acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc) * ******************************************************************************/ -acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc) +acpi_status acpi_ex_system_signal_event(union acpi_operand_object * obj_desc) { acpi_status status = AE_OK; diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c index 982c8b65876f..6b0aeccbb69b 100644 --- a/drivers/acpi/executer/exutils.c +++ b/drivers/acpi/executer/exutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -76,14 +76,15 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base); * * PARAMETERS: None * - * RETURN: Status + * RETURN: None * - * DESCRIPTION: Enter the interpreter execution region. Failure to enter - * the interpreter region is a fatal system error + * DESCRIPTION: Enter the interpreter execution region. Failure to enter + * the interpreter region is a fatal system error. Used in + * conjunction with exit_interpreter. * ******************************************************************************/ -acpi_status acpi_ex_enter_interpreter(void) +void acpi_ex_enter_interpreter(void) { acpi_status status; @@ -91,10 +92,42 @@ acpi_status acpi_ex_enter_interpreter(void) status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, "Could not acquire interpreter mutex")); + ACPI_ERROR((AE_INFO, + "Could not acquire AML Interpreter mutex")); } - return_ACPI_STATUS(status); + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_reacquire_interpreter + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Reacquire the interpreter execution region from within the + * interpreter code. Failure to enter the interpreter region is a + * fatal system error. Used in conjuction with + * relinquish_interpreter + * + ******************************************************************************/ + +void acpi_ex_reacquire_interpreter(void) +{ + ACPI_FUNCTION_TRACE(ex_reacquire_interpreter); + + /* + * If the global serialized flag is set, do not release the interpreter, + * since it was not actually released by acpi_ex_relinquish_interpreter. + * This forces the interpreter to be single threaded. + */ + if (!acpi_gbl_all_methods_serialized) { + acpi_ex_enter_interpreter(); + } + + return_VOID; } /******************************************************************************* @@ -105,17 +138,9 @@ acpi_status acpi_ex_enter_interpreter(void) * * RETURN: None * - * DESCRIPTION: Exit the interpreter execution region - * - * Cases where the interpreter is unlocked: - * 1) Completion of the execution of a control method - * 2) Method blocked on a Sleep() AML opcode - * 3) Method blocked on an Acquire() AML opcode - * 4) Method blocked on a Wait() AML opcode - * 5) Method blocked to acquire the global lock - * 6) Method blocked to execute a serialized control method that is - * already executing - * 7) About to invoke a user-installed opregion handler + * DESCRIPTION: Exit the interpreter execution region. This is the top level + * routine used to exit the interpreter when all processing has + * been completed. * ******************************************************************************/ @@ -127,7 +152,46 @@ void acpi_ex_exit_interpreter(void) status = acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, "Could not release interpreter mutex")); + ACPI_ERROR((AE_INFO, + "Could not release AML Interpreter mutex")); + } + + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_relinquish_interpreter + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Exit the interpreter execution region, from within the + * interpreter - before attempting an operation that will possibly + * block the running thread. + * + * Cases where the interpreter is unlocked internally + * 1) Method to be blocked on a Sleep() AML opcode + * 2) Method to be blocked on an Acquire() AML opcode + * 3) Method to be blocked on a Wait() AML opcode + * 4) Method to be blocked to acquire the global lock + * 5) Method to be blocked waiting to execute a serialized control method + * that is currently executing + * 6) About to invoke a user-installed opregion handler + * + ******************************************************************************/ + +void acpi_ex_relinquish_interpreter(void) +{ + ACPI_FUNCTION_TRACE(ex_relinquish_interpreter); + + /* + * If the global serialized flag is set, do not release the interpreter. + * This forces the interpreter to be single threaded. + */ + if (!acpi_gbl_all_methods_serialized) { + acpi_ex_exit_interpreter(); } return_VOID; @@ -141,8 +205,8 @@ void acpi_ex_exit_interpreter(void) * * RETURN: none * - * DESCRIPTION: Truncate a number to 32-bits if the currently executing method - * belongs to a 32-bit ACPI table. + * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is + * 32-bit, as determined by the revision of the DSDT. * ******************************************************************************/ diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index f305a826ca2d..af22fdf73413 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -48,8 +48,8 @@ MODULE_LICENSE("GPL"); static int acpi_fan_add(struct acpi_device *device); static int acpi_fan_remove(struct acpi_device *device, int type); -static int acpi_fan_suspend(struct acpi_device *device, int state); -static int acpi_fan_resume(struct acpi_device *device, int state); +static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state); +static int acpi_fan_resume(struct acpi_device *device); static struct acpi_driver acpi_fan_driver = { .name = ACPI_FAN_DRIVER_NAME, @@ -237,7 +237,7 @@ static int acpi_fan_remove(struct acpi_device *device, int type) return 0; } -static int acpi_fan_suspend(struct acpi_device *device, int state) +static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state) { if (!device) return -EINVAL; @@ -247,7 +247,7 @@ static int acpi_fan_suspend(struct acpi_device *device, int state) return AE_OK; } -static int acpi_fan_resume(struct acpi_device *device, int state) +static int acpi_fan_resume(struct acpi_device *device) { int result = 0; int power_state = 0; diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 8a0324b43e53..7b6c9ff9bebe 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -86,129 +86,6 @@ static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle) return ret; } -/* Get PCI root bridge's handle from its segment and bus number */ -struct acpi_find_pci_root { - unsigned int seg; - unsigned int bus; - acpi_handle handle; -}; - -static acpi_status -do_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) -{ - unsigned long *busnr = data; - struct acpi_resource_address64 address; - - if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 && - resource->type != ACPI_RESOURCE_TYPE_ADDRESS32 && - resource->type != ACPI_RESOURCE_TYPE_ADDRESS64) - return AE_OK; - - acpi_resource_to_address64(resource, &address); - if ((address.address_length > 0) && - (address.resource_type == ACPI_BUS_NUMBER_RANGE)) - *busnr = address.minimum; - - return AE_OK; -} - -static int get_root_bridge_busnr(acpi_handle handle) -{ - acpi_status status; - unsigned long bus, bbn; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, - &bbn); - if (status == AE_NOT_FOUND) { - /* Assume bus = 0 */ - printk(KERN_INFO PREFIX - "Assume root bridge [%s] bus is 0\n", - (char *)buffer.pointer); - status = AE_OK; - bbn = 0; - } - if (ACPI_FAILURE(status)) { - bbn = -ENODEV; - goto exit; - } - if (bbn > 0) - goto exit; - - /* _BBN in some systems return 0 for all root bridges */ - bus = -1; - status = acpi_walk_resources(handle, METHOD_NAME__CRS, - do_root_bridge_busnr_callback, &bus); - /* If _CRS failed, we just use _BBN */ - if (ACPI_FAILURE(status) || (bus == -1)) - goto exit; - /* We select _CRS */ - if (bbn != bus) { - printk(KERN_INFO PREFIX - "_BBN and _CRS returns different value for %s. Select _CRS\n", - (char *)buffer.pointer); - bbn = bus; - } - exit: - kfree(buffer.pointer); - return (int)bbn; -} - -static acpi_status -find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - struct acpi_find_pci_root *find = (struct acpi_find_pci_root *)context; - unsigned long seg, bus; - acpi_status status; - int tmp; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &seg); - if (status == AE_NOT_FOUND) { - /* Assume seg = 0 */ - status = AE_OK; - seg = 0; - } - if (ACPI_FAILURE(status)) { - status = AE_CTRL_DEPTH; - goto exit; - } - - tmp = get_root_bridge_busnr(handle); - if (tmp < 0) { - printk(KERN_ERR PREFIX - "Find root bridge failed for %s\n", - (char *)buffer.pointer); - status = AE_CTRL_DEPTH; - goto exit; - } - bus = tmp; - - if (seg == find->seg && bus == find->bus) - { - find->handle = handle; - status = AE_CTRL_TERMINATE; - } - else - status = AE_OK; - exit: - kfree(buffer.pointer); - return status; -} - -acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) -{ - struct acpi_find_pci_root find = { seg, bus, NULL }; - - acpi_get_devices(PCI_ROOT_HID_STRING, find_pci_rootbridge, &find, NULL); - return find.handle; -} -EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle); - /* Get device's handler per its address under its parent */ struct acpi_find_child { acpi_handle handle; diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c index de50fab2a910..6031ca13dd2f 100644 --- a/drivers/acpi/hardware/hwacpi.c +++ b/drivers/acpi/hardware/hwacpi.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,41 +47,6 @@ #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME("hwacpi") -/****************************************************************************** - * - * FUNCTION: acpi_hw_initialize - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Initialize and validate the various ACPI registers defined in - * the FADT. - * - ******************************************************************************/ -acpi_status acpi_hw_initialize(void) -{ - acpi_status status; - - ACPI_FUNCTION_TRACE(hw_initialize); - - /* We must have the ACPI tables by the time we get here */ - - if (!acpi_gbl_FADT) { - ACPI_ERROR((AE_INFO, "No FADT is present")); - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - - /* Sanity check the FADT for valid values */ - - status = acpi_ut_validate_fadt(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - return_ACPI_STATUS(AE_OK); -} - /****************************************************************************** * * FUNCTION: acpi_hw_set_mode @@ -93,7 +58,6 @@ acpi_status acpi_hw_initialize(void) * DESCRIPTION: Transitions the system into the requested mode. * ******************************************************************************/ - acpi_status acpi_hw_set_mode(u32 mode) { @@ -106,7 +70,7 @@ acpi_status acpi_hw_set_mode(u32 mode) * ACPI 2.0 clarified that if SMI_CMD in FADT is zero, * system does not support mode transition. */ - if (!acpi_gbl_FADT->smi_cmd) { + if (!acpi_gbl_FADT.smi_command) { ACPI_ERROR((AE_INFO, "No SMI_CMD in FADT, mode transition failed")); return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE); @@ -119,7 +83,7 @@ acpi_status acpi_hw_set_mode(u32 mode) * we make sure both the numbers are zero to determine these * transitions are not supported. */ - if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) { + if (!acpi_gbl_FADT.acpi_enable && !acpi_gbl_FADT.acpi_disable) { ACPI_ERROR((AE_INFO, "No ACPI mode transition supported in this system (enable/disable both zero)")); return_ACPI_STATUS(AE_OK); @@ -130,9 +94,8 @@ acpi_status acpi_hw_set_mode(u32 mode) /* BIOS should have disabled ALL fixed and GP events */ - status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd, - (u32) acpi_gbl_FADT->acpi_enable, - 8); + status = acpi_os_write_port(acpi_gbl_FADT.smi_command, + (u32) acpi_gbl_FADT.acpi_enable, 8); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Attempting to enable ACPI mode\n")); break; @@ -143,8 +106,8 @@ acpi_status acpi_hw_set_mode(u32 mode) * BIOS should clear all fixed status bits and restore fixed event * enable bits to default */ - status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd, - (u32) acpi_gbl_FADT->acpi_disable, + status = acpi_os_write_port(acpi_gbl_FADT.smi_command, + (u32) acpi_gbl_FADT.acpi_disable, 8); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Attempting to enable Legacy (non-ACPI) mode\n")); @@ -204,12 +167,11 @@ u32 acpi_hw_get_mode(void) * ACPI 2.0 clarified that if SMI_CMD in FADT is zero, * system does not support mode transition. */ - if (!acpi_gbl_FADT->smi_cmd) { + if (!acpi_gbl_FADT.smi_command) { return_UINT32(ACPI_SYS_MODE_ACPI); } - status = - acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value, ACPI_MTX_LOCK); + status = acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value); if (ACPI_FAILURE(status)) { return_UINT32(ACPI_SYS_MODE_LEGACY); } diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c index 608a3a60ee11..117a05cadaaa 100644 --- a/drivers/acpi/hardware/hwgpe.c +++ b/drivers/acpi/hardware/hwgpe.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -105,14 +105,20 @@ acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info) acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info) { acpi_status status; + u8 register_bit; ACPI_FUNCTION_ENTRY(); + register_bit = (u8) + (1 << + (gpe_event_info->gpe_number - + gpe_event_info->register_info->base_gpe_number)); + /* * Write a one to the appropriate bit in the status register to * clear this GPE. */ - status = acpi_hw_low_level_write(8, gpe_event_info->register_bit, + status = acpi_hw_low_level_write(8, register_bit, &gpe_event_info->register_info-> status_address); @@ -155,7 +161,10 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, /* Get the register bitmask for this GPE */ - register_bit = gpe_event_info->register_bit; + register_bit = (u8) + (1 << + (gpe_event_info->gpe_number - + gpe_event_info->register_info->base_gpe_number)); /* GPE currently enabled? (enabled for runtime?) */ diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c index fa58c1edce1e..1d371fa663f2 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/hardware/hwregs.c @@ -7,7 +7,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,17 +54,15 @@ ACPI_MODULE_NAME("hwregs") * * FUNCTION: acpi_hw_clear_acpi_status * - * PARAMETERS: Flags - Lock the hardware or not + * PARAMETERS: None * - * RETURN: none + * RETURN: None * * DESCRIPTION: Clears all fixed and general purpose status bits * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED * - * NOTE: TBD: Flags parameter is obsolete, to be removed - * ******************************************************************************/ -acpi_status acpi_hw_clear_acpi_status(u32 flags) +acpi_status acpi_hw_clear_acpi_status(void) { acpi_status status; acpi_cpu_flags lock_flags = 0; @@ -73,7 +71,7 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags) ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n", ACPI_BITMASK_ALL_FIXED_STATUS, - (u16) acpi_gbl_FADT->xpm1a_evt_blk.address)); + (u16) acpi_gbl_FADT.xpm1a_event_block.address)); lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); @@ -86,10 +84,10 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags) /* Clear the fixed events */ - if (acpi_gbl_FADT->xpm1b_evt_blk.address) { + if (acpi_gbl_FADT.xpm1b_event_block.address) { status = acpi_hw_low_level_write(16, ACPI_BITMASK_ALL_FIXED_STATUS, - &acpi_gbl_FADT->xpm1b_evt_blk); + &acpi_gbl_FADT.xpm1b_event_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -253,18 +251,15 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) * * PARAMETERS: register_id - ID of ACPI bit_register to access * return_value - Value that was read from the register - * Flags - Lock the hardware or not * * RETURN: Status and the value read from specified Register. Value * returned is normalized to bit0 (is shifted all the way right) * * DESCRIPTION: ACPI bit_register read function. * - * NOTE: TBD: Flags parameter is obsolete, to be removed - * ******************************************************************************/ -acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags) +acpi_status acpi_get_register(u32 register_id, u32 * return_value) { u32 register_value = 0; struct acpi_bit_register_info *bit_reg_info; @@ -312,16 +307,13 @@ ACPI_EXPORT_SYMBOL(acpi_get_register) * PARAMETERS: register_id - ID of ACPI bit_register to access * Value - (only used on write) value to write to the * Register, NOT pre-normalized to the bit pos - * Flags - Lock the hardware or not * * RETURN: Status * * DESCRIPTION: ACPI Bit Register write function. * - * NOTE: TBD: Flags parameter is obsolete, to be removed - * ******************************************************************************/ -acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags) +acpi_status acpi_set_register(u32 register_id, u32 value) { u32 register_value = 0; struct acpi_bit_register_info *bit_reg_info; @@ -422,8 +414,9 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags) ACPI_DEBUG_PRINT((ACPI_DB_IO, "PM2 control: Read %X from %8.8X%8.8X\n", register_value, - ACPI_FORMAT_UINT64(acpi_gbl_FADT-> - xpm2_cnt_blk.address))); + ACPI_FORMAT_UINT64(acpi_gbl_FADT. + xpm2_control_block. + address))); ACPI_REGISTER_INSERT_VALUE(register_value, bit_reg_info->bit_position, @@ -433,8 +426,9 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags) ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %4.4X to %8.8X%8.8X\n", register_value, - ACPI_FORMAT_UINT64(acpi_gbl_FADT-> - xpm2_cnt_blk.address))); + ACPI_FORMAT_UINT64(acpi_gbl_FADT. + xpm2_control_block. + address))); status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM2_CONTROL, @@ -495,7 +489,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) status = acpi_hw_low_level_read(16, &value1, - &acpi_gbl_FADT->xpm1a_evt_blk); + &acpi_gbl_FADT.xpm1a_event_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -504,7 +498,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) status = acpi_hw_low_level_read(16, &value2, - &acpi_gbl_FADT->xpm1b_evt_blk); + &acpi_gbl_FADT.xpm1b_event_block); value1 |= value2; break; @@ -527,14 +521,14 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) status = acpi_hw_low_level_read(16, &value1, - &acpi_gbl_FADT->xpm1a_cnt_blk); + &acpi_gbl_FADT.xpm1a_control_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } status = acpi_hw_low_level_read(16, &value2, - &acpi_gbl_FADT->xpm1b_cnt_blk); + &acpi_gbl_FADT.xpm1b_control_block); value1 |= value2; break; @@ -542,19 +536,20 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value) status = acpi_hw_low_level_read(8, &value1, - &acpi_gbl_FADT->xpm2_cnt_blk); + &acpi_gbl_FADT.xpm2_control_block); break; case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ status = acpi_hw_low_level_read(32, &value1, - &acpi_gbl_FADT->xpm_tmr_blk); + &acpi_gbl_FADT.xpm_timer_block); break; case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ - status = acpi_os_read_port(acpi_gbl_FADT->smi_cmd, &value1, 8); + status = + acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8); break; default: @@ -635,7 +630,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value) status = acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT->xpm1a_evt_blk); + &acpi_gbl_FADT.xpm1a_event_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -644,7 +639,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value) status = acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT->xpm1b_evt_blk); + &acpi_gbl_FADT.xpm1b_event_block); break; case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */ @@ -682,49 +677,50 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value) status = acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT->xpm1a_cnt_blk); + &acpi_gbl_FADT.xpm1a_control_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } status = acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT->xpm1b_cnt_blk); + &acpi_gbl_FADT.xpm1b_control_block); break; case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */ status = acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT->xpm1a_cnt_blk); + &acpi_gbl_FADT.xpm1a_control_block); break; case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */ status = acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT->xpm1b_cnt_blk); + &acpi_gbl_FADT.xpm1b_control_block); break; case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ status = acpi_hw_low_level_write(8, value, - &acpi_gbl_FADT->xpm2_cnt_blk); + &acpi_gbl_FADT.xpm2_control_block); break; case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ status = acpi_hw_low_level_write(32, value, - &acpi_gbl_FADT->xpm_tmr_blk); + &acpi_gbl_FADT.xpm_timer_block); break; case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ /* SMI_CMD is currently always in IO space */ - status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd, value, 8); + status = + acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8); break; default: @@ -783,7 +779,7 @@ acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg) * Two address spaces supported: Memory or IO. * PCI_Config is not supported here because the GAS struct is insufficient */ - switch (reg->address_space_id) { + switch (reg->space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: status = acpi_os_read_memory((acpi_physical_address) address, @@ -792,22 +788,20 @@ acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg) case ACPI_ADR_SPACE_SYSTEM_IO: - status = acpi_os_read_port((acpi_io_address) address, - value, width); + status = + acpi_os_read_port((acpi_io_address) address, value, width); break; default: ACPI_ERROR((AE_INFO, - "Unsupported address space: %X", - reg->address_space_id)); + "Unsupported address space: %X", reg->space_id)); return (AE_BAD_PARAMETER); } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", - *value, width, - ACPI_FORMAT_UINT64(address), - acpi_ut_get_region_name(reg->address_space_id))); + *value, width, ACPI_FORMAT_UINT64(address), + acpi_ut_get_region_name(reg->space_id))); return (status); } @@ -854,7 +848,7 @@ acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg) * Two address spaces supported: Memory or IO. * PCI_Config is not supported here because the GAS struct is insufficient */ - switch (reg->address_space_id) { + switch (reg->space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: status = acpi_os_write_memory((acpi_physical_address) address, @@ -863,22 +857,20 @@ acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg) case ACPI_ADR_SPACE_SYSTEM_IO: - status = acpi_os_write_port((acpi_io_address) address, - value, width); + status = acpi_os_write_port((acpi_io_address) address, value, + width); break; default: ACPI_ERROR((AE_INFO, - "Unsupported address space: %X", - reg->address_space_id)); + "Unsupported address space: %X", reg->space_id)); return (AE_BAD_PARAMETER); } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", - value, width, - ACPI_FORMAT_UINT64(address), - acpi_ut_get_region_name(reg->address_space_id))); + value, width, ACPI_FORMAT_UINT64(address), + acpi_ut_get_region_name(reg->space_id))); return (status); } diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 8bb43cae60c2..57901ca3ade9 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,6 +43,7 @@ */ #include +#include #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME("hwsleep") @@ -62,17 +63,32 @@ ACPI_MODULE_NAME("hwsleep") acpi_status acpi_set_firmware_waking_vector(acpi_physical_address physical_address) { + struct acpi_table_facs *facs; + acpi_status status; ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); + /* Get the FACS */ + + status = + acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + (struct acpi_table_header **)&facs); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + /* Set the vector */ - if (acpi_gbl_common_fACS.vector_width == 32) { - *(ACPI_CAST_PTR - (u32, acpi_gbl_common_fACS.firmware_waking_vector)) - = (u32) physical_address; + if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) { + /* + * ACPI 1.0 FACS or short table or optional X_ field is zero + */ + facs->firmware_waking_vector = (u32) physical_address; } else { - *acpi_gbl_common_fACS.firmware_waking_vector = physical_address; + /* + * ACPI 2.0 FACS with valid X_ field + */ + facs->xfirmware_waking_vector = physical_address; } return_ACPI_STATUS(AE_OK); @@ -97,6 +113,8 @@ ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) acpi_status acpi_get_firmware_waking_vector(acpi_physical_address * physical_address) { + struct acpi_table_facs *facs; + acpi_status status; ACPI_FUNCTION_TRACE(acpi_get_firmware_waking_vector); @@ -104,16 +122,29 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address) return_ACPI_STATUS(AE_BAD_PARAMETER); } + /* Get the FACS */ + + status = + acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + (struct acpi_table_header **)&facs); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + /* Get the vector */ - if (acpi_gbl_common_fACS.vector_width == 32) { - *physical_address = (acpi_physical_address) - * - (ACPI_CAST_PTR - (u32, acpi_gbl_common_fACS.firmware_waking_vector)); - } else { + if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) { + /* + * ACPI 1.0 FACS or short table or optional X_ field is zero + */ *physical_address = - *acpi_gbl_common_fACS.firmware_waking_vector; + (acpi_physical_address) facs->firmware_waking_vector; + } else { + /* + * ACPI 2.0 FACS with valid X_ field + */ + *physical_address = + (acpi_physical_address) facs->xfirmware_waking_vector; } return_ACPI_STATUS(AE_OK); @@ -246,15 +277,14 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) /* Clear wake status */ - status = - acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); + status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Clear all fixed and general purpose status bits */ - status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK); + status = acpi_hw_clear_acpi_status(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -367,8 +397,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) /* Wait until we enter sleep state */ do { - status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value, - ACPI_MTX_DO_NOT_LOCK); + status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -401,13 +430,12 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void) ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios); - status = - acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); + status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK); + status = acpi_hw_clear_acpi_status(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -429,13 +457,12 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void) ACPI_FLUSH_CPU_CACHE(); - status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd, - (u32) acpi_gbl_FADT->S4bios_req, 8); + status = acpi_os_write_port(acpi_gbl_FADT.smi_command, + (u32) acpi_gbl_FADT.S4bios_request, 8); do { acpi_os_stall(1000); - status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value, - ACPI_MTX_DO_NOT_LOCK); + status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -568,13 +595,11 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) (void) acpi_set_register(acpi_gbl_fixed_event_info - [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1, - ACPI_MTX_DO_NOT_LOCK); + [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1); (void) acpi_set_register(acpi_gbl_fixed_event_info - [ACPI_EVENT_POWER_BUTTON].status_register_id, 1, - ACPI_MTX_DO_NOT_LOCK); + [ACPI_EVENT_POWER_BUTTON].status_register_id, 1); arg.integer.value = ACPI_SST_WORKING; status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL); diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c index c4ec47c939fd..c32eab696acd 100644 --- a/drivers/acpi/hardware/hwtimer.c +++ b/drivers/acpi/hardware/hwtimer.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,7 @@ acpi_status acpi_get_timer_resolution(u32 * resolution) return_ACPI_STATUS(AE_BAD_PARAMETER); } - if (acpi_gbl_FADT->tmr_val_ext == 0) { + if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) { *resolution = 24; } else { *resolution = 32; @@ -98,7 +98,8 @@ acpi_status acpi_get_timer(u32 * ticks) return_ACPI_STATUS(AE_BAD_PARAMETER); } - status = acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT->xpm_tmr_blk); + status = + acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT.xpm_timer_block); return_ACPI_STATUS(status); } @@ -153,7 +154,7 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) if (start_ticks < end_ticks) { delta_ticks = end_ticks - start_ticks; } else if (start_ticks > end_ticks) { - if (acpi_gbl_FADT->tmr_val_ext == 0) { + if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) { /* 24-bit Timer */ diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c deleted file mode 100644 index 2e17ec75af03..000000000000 --- a/drivers/acpi/motherboard.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -/* Purpose: Prevent PCMCIA cards from using motherboard resources. */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME("acpi_motherboard") - -/* Dell use PNP0C01 instead of PNP0C02 */ -#define ACPI_MB_HID1 "PNP0C01" -#define ACPI_MB_HID2 "PNP0C02" -/** - * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved - * Doesn't care about the failure of 'request_region', since other may reserve - * the io ports as well - */ -#define IS_RESERVED_ADDR(base, len) \ - (((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \ - && ((base) + (len) > PCIBIOS_MIN_IO)) -/* - * Clearing the flag (IORESOURCE_BUSY) allows drivers to use - * the io ports if they really know they can use it, while - * still preventing hotplug PCI devices from using it. - */ - -/* - * When CONFIG_PNP is enabled, pnp/system.c binds to PNP0C01 - * and PNP0C02, redundant with acpi_reserve_io_ranges(). - * But acpi_reserve_io_ranges() is necessary for !CONFIG_PNP. - */ -static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data) -{ - struct resource *requested_res = NULL; - - - if (res->type == ACPI_RESOURCE_TYPE_IO) { - struct acpi_resource_io *io_res = &res->data.io; - - if (io_res->minimum != io_res->maximum) - return AE_OK; - if (IS_RESERVED_ADDR - (io_res->minimum, io_res->address_length)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Motherboard resources 0x%08x - 0x%08x\n", - io_res->minimum, - io_res->minimum + - io_res->address_length)); - requested_res = - request_region(io_res->minimum, - io_res->address_length, "motherboard"); - } - } else if (res->type == ACPI_RESOURCE_TYPE_FIXED_IO) { - struct acpi_resource_fixed_io *fixed_io_res = - &res->data.fixed_io; - - if (IS_RESERVED_ADDR - (fixed_io_res->address, fixed_io_res->address_length)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Motherboard resources 0x%08x - 0x%08x\n", - fixed_io_res->address, - fixed_io_res->address + - fixed_io_res->address_length)); - requested_res = - request_region(fixed_io_res->address, - fixed_io_res->address_length, - "motherboard"); - } - } else { - /* Memory mapped IO? */ - } - - if (requested_res) - requested_res->flags &= ~IORESOURCE_BUSY; - return AE_OK; -} - -static int acpi_motherboard_add(struct acpi_device *device) -{ - if (!device) - return -EINVAL; - acpi_walk_resources(device->handle, METHOD_NAME__CRS, - acpi_reserve_io_ranges, NULL); - - return 0; -} - -static struct acpi_driver acpi_motherboard_driver1 = { - .name = "motherboard", - .class = "", - .ids = ACPI_MB_HID1, - .ops = { - .add = acpi_motherboard_add, - }, -}; - -static struct acpi_driver acpi_motherboard_driver2 = { - .name = "motherboard", - .class = "", - .ids = ACPI_MB_HID2, - .ops = { - .add = acpi_motherboard_add, - }, -}; - -static void __init acpi_request_region (struct acpi_generic_address *addr, - unsigned int length, char *desc) -{ - if (!addr->address || !length) - return; - - if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) - request_region(addr->address, length, desc); - else if (addr->address_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->xpm1b_evt_blk, - acpi_gbl_FADT->pm1_evt_len, "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->xpm1b_cnt_blk, - acpi_gbl_FADT->pm1_cnt_len, "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"); - - acpi_request_region(&acpi_gbl_FADT->xpm2_cnt_blk, - acpi_gbl_FADT->pm2_cnt_len, "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->gpe1_blk_len & 0x1)) - acpi_request_region(&acpi_gbl_FADT->xgpe1_blk, - acpi_gbl_FADT->gpe1_blk_len, "ACPI GPE1_BLK"); -} - -static int __init acpi_motherboard_init(void) -{ - acpi_bus_register_driver(&acpi_motherboard_driver1); - acpi_bus_register_driver(&acpi_motherboard_driver2); - /* - * Guarantee motherboard IO reservation first - * This module must run after scan.c - */ - if (!acpi_disabled) - acpi_reserve_resources(); - return 0; -} - -/** - * Reserve motherboard resources after PCI claim BARs, - * but before PCI assign resources for uninitialized PCI devices - */ -fs_initcall(acpi_motherboard_init); diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c index c1c6c236df9a..57faf598bad8 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/namespace/nsaccess.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -195,31 +195,27 @@ acpi_status acpi_ns_root_initialize(void) obj_desc->mutex.sync_level = (u8) (ACPI_TO_INTEGER(val) - 1); + /* Create a mutex */ + + status = + acpi_os_create_mutex(&obj_desc->mutex. + os_mutex); + if (ACPI_FAILURE(status)) { + acpi_ut_remove_reference(obj_desc); + goto unlock_and_exit; + } + + /* Special case for ACPI Global Lock */ + if (ACPI_STRCMP(init_val->name, "_GL_") == 0) { + acpi_gbl_global_lock_mutex = + obj_desc->mutex.os_mutex; - /* Create a counting semaphore for the global lock */ + /* Create additional counting semaphore for global lock */ status = - acpi_os_create_semaphore - (ACPI_NO_UNIT_LIMIT, 1, - &acpi_gbl_global_lock_semaphore); - if (ACPI_FAILURE(status)) { - acpi_ut_remove_reference - (obj_desc); - goto unlock_and_exit; - } - - /* Mark this mutex as very special */ - - obj_desc->mutex.os_mutex = - ACPI_GLOBAL_LOCK; - } else { - /* Create a mutex */ - - status = - acpi_os_create_mutex(&obj_desc-> - mutex. - os_mutex); + acpi_os_create_semaphore(1, 0, + &acpi_gbl_global_lock_semaphore); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference (obj_desc); diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c index 55b407aae266..1d693d8ad2d8 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/namespace/nsalloc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -61,6 +61,9 @@ ACPI_MODULE_NAME("nsalloc") struct acpi_namespace_node *acpi_ns_create_node(u32 name) { struct acpi_namespace_node *node; +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + u32 temp; +#endif ACPI_FUNCTION_TRACE(ns_create_node); @@ -71,6 +74,15 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name) ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++); +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + temp = + acpi_gbl_ns_node_list->total_allocated - + acpi_gbl_ns_node_list->total_freed; + if (temp > acpi_gbl_ns_node_list->max_occupied) { + acpi_gbl_ns_node_list->max_occupied = temp; + } +#endif + node->name.integer = name; ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED); return_PTR(node); diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c index d72df66aa965..1fc4f86676e1 100644 --- a/drivers/acpi/namespace/nsdump.c +++ b/drivers/acpi/namespace/nsdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -205,7 +205,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, if (!acpi_ut_valid_acpi_name(this_node->name.integer)) { this_node->name.integer = - acpi_ut_repair_name(this_node->name.integer); + acpi_ut_repair_name(this_node->name.ascii); ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X", this_node->name.integer)); @@ -226,6 +226,12 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, obj_desc = acpi_ns_get_attached_object(this_node); acpi_dbg_level = dbg_level; + /* Temp nodes are those nodes created by a control method */ + + if (this_node->flags & ANOBJ_TEMPORARY) { + acpi_os_printf("(T) "); + } + switch (info->display_type & ACPI_DISPLAY_MASK) { case ACPI_DISPLAY_SUMMARY: @@ -623,7 +629,8 @@ acpi_ns_dump_objects(acpi_object_type type, info.display_type = display_type; (void)acpi_ns_walk_namespace(type, start_handle, max_depth, - ACPI_NS_WALK_NO_UNLOCK, + ACPI_NS_WALK_NO_UNLOCK | + ACPI_NS_WALK_TEMP_NODES, acpi_ns_dump_one_object, (void *)&info, NULL); } diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c index c6bf5d30fca3..5097e167939e 100644 --- a/drivers/acpi/namespace/nsdumpdv.c +++ b/drivers/acpi/namespace/nsdumpdv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c index 4b0a4a8c9843..aa6370c67ec1 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/namespace/nseval.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -154,11 +154,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) * Execute the method via the interpreter. The interpreter is locked * here before calling into the AML parser */ - status = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - + acpi_ex_enter_interpreter(); status = acpi_ps_execute_method(info); acpi_ex_exit_interpreter(); } else { @@ -182,10 +178,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) * resolution, we must lock it because we could access an opregion. * The opregion access code assumes that the interpreter is locked. */ - status = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + acpi_ex_enter_interpreter(); /* Function has a strange interface */ diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c index aec8488c0019..326af8fc0ce7 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/namespace/nsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -213,7 +213,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle, u32 level, void *context, void **return_value) { acpi_object_type type; - acpi_status status; + acpi_status status = AE_OK; struct acpi_init_walk_info *info = (struct acpi_init_walk_info *)context; struct acpi_namespace_node *node = @@ -267,10 +267,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle, /* * Must lock the interpreter before executing AML code */ - status = acpi_ex_enter_interpreter(); - if (ACPI_FAILURE(status)) { - return (status); - } + acpi_ex_enter_interpreter(); /* * Each of these types can contain executable AML code within the diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c index fe75d888e183..d4f9654fd20f 100644 --- a/drivers/acpi/namespace/nsload.c +++ b/drivers/acpi/namespace/nsload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,13 +44,12 @@ #include #include #include +#include #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsload") /* Local prototypes */ -static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type); - #ifdef ACPI_FUTURE_IMPLEMENTATION acpi_status acpi_ns_unload_namespace(acpi_handle handle); @@ -62,7 +61,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle); * * FUNCTION: acpi_ns_load_table * - * PARAMETERS: table_desc - Descriptor for table to be loaded + * PARAMETERS: table_index - Index for table to be loaded * Node - Owning NS node * * RETURN: Status @@ -72,42 +71,13 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle); ******************************************************************************/ acpi_status -acpi_ns_load_table(struct acpi_table_desc *table_desc, +acpi_ns_load_table(acpi_native_uint table_index, struct acpi_namespace_node *node) { acpi_status status; ACPI_FUNCTION_TRACE(ns_load_table); - /* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */ - - if (! - (acpi_gbl_table_data[table_desc->type]. - flags & ACPI_TABLE_EXECUTABLE)) { - - /* Just ignore this table */ - - return_ACPI_STATUS(AE_OK); - } - - /* Check validity of the AML start and length */ - - if (!table_desc->aml_start) { - ACPI_ERROR((AE_INFO, "Null AML pointer")); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AML block at %p\n", - table_desc->aml_start)); - - /* Ignore table if there is no AML contained within */ - - if (!table_desc->aml_length) { - ACPI_WARNING((AE_INFO, "Zero-length AML block in table [%4.4s]", - table_desc->pointer->signature)); - return_ACPI_STATUS(AE_OK); - } - /* * Parse the table and load the namespace with all named * objects found within. Control methods are NOT parsed @@ -117,15 +87,34 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc, * to another control method, we can't continue parsing * because we don't know how many arguments to parse next! */ - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "**** Loading table into namespace ****\n")); - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } - status = acpi_ns_parse_table(table_desc, node->child); + /* If table already loaded into namespace, just return */ + + if (acpi_tb_is_table_loaded(table_index)) { + status = AE_ALREADY_EXISTS; + goto unlock; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "**** Loading table into namespace ****\n")); + + status = acpi_tb_allocate_owner_id(table_index); + if (ACPI_FAILURE(status)) { + goto unlock; + } + + status = acpi_ns_parse_table(table_index, node->child); + if (ACPI_SUCCESS(status)) { + acpi_tb_set_table_loaded_flag(table_index, TRUE); + } else { + acpi_tb_release_owner_id(table_index); + } + + unlock: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { @@ -141,7 +130,7 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc, ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Begin Table Method Parsing and Object Initialization ****\n")); - status = acpi_ds_initialize_objects(table_desc, node); + status = acpi_ds_initialize_objects(table_index, node); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Completed Table Method Parsing and Object Initialization ****\n")); @@ -149,99 +138,7 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc, return_ACPI_STATUS(status); } -/******************************************************************************* - * - * FUNCTION: acpi_ns_load_table_by_type - * - * PARAMETERS: table_type - Id of the table type to load - * - * RETURN: Status - * - * DESCRIPTION: Load an ACPI table or tables into the namespace. All tables - * of the given type are loaded. The mechanism allows this - * routine to be called repeatedly. - * - ******************************************************************************/ - -static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type) -{ - u32 i; - acpi_status status; - struct acpi_table_desc *table_desc; - - ACPI_FUNCTION_TRACE(ns_load_table_by_type); - - status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* - * Table types supported are: - * DSDT (one), SSDT/PSDT (multiple) - */ - switch (table_type) { - case ACPI_TABLE_ID_DSDT: - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace load: DSDT\n")); - - table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_DSDT].next; - - /* If table already loaded into namespace, just return */ - - if (table_desc->loaded_into_namespace) { - goto unlock_and_exit; - } - - /* Now load the single DSDT */ - - status = acpi_ns_load_table(table_desc, acpi_gbl_root_node); - if (ACPI_SUCCESS(status)) { - table_desc->loaded_into_namespace = TRUE; - } - break; - - case ACPI_TABLE_ID_SSDT: - case ACPI_TABLE_ID_PSDT: - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Namespace load: %d SSDT or PSDTs\n", - acpi_gbl_table_lists[table_type].count)); - - /* - * Traverse list of SSDT or PSDT tables - */ - table_desc = acpi_gbl_table_lists[table_type].next; - for (i = 0; i < acpi_gbl_table_lists[table_type].count; i++) { - /* - * Only attempt to load table into namespace if it is not - * already loaded! - */ - if (!table_desc->loaded_into_namespace) { - status = - acpi_ns_load_table(table_desc, - acpi_gbl_root_node); - if (ACPI_FAILURE(status)) { - break; - } - - table_desc->loaded_into_namespace = TRUE; - } - - table_desc = table_desc->next; - } - break; - - default: - status = AE_SUPPORT; - break; - } - - unlock_and_exit: - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(status); -} - +#ifdef ACPI_OBSOLETE_FUNCTIONS /******************************************************************************* * * FUNCTION: acpi_load_namespace @@ -288,6 +185,7 @@ acpi_status acpi_ns_load_namespace(void) return_ACPI_STATUS(status); } +#endif #ifdef ACPI_FUTURE_IMPLEMENTATION /******************************************************************************* diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c index 97b8332c9746..cbd94af08cc5 100644 --- a/drivers/acpi/namespace/nsnames.c +++ b/drivers/acpi/namespace/nsnames.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c index aabe8794b908..d9d7377bc6e6 100644 --- a/drivers/acpi/namespace/nsobject.c +++ b/drivers/acpi/namespace/nsobject.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c index 155505a4ef69..e696aa847990 100644 --- a/drivers/acpi/namespace/nsparse.c +++ b/drivers/acpi/namespace/nsparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,7 @@ #include #include #include +#include #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsparse") @@ -62,14 +63,24 @@ ACPI_MODULE_NAME("nsparse") * ******************************************************************************/ acpi_status -acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc) +acpi_ns_one_complete_parse(acpi_native_uint pass_number, + acpi_native_uint table_index) { union acpi_parse_object *parse_root; acpi_status status; + acpi_native_uint aml_length; + u8 *aml_start; struct acpi_walk_state *walk_state; + struct acpi_table_header *table; + acpi_owner_id owner_id; ACPI_FUNCTION_TRACE(ns_one_complete_parse); + status = acpi_tb_get_owner_id(table_index, &owner_id); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + /* Create and init a Root Node */ parse_root = acpi_ps_create_scope_op(); @@ -79,26 +90,41 @@ acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc) /* Create and initialize a new walk state */ - walk_state = acpi_ds_create_walk_state(table_desc->owner_id, - NULL, NULL, NULL); + walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL); if (!walk_state) { acpi_ps_free_op(parse_root); return_ACPI_STATUS(AE_NO_MEMORY); } - status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL, - table_desc->aml_start, - table_desc->aml_length, NULL, - pass_number); + status = acpi_get_table_by_index(table_index, &table); if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); + acpi_ps_free_op(parse_root); + return_ACPI_STATUS(status); + } + + /* Table must consist of at least a complete header */ + + if (table->length < sizeof(struct acpi_table_header)) { + status = AE_BAD_HEADER; + } else { + aml_start = (u8 *) table + sizeof(struct acpi_table_header); + aml_length = table->length - sizeof(struct acpi_table_header); + status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL, + aml_start, aml_length, NULL, + (u8) pass_number); + } + + if (ACPI_FAILURE(status)) { + acpi_ds_delete_walk_state(walk_state); + acpi_ps_delete_parse_tree(parse_root); return_ACPI_STATUS(status); } /* Parse the AML */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %d parse\n", - pass_number)); + (unsigned)pass_number)); status = acpi_ps_parse_aml(walk_state); acpi_ps_delete_parse_tree(parse_root); @@ -119,7 +145,7 @@ acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc) ******************************************************************************/ acpi_status -acpi_ns_parse_table(struct acpi_table_desc *table_desc, +acpi_ns_parse_table(acpi_native_uint table_index, struct acpi_namespace_node *start_node) { acpi_status status; @@ -134,10 +160,10 @@ acpi_ns_parse_table(struct acpi_table_desc *table_desc, * each Parser Op subtree is deleted when it is finished. This saves * a great deal of memory, and allows a small cache of parse objects * to service the entire parse. The second pass of the parse then - * performs another complete parse of the AML.. + * performs another complete parse of the AML. */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n")); - status = acpi_ns_one_complete_parse(1, table_desc); + status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -152,7 +178,7 @@ acpi_ns_parse_table(struct acpi_table_desc *table_desc, * parse objects are all cached. */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 2\n")); - status = acpi_ns_one_complete_parse(2, table_desc); + status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c index 500e2bbcfaf7..e863be665ce8 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/namespace/nssearch.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -321,7 +321,8 @@ acpi_ns_search_and_enter(u32 target_name, * even though there are a few bad names. */ if (!acpi_ut_valid_acpi_name(target_name)) { - target_name = acpi_ut_repair_name(target_name); + target_name = + acpi_ut_repair_name(ACPI_CAST_PTR(char, &target_name)); /* Report warning only if in strict mode or debug mode */ @@ -401,6 +402,10 @@ acpi_ns_search_and_enter(u32 target_name, } #endif + if (flags & ACPI_NS_TEMPORARY) { + new_node->flags |= ANOBJ_TEMPORARY; + } + /* Install the new object into the parent's list of children */ acpi_ns_install_node(walk_state, node, new_node, type); diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c index aa4e799d9a8c..90fd059615ff 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/namespace/nsutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -770,13 +770,6 @@ void acpi_ns_terminate(void) } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace freed\n")); - - /* - * 2) Now we can delete the ACPI tables - */ - acpi_tb_delete_all_tables(); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); - return_VOID; } diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c index c8f6bef16ed0..94eb8f332d94 100644 --- a/drivers/acpi/namespace/nswalk.c +++ b/drivers/acpi/namespace/nswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -126,7 +126,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, * PARAMETERS: Type - acpi_object_type to search for * start_node - Handle in namespace where search begins * max_depth - Depth to which search is to reach - * unlock_before_callback- Whether to unlock the NS before invoking + * Flags - Whether to unlock the NS before invoking * the callback routine * user_function - Called when an object of "Type" is found * Context - Passed to user function @@ -153,7 +153,7 @@ acpi_status acpi_ns_walk_namespace(acpi_object_type type, acpi_handle start_node, u32 max_depth, - u8 unlock_before_callback, + u32 flags, acpi_walk_callback user_function, void *context, void **return_value) { @@ -193,20 +193,34 @@ acpi_ns_walk_namespace(acpi_object_type type, acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, child_node); if (child_node) { - /* - * Found node, Get the type if we are not - * searching for ANY - */ + + /* Found next child, get the type if we are not searching for ANY */ + if (type != ACPI_TYPE_ANY) { child_type = child_node->type; } - if (child_type == type) { + /* + * Ignore all temporary namespace nodes (created during control + * method execution) unless told otherwise. These temporary nodes + * can cause a race condition because they can be deleted during the + * execution of the user function (if the namespace is unlocked before + * invocation of the user function.) Only the debugger namespace dump + * will examine the temporary nodes. + */ + if ((child_node->flags & ANOBJ_TEMPORARY) && + !(flags & ACPI_NS_WALK_TEMP_NODES)) { + status = AE_CTRL_DEPTH; + } + + /* Type must match requested type */ + + else if (child_type == type) { /* - * Found a matching node, invoke the user - * callback function + * Found a matching node, invoke the user callback function. + * Unlock the namespace if flag is set. */ - if (unlock_before_callback) { + if (flags & ACPI_NS_WALK_UNLOCK) { mutex_status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); @@ -216,10 +230,11 @@ acpi_ns_walk_namespace(acpi_object_type type, } } - status = user_function(child_node, level, - context, return_value); + status = + user_function(child_node, level, context, + return_value); - if (unlock_before_callback) { + if (flags & ACPI_NS_WALK_UNLOCK) { mutex_status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); @@ -251,20 +266,17 @@ acpi_ns_walk_namespace(acpi_object_type type, } /* - * Depth first search: - * Attempt to go down another level in the namespace - * if we are allowed to. Don't go any further if we - * have reached the caller specified maximum depth - * or if the user function has specified that the - * maximum depth has been reached. + * Depth first search: Attempt to go down another level in the + * namespace if we are allowed to. Don't go any further if we have + * reached the caller specified maximum depth or if the user + * function has specified that the maximum depth has been reached. */ if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { if (acpi_ns_get_next_node (ACPI_TYPE_ANY, child_node, NULL)) { - /* - * There is at least one child of this - * node, visit the onde - */ + + /* There is at least one child of this node, visit it */ + level++; parent_node = child_node; child_node = NULL; @@ -272,9 +284,8 @@ acpi_ns_walk_namespace(acpi_object_type type, } } else { /* - * No more children of this node (acpi_ns_get_next_node - * failed), go back upwards in the namespace tree to - * the node's parent. + * No more children of this node (acpi_ns_get_next_node failed), go + * back upwards in the namespace tree to the node's parent. */ level--; child_node = parent_node; diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c index dca6799ac678..7ac6ace50059 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/namespace/nsxfeval.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -170,7 +170,6 @@ acpi_evaluate_object(acpi_handle handle, struct acpi_buffer *return_buffer) { acpi_status status; - acpi_status status2; struct acpi_evaluate_info *info; acpi_size buffer_space_needed; u32 i; @@ -329,14 +328,12 @@ acpi_evaluate_object(acpi_handle handle, * Delete the internal return object. NOTE: Interpreter must be * locked to avoid race condition. */ - status2 = acpi_ex_enter_interpreter(); - if (ACPI_SUCCESS(status2)) { + acpi_ex_enter_interpreter(); - /* Remove one reference on the return object (should delete it) */ + /* Remove one reference on the return object (should delete it) */ - acpi_ut_remove_reference(info->return_object); - acpi_ex_exit_interpreter(); - } + acpi_ut_remove_reference(info->return_object); + acpi_ex_exit_interpreter(); } cleanup: diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c index 978213a6c19f..b489781b22a8 100644 --- a/drivers/acpi/namespace/nsxfname.c +++ b/drivers/acpi/namespace/nsxfname.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -84,38 +84,41 @@ acpi_get_handle(acpi_handle parent, /* Convert a parent handle to a prefix node */ if (parent) { - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return (status); - } - prefix_node = acpi_ns_map_handle_to_node(parent); if (!prefix_node) { - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); } - - status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return (status); - } - } - - /* Special case for root, since we can't search for it */ - - if (ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH) == 0) { - *ret_handle = - acpi_ns_convert_entry_to_handle(acpi_gbl_root_node); - return (AE_OK); } /* - * Find the Node and convert to a handle + * Valid cases are: + * 1) Fully qualified pathname + * 2) Parent + Relative pathname + * + * Error for */ - status = acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, - &node); + if (acpi_ns_valid_root_prefix(pathname[0])) { - *ret_handle = NULL; + /* Pathname is fully qualified (starts with '\') */ + + /* Special case for root-only, since we can't search for it */ + + if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) { + *ret_handle = + acpi_ns_convert_entry_to_handle(acpi_gbl_root_node); + return (AE_OK); + } + } else if (!prefix_node) { + + /* Relative path with null prefix is disallowed */ + + return (AE_BAD_PARAMETER); + } + + /* Find the Node and convert to a handle */ + + status = + acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node); if (ACPI_SUCCESS(status)) { *ret_handle = acpi_ns_convert_entry_to_handle(node); } diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c index a18b1c223129..faa375887201 100644 --- a/drivers/acpi/namespace/nsxfobj.c +++ b/drivers/acpi/namespace/nsxfobj.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without 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/acpi/osl.c b/drivers/acpi/osl.c index 57ae1e5cde0a..0f6f3bcbc8eb 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,54 @@ static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; static struct workqueue_struct *kacpid_wq; +static void __init acpi_request_region (struct acpi_generic_address *addr, + unsigned int length, char *desc) +{ + struct resource *res; + + if (!addr->address || !length) + return; + + if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO) + res = request_region(addr->address, length, desc); + else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + res = request_mem_region(addr->address, length, desc); +} + +static int __init acpi_reserve_resources(void) +{ + 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_event_block, acpi_gbl_FADT.pm1_event_length, + "ACPI PM1b_EVT_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_control_block, acpi_gbl_FADT.pm1_control_length, + "ACPI PM1b_CNT_BLK"); + + 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_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_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_block_length & 0x1)) + acpi_request_region(&acpi_gbl_FADT.xgpe1_block, + acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK"); + + return 0; +} +device_initcall(acpi_reserve_resources); + acpi_status acpi_os_initialize(void) { return AE_OK; @@ -136,53 +185,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); @@ -254,7 +293,7 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, * FADT. It may not be the same if an interrupt source override exists * for the SCI. */ - gsi = acpi_fadt.sci_int; + gsi = acpi_gbl_FADT.sci_interrupt; if (acpi_gsi_to_irq(gsi, &irq) < 0) { printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n", gsi); diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c index bf88e076c3e9..c2b9835c890b 100644 --- a/drivers/acpi/parser/psargs.c +++ b/drivers/acpi/parser/psargs.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c index e1541db3753a..773aee82fbb8 100644 --- a/drivers/acpi/parser/psloop.c +++ b/drivers/acpi/parser/psloop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,12 +42,11 @@ */ /* - * Parse the AML and build an operation tree as most interpreters, - * like Perl, do. Parsing is done by hand rather than with a YACC - * generated parser to tightly constrain stack and dynamic memory - * usage. At the same time, parsing is kept flexible and the code - * fairly compact by parsing based on a list of AML opcode - * templates in aml_op_info[] + * Parse the AML and build an operation tree as most interpreters, (such as + * Perl) do. Parsing is done by hand rather than with a YACC generated parser + * to tightly constrain stack and dynamic memory usage. Parsing is kept + * flexible and the code fairly compact by parsing based on a list of AML + * opcode templates in aml_op_info[]. */ #include @@ -60,6 +59,761 @@ ACPI_MODULE_NAME("psloop") static u32 acpi_gbl_depth = 0; +/* Local prototypes */ + +static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state); + +static acpi_status +acpi_ps_build_named_op(struct acpi_walk_state *walk_state, + u8 * aml_op_start, + union acpi_parse_object *unnamed_op, + union acpi_parse_object **op); + +static acpi_status +acpi_ps_create_op(struct acpi_walk_state *walk_state, + u8 * aml_op_start, union acpi_parse_object **new_op); + +static acpi_status +acpi_ps_get_arguments(struct acpi_walk_state *walk_state, + u8 * aml_op_start, union acpi_parse_object *op); + +static acpi_status +acpi_ps_complete_op(struct acpi_walk_state *walk_state, + union acpi_parse_object **op, acpi_status status); + +static acpi_status +acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, acpi_status status); + +/******************************************************************************* + * + * FUNCTION: acpi_ps_get_aml_opcode + * + * PARAMETERS: walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Extract the next AML opcode from the input stream. + * + ******************************************************************************/ + +static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) +{ + + ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state); + + walk_state->aml_offset = + (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml, + walk_state->parser_state.aml_start); + walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state)); + + /* + * First cut to determine what we have found: + * 1) A valid AML opcode + * 2) A name string + * 3) An unknown/invalid opcode + */ + walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); + + switch (walk_state->op_info->class) { + case AML_CLASS_ASCII: + case AML_CLASS_PREFIX: + /* + * Starts with a valid prefix or ASCII char, this is a name + * string. Convert the bare name string to a namepath. + */ + walk_state->opcode = AML_INT_NAMEPATH_OP; + walk_state->arg_types = ARGP_NAMESTRING; + break; + + case AML_CLASS_UNKNOWN: + + /* The opcode is unrecognized. Just skip unknown opcodes */ + + ACPI_ERROR((AE_INFO, + "Found unknown opcode %X at AML address %p offset %X, ignoring", + walk_state->opcode, walk_state->parser_state.aml, + walk_state->aml_offset)); + + ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128); + + /* Assume one-byte bad opcode */ + + walk_state->parser_state.aml++; + return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); + + default: + + /* Found opcode info, this is a normal opcode */ + + walk_state->parser_state.aml += + acpi_ps_get_opcode_size(walk_state->opcode); + walk_state->arg_types = walk_state->op_info->parse_args; + break; + } + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ps_build_named_op + * + * PARAMETERS: walk_state - Current state + * aml_op_start - Begin of named Op in AML + * unnamed_op - Early Op (not a named Op) + * Op - Returned Op + * + * RETURN: Status + * + * DESCRIPTION: Parse a named Op + * + ******************************************************************************/ + +static acpi_status +acpi_ps_build_named_op(struct acpi_walk_state *walk_state, + u8 * aml_op_start, + union acpi_parse_object *unnamed_op, + union acpi_parse_object **op) +{ + acpi_status status = AE_OK; + union acpi_parse_object *arg = NULL; + + ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state); + + unnamed_op->common.value.arg = NULL; + unnamed_op->common.aml_opcode = walk_state->opcode; + + /* + * Get and append arguments until we find the node that contains + * the name (the type ARGP_NAME). + */ + while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && + (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) { + status = + acpi_ps_get_next_arg(walk_state, + &(walk_state->parser_state), + GET_CURRENT_ARG_TYPE(walk_state-> + arg_types), &arg); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + acpi_ps_append_arg(unnamed_op, arg); + INCREMENT_ARG_LIST(walk_state->arg_types); + } + + /* + * Make sure that we found a NAME and didn't run out of arguments + */ + if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) { + return_ACPI_STATUS(AE_AML_NO_OPERAND); + } + + /* We know that this arg is a name, move to next arg */ + + INCREMENT_ARG_LIST(walk_state->arg_types); + + /* + * Find the object. This will either insert the object into + * the namespace or simply look it up + */ + walk_state->op = NULL; + + status = walk_state->descending_callback(walk_state, op); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog")); + return_ACPI_STATUS(status); + } + + if (!*op) { + return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); + } + + status = acpi_ps_next_parse_state(walk_state, *op, status); + if (ACPI_FAILURE(status)) { + if (status == AE_CTRL_PENDING) { + return_ACPI_STATUS(AE_CTRL_PARSE_PENDING); + } + return_ACPI_STATUS(status); + } + + acpi_ps_append_arg(*op, unnamed_op->common.value.arg); + acpi_gbl_depth++; + + if ((*op)->common.aml_opcode == AML_REGION_OP) { + /* + * Defer final parsing of an operation_region body, because we don't + * have enough info in the first pass to parse it correctly (i.e., + * there may be method calls within the term_arg elements of the body.) + * + * However, we must continue parsing because the opregion is not a + * standalone package -- we don't know where the end is at this point. + * + * (Length is unknown until parse of the body complete) + */ + (*op)->named.data = aml_op_start; + (*op)->named.length = 0; + } + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ps_create_op + * + * PARAMETERS: walk_state - Current state + * aml_op_start - Op start in AML + * new_op - Returned Op + * + * RETURN: Status + * + * DESCRIPTION: Get Op from AML + * + ******************************************************************************/ + +static acpi_status +acpi_ps_create_op(struct acpi_walk_state *walk_state, + u8 * aml_op_start, union acpi_parse_object **new_op) +{ + acpi_status status = AE_OK; + union acpi_parse_object *op; + union acpi_parse_object *named_op = NULL; + + ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state); + + status = acpi_ps_get_aml_opcode(walk_state); + if (status == AE_CTRL_PARSE_CONTINUE) { + return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); + } + + /* Create Op structure and append to parent's argument list */ + + walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); + op = acpi_ps_alloc_op(walk_state->opcode); + if (!op) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + if (walk_state->op_info->flags & AML_NAMED) { + status = + acpi_ps_build_named_op(walk_state, aml_op_start, op, + &named_op); + acpi_ps_free_op(op); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + *new_op = named_op; + return_ACPI_STATUS(AE_OK); + } + + /* Not a named opcode, just allocate Op and append to parent */ + + if (walk_state->op_info->flags & AML_CREATE) { + /* + * Backup to beginning of create_xXXfield declaration + * body_length is unknown until we parse the body + */ + op->named.data = aml_op_start; + op->named.length = 0; + } + + acpi_ps_append_arg(acpi_ps_get_parent_scope + (&(walk_state->parser_state)), op); + + if (walk_state->descending_callback != NULL) { + /* + * Find the object. This will either insert the object into + * the namespace or simply look it up + */ + walk_state->op = *new_op = op; + + status = walk_state->descending_callback(walk_state, &op); + status = acpi_ps_next_parse_state(walk_state, op, status); + if (status == AE_CTRL_PENDING) { + status = AE_CTRL_PARSE_PENDING; + } + } + + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ps_get_arguments + * + * PARAMETERS: walk_state - Current state + * aml_op_start - Op start in AML + * Op - Current Op + * + * RETURN: Status + * + * DESCRIPTION: Get arguments for passed Op. + * + ******************************************************************************/ + +static acpi_status +acpi_ps_get_arguments(struct acpi_walk_state *walk_state, + u8 * aml_op_start, union acpi_parse_object *op) +{ + acpi_status status = AE_OK; + union acpi_parse_object *arg = NULL; + + ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state); + + switch (op->common.aml_opcode) { + case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ + case AML_WORD_OP: /* AML_WORDDATA_ARG */ + case AML_DWORD_OP: /* AML_DWORDATA_ARG */ + case AML_QWORD_OP: /* AML_QWORDATA_ARG */ + case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ + + /* Fill in constant or string argument directly */ + + acpi_ps_get_next_simple_arg(&(walk_state->parser_state), + GET_CURRENT_ARG_TYPE(walk_state-> + arg_types), + op); + break; + + case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ + + status = + acpi_ps_get_next_namepath(walk_state, + &(walk_state->parser_state), op, + 1); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + walk_state->arg_types = 0; + break; + + default: + /* + * Op is not a constant or string, append each argument to the Op + */ + while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) + && !walk_state->arg_count) { + walk_state->aml_offset = + (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml, + walk_state->parser_state. + aml_start); + + status = + acpi_ps_get_next_arg(walk_state, + &(walk_state->parser_state), + GET_CURRENT_ARG_TYPE + (walk_state->arg_types), &arg); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + if (arg) { + arg->common.aml_offset = walk_state->aml_offset; + acpi_ps_append_arg(op, arg); + } + + INCREMENT_ARG_LIST(walk_state->arg_types); + } + + /* Special processing for certain opcodes */ + + /* TBD (remove): Temporary mechanism to disable this code if needed */ + +#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE + + if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS1) && + ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) { + /* + * We want to skip If/Else/While constructs during Pass1 because we + * want to actually conditionally execute the code during Pass2. + * + * Except for disassembly, where we always want to walk the + * If/Else/While packages + */ + switch (op->common.aml_opcode) { + case AML_IF_OP: + case AML_ELSE_OP: + case AML_WHILE_OP: + + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Pass1: Skipping an If/Else/While body\n")); + + /* Skip body of if/else/while in pass 1 */ + + walk_state->parser_state.aml = + walk_state->parser_state.pkg_end; + walk_state->arg_count = 0; + break; + + default: + break; + } + } +#endif + + switch (op->common.aml_opcode) { + case AML_METHOD_OP: + /* + * Skip parsing of control method because we don't have enough + * info in the first pass to parse it correctly. + * + * Save the length and address of the body + */ + op->named.data = walk_state->parser_state.aml; + op->named.length = (u32) + (walk_state->parser_state.pkg_end - + walk_state->parser_state.aml); + + /* Skip body of method */ + + walk_state->parser_state.aml = + walk_state->parser_state.pkg_end; + walk_state->arg_count = 0; + break; + + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + if ((op->common.parent) && + (op->common.parent->common.aml_opcode == + AML_NAME_OP) + && (walk_state->pass_number <= + ACPI_IMODE_LOAD_PASS2)) { + /* + * Skip parsing of Buffers and Packages because we don't have + * enough info in the first pass to parse them correctly. + */ + op->named.data = aml_op_start; + op->named.length = (u32) + (walk_state->parser_state.pkg_end - + aml_op_start); + + /* Skip body */ + + walk_state->parser_state.aml = + walk_state->parser_state.pkg_end; + walk_state->arg_count = 0; + } + break; + + case AML_WHILE_OP: + + if (walk_state->control_state) { + walk_state->control_state->control.package_end = + walk_state->parser_state.pkg_end; + } + break; + + default: + + /* No action for all other opcodes */ + break; + } + + break; + } + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ps_complete_op + * + * PARAMETERS: walk_state - Current state + * Op - Returned Op + * Status - Parse status before complete Op + * + * RETURN: Status + * + * DESCRIPTION: Complete Op + * + ******************************************************************************/ + +static acpi_status +acpi_ps_complete_op(struct acpi_walk_state *walk_state, + union acpi_parse_object **op, acpi_status status) +{ + acpi_status status2; + + ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state); + + /* + * Finished one argument of the containing scope + */ + walk_state->parser_state.scope->parse_scope.arg_count--; + + /* Close this Op (will result in parse subtree deletion) */ + + status2 = acpi_ps_complete_this_op(walk_state, *op); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); + } + + *op = NULL; + + switch (status) { + case AE_OK: + break; + + case AE_CTRL_TRANSFER: + + /* We are about to transfer to a called method */ + + walk_state->prev_op = NULL; + walk_state->prev_arg_types = walk_state->arg_types; + return_ACPI_STATUS(status); + + case AE_CTRL_END: + + acpi_ps_pop_scope(&(walk_state->parser_state), op, + &walk_state->arg_types, + &walk_state->arg_count); + + if (*op) { + walk_state->op = *op; + walk_state->op_info = + acpi_ps_get_opcode_info((*op)->common.aml_opcode); + walk_state->opcode = (*op)->common.aml_opcode; + + status = walk_state->ascending_callback(walk_state); + status = + acpi_ps_next_parse_state(walk_state, *op, status); + + status2 = acpi_ps_complete_this_op(walk_state, *op); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); + } + } + + status = AE_OK; + break; + + case AE_CTRL_BREAK: + case AE_CTRL_CONTINUE: + + /* Pop off scopes until we find the While */ + + while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) { + acpi_ps_pop_scope(&(walk_state->parser_state), op, + &walk_state->arg_types, + &walk_state->arg_count); + + if ((*op)->common.aml_opcode != AML_WHILE_OP) { + status2 = acpi_ds_result_stack_pop(walk_state); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); + } + } + } + + /* Close this iteration of the While loop */ + + walk_state->op = *op; + walk_state->op_info = + acpi_ps_get_opcode_info((*op)->common.aml_opcode); + walk_state->opcode = (*op)->common.aml_opcode; + + status = walk_state->ascending_callback(walk_state); + status = acpi_ps_next_parse_state(walk_state, *op, status); + + status2 = acpi_ps_complete_this_op(walk_state, *op); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); + } + + status = AE_OK; + break; + + case AE_CTRL_TERMINATE: + + /* Clean up */ + do { + if (*op) { + status2 = + acpi_ps_complete_this_op(walk_state, *op); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); + } + status2 = acpi_ds_result_stack_pop(walk_state); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); + } + + acpi_ut_delete_generic_state + (acpi_ut_pop_generic_state + (&walk_state->control_state)); + } + + acpi_ps_pop_scope(&(walk_state->parser_state), op, + &walk_state->arg_types, + &walk_state->arg_count); + + } while (*op); + + return_ACPI_STATUS(AE_OK); + + default: /* All other non-AE_OK status */ + + do { + if (*op) { + status2 = + acpi_ps_complete_this_op(walk_state, *op); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); + } + } + + acpi_ps_pop_scope(&(walk_state->parser_state), op, + &walk_state->arg_types, + &walk_state->arg_count); + + } while (*op); + +#if 0 + /* + * TBD: Cleanup parse ops on error + */ + if (*op == NULL) { + acpi_ps_pop_scope(parser_state, op, + &walk_state->arg_types, + &walk_state->arg_count); + } +#endif + walk_state->prev_op = NULL; + walk_state->prev_arg_types = walk_state->arg_types; + return_ACPI_STATUS(status); + } + + /* This scope complete? */ + + if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) { + acpi_ps_pop_scope(&(walk_state->parser_state), op, + &walk_state->arg_types, + &walk_state->arg_count); + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op)); + } else { + *op = NULL; + } + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ps_complete_final_op + * + * PARAMETERS: walk_state - Current state + * Op - Current Op + * Status - Current parse status before complete last + * Op + * + * RETURN: Status + * + * DESCRIPTION: Complete last Op. + * + ******************************************************************************/ + +static acpi_status +acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, acpi_status status) +{ + acpi_status status2; + + ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state); + + /* + * Complete the last Op (if not completed), and clear the scope stack. + * It is easily possible to end an AML "package" with an unbounded number + * of open scopes (such as when several ASL blocks are closed with + * sequential closing braces). We want to terminate each one cleanly. + */ + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n", + op)); + do { + if (op) { + if (walk_state->ascending_callback != NULL) { + walk_state->op = op; + walk_state->op_info = + acpi_ps_get_opcode_info(op->common. + aml_opcode); + walk_state->opcode = op->common.aml_opcode; + + status = + walk_state->ascending_callback(walk_state); + status = + acpi_ps_next_parse_state(walk_state, op, + status); + if (status == AE_CTRL_PENDING) { + status = + acpi_ps_complete_op(walk_state, &op, + AE_OK); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + } + + if (status == AE_CTRL_TERMINATE) { + status = AE_OK; + + /* Clean up */ + do { + if (op) { + status2 = + acpi_ps_complete_this_op + (walk_state, op); + if (ACPI_FAILURE + (status2)) { + return_ACPI_STATUS + (status2); + } + } + + acpi_ps_pop_scope(& + (walk_state-> + parser_state), + &op, + &walk_state-> + arg_types, + &walk_state-> + arg_count); + + } while (op); + + return_ACPI_STATUS(status); + } + + else if (ACPI_FAILURE(status)) { + + /* First error is most important */ + + (void) + acpi_ps_complete_this_op(walk_state, + op); + return_ACPI_STATUS(status); + } + } + + status2 = acpi_ps_complete_this_op(walk_state, op); + if (ACPI_FAILURE(status2)) { + return_ACPI_STATUS(status2); + } + } + + acpi_ps_pop_scope(&(walk_state->parser_state), &op, + &walk_state->arg_types, + &walk_state->arg_count); + + } while (op); + + return_ACPI_STATUS(status); +} + /******************************************************************************* * * FUNCTION: acpi_ps_parse_loop @@ -76,10 +830,7 @@ static u32 acpi_gbl_depth = 0; acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) { acpi_status status = AE_OK; - acpi_status status2; union acpi_parse_object *op = NULL; /* current op */ - union acpi_parse_object *arg = NULL; - union acpi_parse_object *pre_op = NULL; struct acpi_parse_state *parser_state; u8 *aml_op_start = NULL; @@ -128,6 +879,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) "Invoked method did not return a value")); } + ACPI_EXCEPTION((AE_INFO, status, "GetPredicate Failed")); return_ACPI_STATUS(status); @@ -158,217 +910,25 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) while ((parser_state->aml < parser_state->aml_end) || (op)) { aml_op_start = parser_state->aml; if (!op) { - - /* Get the next opcode from the AML stream */ - - walk_state->aml_offset = - (u32) ACPI_PTR_DIFF(parser_state->aml, - parser_state->aml_start); - walk_state->opcode = acpi_ps_peek_opcode(parser_state); - - /* - * First cut to determine what we have found: - * 1) A valid AML opcode - * 2) A name string - * 3) An unknown/invalid opcode - */ - walk_state->op_info = - acpi_ps_get_opcode_info(walk_state->opcode); - switch (walk_state->op_info->class) { - case AML_CLASS_ASCII: - case AML_CLASS_PREFIX: - /* - * Starts with a valid prefix or ASCII char, this is a name - * string. Convert the bare name string to a namepath. - */ - walk_state->opcode = AML_INT_NAMEPATH_OP; - walk_state->arg_types = ARGP_NAMESTRING; - break; - - case AML_CLASS_UNKNOWN: - - /* The opcode is unrecognized. Just skip unknown opcodes */ - - ACPI_ERROR((AE_INFO, - "Found unknown opcode %X at AML address %p offset %X, ignoring", - walk_state->opcode, - parser_state->aml, - walk_state->aml_offset)); - - ACPI_DUMP_BUFFER(parser_state->aml, 128); - - /* Assume one-byte bad opcode */ - - parser_state->aml++; - continue; - - default: - - /* Found opcode info, this is a normal opcode */ - - parser_state->aml += - acpi_ps_get_opcode_size(walk_state->opcode); - walk_state->arg_types = - walk_state->op_info->parse_args; - break; - } - - /* Create Op structure and append to parent's argument list */ - - if (walk_state->op_info->flags & AML_NAMED) { - - /* Allocate a new pre_op if necessary */ - - if (!pre_op) { - pre_op = - acpi_ps_alloc_op(walk_state-> - opcode); - if (!pre_op) { - status = AE_NO_MEMORY; - goto close_this_op; - } - } - - pre_op->common.value.arg = NULL; - pre_op->common.aml_opcode = walk_state->opcode; - - /* - * Get and append arguments until we find the node that contains - * the name (the type ARGP_NAME). - */ - while (GET_CURRENT_ARG_TYPE - (walk_state->arg_types) - && - (GET_CURRENT_ARG_TYPE - (walk_state->arg_types) != ARGP_NAME)) { - status = - acpi_ps_get_next_arg(walk_state, - parser_state, - GET_CURRENT_ARG_TYPE - (walk_state-> - arg_types), - &arg); - if (ACPI_FAILURE(status)) { - goto close_this_op; - } - - acpi_ps_append_arg(pre_op, arg); - INCREMENT_ARG_LIST(walk_state-> - arg_types); - } - - /* - * Make sure that we found a NAME and didn't run out of - * arguments - */ - if (!GET_CURRENT_ARG_TYPE - (walk_state->arg_types)) { - status = AE_AML_NO_OPERAND; - goto close_this_op; - } - - /* We know that this arg is a name, move to next arg */ - - INCREMENT_ARG_LIST(walk_state->arg_types); - - /* - * Find the object. This will either insert the object into - * the namespace or simply look it up - */ - walk_state->op = NULL; - - status = - walk_state->descending_callback(walk_state, - &op); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "During name lookup/catalog")); - goto close_this_op; - } - - if (!op) { + status = + acpi_ps_create_op(walk_state, aml_op_start, &op); + if (ACPI_FAILURE(status)) { + if (status == AE_CTRL_PARSE_CONTINUE) { continue; } - status = - acpi_ps_next_parse_state(walk_state, op, - status); - if (status == AE_CTRL_PENDING) { + if (status == AE_CTRL_PARSE_PENDING) { status = AE_OK; - goto close_this_op; } + status = + acpi_ps_complete_op(walk_state, &op, + status); if (ACPI_FAILURE(status)) { - goto close_this_op; + return_ACPI_STATUS(status); } - acpi_ps_append_arg(op, - pre_op->common.value.arg); - acpi_gbl_depth++; - - if (op->common.aml_opcode == AML_REGION_OP) { - /* - * Defer final parsing of an operation_region body, - * because we don't have enough info in the first pass - * to parse it correctly (i.e., there may be method - * calls within the term_arg elements of the body.) - * - * However, we must continue parsing because - * the opregion is not a standalone package -- - * we don't know where the end is at this point. - * - * (Length is unknown until parse of the body complete) - */ - op->named.data = aml_op_start; - op->named.length = 0; - } - } else { - /* Not a named opcode, just allocate Op and append to parent */ - - walk_state->op_info = - acpi_ps_get_opcode_info(walk_state->opcode); - op = acpi_ps_alloc_op(walk_state->opcode); - if (!op) { - status = AE_NO_MEMORY; - goto close_this_op; - } - - if (walk_state->op_info->flags & AML_CREATE) { - /* - * Backup to beginning of create_xXXfield declaration - * body_length is unknown until we parse the body - */ - op->named.data = aml_op_start; - op->named.length = 0; - } - - acpi_ps_append_arg(acpi_ps_get_parent_scope - (parser_state), op); - - if ((walk_state->descending_callback != NULL)) { - /* - * Find the object. This will either insert the object into - * the namespace or simply look it up - */ - walk_state->op = op; - - status = - walk_state-> - descending_callback(walk_state, - &op); - status = - acpi_ps_next_parse_state(walk_state, - op, - status); - if (status == AE_CTRL_PENDING) { - status = AE_OK; - goto close_this_op; - } - - if (ACPI_FAILURE(status)) { - goto close_this_op; - } - } + continue; } op->common.aml_offset = walk_state->aml_offset; @@ -395,172 +955,17 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) /* Get arguments */ - switch (op->common.aml_opcode) { - case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ - case AML_WORD_OP: /* AML_WORDDATA_ARG */ - case AML_DWORD_OP: /* AML_DWORDATA_ARG */ - case AML_QWORD_OP: /* AML_QWORDATA_ARG */ - case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ - - /* Fill in constant or string argument directly */ - - acpi_ps_get_next_simple_arg(parser_state, - GET_CURRENT_ARG_TYPE - (walk_state-> - arg_types), op); - break; - - case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ - + status = + acpi_ps_get_arguments(walk_state, aml_op_start, op); + if (ACPI_FAILURE(status)) { status = - acpi_ps_get_next_namepath(walk_state, - parser_state, op, - 1); + acpi_ps_complete_op(walk_state, &op, + status); if (ACPI_FAILURE(status)) { - goto close_this_op; + return_ACPI_STATUS(status); } - walk_state->arg_types = 0; - break; - - default: - /* - * Op is not a constant or string, append each argument - * to the Op - */ - while (GET_CURRENT_ARG_TYPE - (walk_state->arg_types) - && !walk_state->arg_count) { - walk_state->aml_offset = (u32) - ACPI_PTR_DIFF(parser_state->aml, - parser_state-> - aml_start); - - status = - acpi_ps_get_next_arg(walk_state, - parser_state, - GET_CURRENT_ARG_TYPE - (walk_state-> - arg_types), - &arg); - if (ACPI_FAILURE(status)) { - goto close_this_op; - } - - if (arg) { - arg->common.aml_offset = - walk_state->aml_offset; - acpi_ps_append_arg(op, arg); - } - INCREMENT_ARG_LIST(walk_state-> - arg_types); - } - - /* Special processing for certain opcodes */ - - /* TBD (remove): Temporary mechanism to disable this code if needed */ - -#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE - - if ((walk_state->pass_number <= - ACPI_IMODE_LOAD_PASS1) - && - ((walk_state-> - parse_flags & ACPI_PARSE_DISASSEMBLE) == - 0)) { - /* - * We want to skip If/Else/While constructs during Pass1 - * because we want to actually conditionally execute the - * code during Pass2. - * - * Except for disassembly, where we always want to - * walk the If/Else/While packages - */ - switch (op->common.aml_opcode) { - case AML_IF_OP: - case AML_ELSE_OP: - case AML_WHILE_OP: - - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Pass1: Skipping an If/Else/While body\n")); - - /* Skip body of if/else/while in pass 1 */ - - parser_state->aml = - parser_state->pkg_end; - walk_state->arg_count = 0; - break; - - default: - break; - } - } -#endif - switch (op->common.aml_opcode) { - case AML_METHOD_OP: - - /* - * Skip parsing of control method - * because we don't have enough info in the first pass - * to parse it correctly. - * - * Save the length and address of the body - */ - op->named.data = parser_state->aml; - op->named.length = - (u32) (parser_state->pkg_end - - parser_state->aml); - - /* Skip body of method */ - - parser_state->aml = - parser_state->pkg_end; - walk_state->arg_count = 0; - break; - - case AML_BUFFER_OP: - case AML_PACKAGE_OP: - case AML_VAR_PACKAGE_OP: - - if ((op->common.parent) && - (op->common.parent->common. - aml_opcode == AML_NAME_OP) - && (walk_state->pass_number <= - ACPI_IMODE_LOAD_PASS2)) { - /* - * Skip parsing of Buffers and Packages - * because we don't have enough info in the first pass - * to parse them correctly. - */ - op->named.data = aml_op_start; - op->named.length = - (u32) (parser_state-> - pkg_end - - aml_op_start); - - /* Skip body */ - - parser_state->aml = - parser_state->pkg_end; - walk_state->arg_count = 0; - } - break; - - case AML_WHILE_OP: - - if (walk_state->control_state) { - walk_state->control_state-> - control.package_end = - parser_state->pkg_end; - } - break; - - default: - - /* No action for all other opcodes */ - break; - } - break; + continue; } } @@ -575,8 +980,16 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) walk_state->arg_types, walk_state->arg_count); if (ACPI_FAILURE(status)) { - goto close_this_op; + status = + acpi_ps_complete_op(walk_state, &op, + status); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + continue; } + op = NULL; continue; } @@ -628,269 +1041,16 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) acpi_ps_next_parse_state(walk_state, op, status); if (status == AE_CTRL_PENDING) { status = AE_OK; - goto close_this_op; } } - close_this_op: - /* - * Finished one argument of the containing scope - */ - parser_state->scope->parse_scope.arg_count--; - - /* Finished with pre_op */ - - if (pre_op) { - acpi_ps_free_op(pre_op); - pre_op = NULL; - } - - /* Close this Op (will result in parse subtree deletion) */ - - status2 = acpi_ps_complete_this_op(walk_state, op); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } - op = NULL; - - switch (status) { - case AE_OK: - break; - - case AE_CTRL_TRANSFER: - - /* We are about to transfer to a called method. */ - - walk_state->prev_op = op; - walk_state->prev_arg_types = walk_state->arg_types; + status = acpi_ps_complete_op(walk_state, &op, status); + if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); - - case AE_CTRL_END: - - acpi_ps_pop_scope(parser_state, &op, - &walk_state->arg_types, - &walk_state->arg_count); - - if (op) { - walk_state->op = op; - walk_state->op_info = - acpi_ps_get_opcode_info(op->common. - aml_opcode); - walk_state->opcode = op->common.aml_opcode; - - status = - walk_state->ascending_callback(walk_state); - status = - acpi_ps_next_parse_state(walk_state, op, - status); - - status2 = - acpi_ps_complete_this_op(walk_state, op); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } - op = NULL; - } - status = AE_OK; - break; - - case AE_CTRL_BREAK: - case AE_CTRL_CONTINUE: - - /* Pop off scopes until we find the While */ - - while (!op || (op->common.aml_opcode != AML_WHILE_OP)) { - acpi_ps_pop_scope(parser_state, &op, - &walk_state->arg_types, - &walk_state->arg_count); - - if (op->common.aml_opcode != AML_WHILE_OP) { - status2 = - acpi_ds_result_stack_pop - (walk_state); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } - } - } - - /* Close this iteration of the While loop */ - - walk_state->op = op; - walk_state->op_info = - acpi_ps_get_opcode_info(op->common.aml_opcode); - walk_state->opcode = op->common.aml_opcode; - - status = walk_state->ascending_callback(walk_state); - status = - acpi_ps_next_parse_state(walk_state, op, status); - - status2 = acpi_ps_complete_this_op(walk_state, op); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } - op = NULL; - - status = AE_OK; - break; - - case AE_CTRL_TERMINATE: - - status = AE_OK; - - /* Clean up */ - do { - if (op) { - status2 = - acpi_ps_complete_this_op(walk_state, - op); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } - - status2 = - acpi_ds_result_stack_pop - (walk_state); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } - - acpi_ut_delete_generic_state - (acpi_ut_pop_generic_state - (&walk_state->control_state)); - } - - acpi_ps_pop_scope(parser_state, &op, - &walk_state->arg_types, - &walk_state->arg_count); - - } while (op); - - return_ACPI_STATUS(status); - - default: /* All other non-AE_OK status */ - - do { - if (op) { - status2 = - acpi_ps_complete_this_op(walk_state, - op); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } - } - - acpi_ps_pop_scope(parser_state, &op, - &walk_state->arg_types, - &walk_state->arg_count); - - } while (op); - - /* - * TBD: Cleanup parse ops on error - */ -#if 0 - if (op == NULL) { - acpi_ps_pop_scope(parser_state, &op, - &walk_state->arg_types, - &walk_state->arg_count); - } -#endif - walk_state->prev_op = op; - walk_state->prev_arg_types = walk_state->arg_types; - return_ACPI_STATUS(status); - } - - /* This scope complete? */ - - if (acpi_ps_has_completed_scope(parser_state)) { - acpi_ps_pop_scope(parser_state, &op, - &walk_state->arg_types, - &walk_state->arg_count); - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Popped scope, Op=%p\n", op)); - } else { - op = NULL; } } /* while parser_state->Aml */ - /* - * Complete the last Op (if not completed), and clear the scope stack. - * It is easily possible to end an AML "package" with an unbounded number - * of open scopes (such as when several ASL blocks are closed with - * sequential closing braces). We want to terminate each one cleanly. - */ - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n", - op)); - do { - if (op) { - if (walk_state->ascending_callback != NULL) { - walk_state->op = op; - walk_state->op_info = - acpi_ps_get_opcode_info(op->common. - aml_opcode); - walk_state->opcode = op->common.aml_opcode; - - status = - walk_state->ascending_callback(walk_state); - status = - acpi_ps_next_parse_state(walk_state, op, - status); - if (status == AE_CTRL_PENDING) { - status = AE_OK; - goto close_this_op; - } - - if (status == AE_CTRL_TERMINATE) { - status = AE_OK; - - /* Clean up */ - do { - if (op) { - status2 = - acpi_ps_complete_this_op - (walk_state, op); - if (ACPI_FAILURE - (status2)) { - return_ACPI_STATUS - (status2); - } - } - - acpi_ps_pop_scope(parser_state, - &op, - &walk_state-> - arg_types, - &walk_state-> - arg_count); - - } while (op); - - return_ACPI_STATUS(status); - } - - else if (ACPI_FAILURE(status)) { - - /* First error is most important */ - - (void) - acpi_ps_complete_this_op(walk_state, - op); - return_ACPI_STATUS(status); - } - } - - status2 = acpi_ps_complete_this_op(walk_state, op); - if (ACPI_FAILURE(status2)) { - return_ACPI_STATUS(status2); - } - } - - acpi_ps_pop_scope(parser_state, &op, &walk_state->arg_types, - &walk_state->arg_count); - - } while (op); - + status = acpi_ps_complete_final_op(walk_state, op, status); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c index 4bd25e32769f..16d8b6cc3c22 100644 --- a/drivers/acpi/parser/psopcode.c +++ b/drivers/acpi/parser/psopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c index a02aa62fe1e5..5d63f48e56b5 100644 --- a/drivers/acpi/parser/psparse.c +++ b/drivers/acpi/parser/psparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -540,6 +540,11 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) if ((status == AE_ALREADY_EXISTS) && (!walk_state->method_desc->method.mutex)) { + ACPI_INFO((AE_INFO, + "Marking method %4.4s as Serialized", + walk_state->method_node->name. + ascii)); + /* * Method tried to create an object twice. The probable cause is * that the method cannot handle reentrancy. diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c index a3e0314de24d..77cfa4ed0cfe 100644 --- a/drivers/acpi/parser/psscope.c +++ b/drivers/acpi/parser/psscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c index 0015717ef096..966e7ea2a0c4 100644 --- a/drivers/acpi/parser/pstree.c +++ b/drivers/acpi/parser/pstree.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c index d405387b7414..8ca52002db55 100644 --- a/drivers/acpi/parser/psutils.c +++ b/drivers/acpi/parser/psutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c index a84a547a0f1b..49f9757434e4 100644 --- a/drivers/acpi/parser/pswalk.c +++ b/drivers/acpi/parser/pswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c index 5d996c1140af..94103bced75e 100644 --- a/drivers/acpi/parser/psxface.c +++ b/drivers/acpi/parser/psxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,8 +54,6 @@ static void acpi_ps_start_trace(struct acpi_evaluate_info *info); static void acpi_ps_stop_trace(struct acpi_evaluate_info *info); -static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info); - static void acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action); @@ -215,6 +213,8 @@ static void acpi_ps_stop_trace(struct acpi_evaluate_info *info) acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) { acpi_status status; + union acpi_parse_object *op; + struct acpi_walk_state *walk_state; ACPI_FUNCTION_TRACE(ps_execute_method); @@ -234,8 +234,7 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) } /* - * The caller "owns" the parameters, so give each one an extra - * reference + * The caller "owns" the parameters, so give each one an extra reference */ acpi_ps_update_parameter_list(info, REF_INCREMENT); @@ -244,30 +243,50 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) acpi_ps_start_trace(info); /* - * 1) Perform the first pass parse of the method to enter any - * named objects that it creates into the namespace + * Execute the method. Performs parse simultaneously */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "**** Begin Method Parse **** Entry=%p obj=%p\n", - info->resolved_node, info->obj_desc)); + "**** Begin Method Parse/Execute [%4.4s] **** Node=%p Obj=%p\n", + info->resolved_node->name.ascii, info->resolved_node, + info->obj_desc)); - info->pass_number = 1; - status = acpi_ps_execute_pass(info); - if (ACPI_FAILURE(status)) { + /* Create and init a Root Node */ + + op = acpi_ps_create_scope_op(); + if (!op) { + status = AE_NO_MEMORY; goto cleanup; } - /* - * 2) Execute the method. Performs second pass parse simultaneously - */ - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "**** Begin Method Execution **** Entry=%p obj=%p\n", - info->resolved_node, info->obj_desc)); + /* Create and initialize a new walk state */ - info->pass_number = 3; - status = acpi_ps_execute_pass(info); + info->pass_number = ACPI_IMODE_EXECUTE; + walk_state = + acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL, + NULL, NULL); + if (!walk_state) { + status = AE_NO_MEMORY; + goto cleanup; + } + + status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node, + info->obj_desc->method.aml_start, + info->obj_desc->method.aml_length, info, + info->pass_number); + if (ACPI_FAILURE(status)) { + acpi_ds_delete_walk_state(walk_state); + goto cleanup; + } + + /* Parse the AML */ + + status = acpi_ps_parse_aml(walk_state); + + /* walk_state was deleted by parse_aml */ cleanup: + acpi_ps_delete_parse_tree(op); + /* End optional tracing */ acpi_ps_stop_trace(info); @@ -330,62 +349,3 @@ acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action) } } } - -/******************************************************************************* - * - * FUNCTION: acpi_ps_execute_pass - * - * PARAMETERS: Info - See struct acpi_evaluate_info - * (Used: pass_number, Node, and obj_desc) - * - * RETURN: Status - * - * DESCRIPTION: Single AML pass: Parse or Execute a control method - * - ******************************************************************************/ - -static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info) -{ - acpi_status status; - union acpi_parse_object *op; - struct acpi_walk_state *walk_state; - - ACPI_FUNCTION_TRACE(ps_execute_pass); - - /* Create and init a Root Node */ - - op = acpi_ps_create_scope_op(); - if (!op) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* Create and initialize a new walk state */ - - walk_state = - acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL, - NULL, NULL); - if (!walk_state) { - status = AE_NO_MEMORY; - goto cleanup; - } - - status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node, - info->obj_desc->method.aml_start, - info->obj_desc->method.aml_length, - info->pass_number == 1 ? NULL : info, - info->pass_number); - if (ACPI_FAILURE(status)) { - acpi_ds_delete_walk_state(walk_state); - goto cleanup; - } - - /* Parse the AML */ - - status = acpi_ps_parse_aml(walk_state); - - /* Walk state was deleted by parse_aml */ - - cleanup: - acpi_ps_delete_parse_tree(op); - return_ACPI_STATUS(status); -} diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 481e633bbf41..0f683c8c6fbc 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -513,7 +513,7 @@ int __init acpi_irq_penalty_init(void) } } /* Add a penalty for the SCI */ - acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING; + acpi_irq_penalty[acpi_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING; return 0; } @@ -785,7 +785,7 @@ static int irqrouter_resume(struct sys_device *dev) /* Make sure SCI is enabled again (Apple firmware bug?) */ - acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1, ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1); list_for_each(node, &acpi_link.entries) { link = list_entry(node, struct acpi_pci_link, node); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index a860efa2c562..4ecf701687e8 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -117,6 +117,19 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) EXPORT_SYMBOL(acpi_pci_unregister_driver); +acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) +{ + struct acpi_pci_root *tmp; + + list_for_each_entry(tmp, &acpi_pci_roots, node) { + if ((tmp->id.segment == (u16) seg) && (tmp->id.bus == (u16) bus)) + return tmp->device->handle; + } + return NULL; +} + +EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle); + static acpi_status get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) { @@ -152,6 +165,21 @@ static acpi_status try_get_root_bridge_busnr(acpi_handle handle, int *busnum) return AE_OK; } +static void acpi_pci_bridge_scan(struct acpi_device *device) +{ + int status; + struct acpi_device *child = NULL; + + if (device->flags.bus_address) + if (device->parent && device->parent->ops.bind) { + status = device->parent->ops.bind(device); + if (!status) { + list_for_each_entry(child, &device->children, node) + acpi_pci_bridge_scan(child); + } + } +} + static int acpi_pci_root_add(struct acpi_device *device) { int result = 0; @@ -160,6 +188,7 @@ static int acpi_pci_root_add(struct acpi_device *device) acpi_status status = AE_OK; unsigned long value = 0; acpi_handle handle = NULL; + struct acpi_device *child; if (!device) @@ -175,9 +204,6 @@ static int acpi_pci_root_add(struct acpi_device *device) strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); acpi_driver_data(device) = root; - /* - * TBD: Doesn't the bus driver automatically set this? - */ device->ops.bind = acpi_pci_bind; /* @@ -299,6 +325,12 @@ static int acpi_pci_root_add(struct acpi_device *device) result = acpi_pci_irq_add_prt(device->handle, root->id.segment, root->id.bus); + /* + * Scan and bind all _ADR-Based Devices + */ + list_for_each_entry(child, &device->children, node) + acpi_pci_bridge_scan(child); + end: if (result) { if (!list_empty(&root->node)) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 5f9496d59ed6..0079bc51082c 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -375,30 +375,126 @@ static int acpi_processor_remove_fs(struct acpi_device *device) } /* Use the acpiid in MADT to map cpus in case of SMP */ + #ifndef CONFIG_SMP -#define convert_acpiid_to_cpu(acpi_id) (-1) +static int get_cpu_id(acpi_handle handle, u32 acpi_id) {return -1;} #else +static struct acpi_table_madt *madt; + +static int map_lapic_id(struct acpi_subtable_header *entry, + u32 acpi_id, int *apic_id) +{ + struct acpi_madt_local_apic *lapic = + (struct acpi_madt_local_apic *)entry; + if ((lapic->lapic_flags & ACPI_MADT_ENABLED) && + lapic->processor_id == acpi_id) { + *apic_id = lapic->id; + return 1; + } + return 0; +} + +static int map_lsapic_id(struct acpi_subtable_header *entry, + u32 acpi_id, int *apic_id) +{ + struct acpi_madt_local_sapic *lsapic = + (struct acpi_madt_local_sapic *)entry; + /* Only check enabled APICs*/ + if (lsapic->lapic_flags & ACPI_MADT_ENABLED) { + /* First check against id */ + if (lsapic->processor_id == acpi_id) { + *apic_id = lsapic->id; + return 1; + /* Check against optional uid */ + } else if (entry->length >= 16 && + lsapic->uid == acpi_id) { + *apic_id = lsapic->uid; + return 1; + } + } + return 0; +} + #ifdef CONFIG_IA64 -#define arch_acpiid_to_apicid ia64_acpiid_to_sapicid #define arch_cpu_to_apicid ia64_cpu_to_sapicid -#define ARCH_BAD_APICID (0xffff) #else -#define arch_acpiid_to_apicid x86_acpiid_to_apicid #define arch_cpu_to_apicid x86_cpu_to_apicid -#define ARCH_BAD_APICID (0xff) #endif -static int convert_acpiid_to_cpu(u8 acpi_id) +static int map_madt_entry(u32 acpi_id) +{ + unsigned long madt_end, entry; + int apic_id = -1; + + if (!madt) + return apic_id; + + entry = (unsigned long)madt; + madt_end = entry + madt->header.length; + + /* Parse all entries looking for a match. */ + + entry += sizeof(struct acpi_table_madt); + while (entry + sizeof(struct acpi_subtable_header) < madt_end) { + struct acpi_subtable_header *header = + (struct acpi_subtable_header *)entry; + if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) { + if (map_lapic_id(header, acpi_id, &apic_id)) + break; + } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { + if (map_lsapic_id(header, acpi_id, &apic_id)) + break; + } + entry += header->length; + } + return apic_id; +} + +static int map_mat_entry(acpi_handle handle, u32 acpi_id) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + struct acpi_subtable_header *header; + int apic_id = -1; + + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) + goto exit; + + if (!buffer.length || !buffer.pointer) + goto exit; + + obj = buffer.pointer; + if (obj->type != ACPI_TYPE_BUFFER || + obj->buffer.length < sizeof(struct acpi_subtable_header)) { + goto exit; + } + + header = (struct acpi_subtable_header *)obj->buffer.pointer; + if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) { + map_lapic_id(header, acpi_id, &apic_id); + } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { + map_lsapic_id(header, acpi_id, &apic_id); + } + +exit: + if (buffer.pointer) + kfree(buffer.pointer); + return apic_id; +} + +static int get_cpu_id(acpi_handle handle, u32 acpi_id) { - u16 apic_id; int i; + int apic_id = -1; - apic_id = arch_acpiid_to_apicid[acpi_id]; - if (apic_id == ARCH_BAD_APICID) - return -1; + apic_id = map_mat_entry(handle, acpi_id); + if (apic_id == -1) + apic_id = map_madt_entry(acpi_id); + if (apic_id == -1) + return apic_id; - for (i = 0; i < NR_CPUS; i++) { + for (i = 0; i < NR_CPUS; ++i) { if (arch_cpu_to_apicid[i] == apic_id) return i; } @@ -410,7 +506,7 @@ static int convert_acpiid_to_cpu(u8 acpi_id) Driver Interface -------------------------------------------------------------------------- */ -static int acpi_processor_get_info(struct acpi_processor *pr) +static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid) { acpi_status status = 0; union acpi_object object = { 0 }; @@ -431,7 +527,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_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) { pr->flags.bm_control = 1; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Bus mastering arbitration control present\n")); @@ -439,24 +535,35 @@ static int acpi_processor_get_info(struct acpi_processor *pr) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No bus mastering arbitration control\n")); - /* - * Evalute the processor object. Note that it is common on SMP to - * have the first (boot) processor with a valid PBLK address while - * all others have a NULL address. - */ - status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Evaluating processor object\n"); - return -ENODEV; + /* Check if it is a Device with HID and UID */ + if (has_uid) { + unsigned long value; + status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, + NULL, &value); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Evaluating processor _UID\n"); + return -ENODEV; + } + pr->acpi_id = value; + } else { + /* + * Evalute the processor object. Note that it is common on SMP to + * have the first (boot) processor with a valid PBLK address while + * all others have a NULL address. + */ + status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX "Evaluating processor object\n"); + return -ENODEV; + } + + /* + * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. + * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c + */ + pr->acpi_id = object.processor.proc_id; } - - /* - * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. - * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c - */ - pr->acpi_id = object.processor.proc_id; - - cpu_index = convert_acpiid_to_cpu(pr->acpi_id); + cpu_index = get_cpu_id(pr->handle, pr->acpi_id); /* Handle UP system running SMP kernel, with no LAPIC in MADT */ if (!cpu0_initialized && (cpu_index == -1) && @@ -473,7 +580,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr) * less than the max # of CPUs. They should be ignored _iff * they are physically not present. */ - if (cpu_index == -1) { + if (pr->id == -1) { if (ACPI_FAILURE (acpi_processor_hotadd_init(pr->handle, &pr->id))) { return -ENODEV; @@ -490,8 +597,8 @@ static int acpi_processor_get_info(struct acpi_processor *pr) object.processor.pblk_length); else { pr->throttling.address = object.processor.pblk_address; - pr->throttling.duty_offset = acpi_fadt.duty_offset; - pr->throttling.duty_width = acpi_fadt.duty_width; + pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset; + pr->throttling.duty_width = acpi_gbl_FADT.duty_width; pr->pblk = object.processor.pblk_address; @@ -525,7 +632,7 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) pr = acpi_driver_data(device); - result = acpi_processor_get_info(pr); + result = acpi_processor_get_info(pr, device->flags.unique_id); if (result) { /* Processor is physically not present */ return 0; @@ -707,7 +814,7 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) return -ENODEV; if ((pr->id >= 0) && (pr->id < NR_CPUS)) { - kobject_uevent(&(*device)->kobj, KOBJ_ONLINE); + kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE); } return 0; } @@ -745,13 +852,13 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) } if (pr->id >= 0 && (pr->id < NR_CPUS)) { - kobject_uevent(&device->kobj, KOBJ_OFFLINE); + kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); break; } result = acpi_processor_start(device); if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) { - kobject_uevent(&device->kobj, KOBJ_ONLINE); + kobject_uevent(&device->dev.kobj, KOBJ_ONLINE); } else { printk(KERN_ERR PREFIX "Device [%s] failed to start\n", acpi_device_bid(device)); @@ -774,7 +881,7 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) } if ((pr->id < NR_CPUS) && (cpu_present(pr->id))) - kobject_uevent(&device->kobj, KOBJ_OFFLINE); + kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -895,6 +1002,12 @@ static int __init acpi_processor_init(void) memset(&processors, 0, sizeof(processors)); memset(&errata, 0, sizeof(errata)); +#ifdef CONFIG_SMP + if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, + (struct acpi_table_header **)&madt))) + madt = 0; +#endif + acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); if (!acpi_processor_dir) return -ENOMEM; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 3f30af21574e..6c6751b1405b 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_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER)) return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF); else return ((0xFFFFFFFF - t1) + t2); @@ -187,8 +187,7 @@ acpi_processor_power_activate(struct acpi_processor *pr, case ACPI_STATE_C3: /* Disable bus master reload */ if (new->type != ACPI_STATE_C3 && pr->flags.bm_check) - acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0); break; } } @@ -198,8 +197,7 @@ acpi_processor_power_activate(struct acpi_processor *pr, case ACPI_STATE_C3: /* Enable bus master reload */ if (old->type != ACPI_STATE_C3 && pr->flags.bm_check) - acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1); break; } @@ -236,7 +234,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_gbl_FADT.xpm_timer_block.address); } } @@ -291,12 +289,10 @@ static void acpi_processor_idle(void) pr->power.bm_activity <<= diff; - acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, - &bm_status, ACPI_MTX_DO_NOT_LOCK); + acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status); if (bm_status) { pr->power.bm_activity |= 0x1; - acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, - 1, ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1); } /* * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect @@ -338,7 +334,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_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) cx = &pr->power.states[ACPI_STATE_C1]; #endif @@ -384,11 +380,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_gbl_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_gbl_FADT.xpm_timer_block.address); #ifdef CONFIG_GENERIC_TIME /* TSC halts in C2, so notify users */ @@ -411,8 +407,7 @@ static void acpi_processor_idle(void) * All CPUs are trying to go to C3 * Disable bus master arbitration */ - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1); } } else { /* SMP with no shared cache... Invalidate cache */ @@ -420,16 +415,15 @@ static void acpi_processor_idle(void) } /* Get start time (ticks) */ - t1 = inl(acpi_fadt.xpm_tmr_blk.address); + t1 = inl(acpi_gbl_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_gbl_FADT.xpm_timer_block.address); if (pr->flags.bm_check) { /* Enable bus master arbitration */ atomic_dec(&c3_cpu_count); - acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, - ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); } #ifdef CONFIG_GENERIC_TIME @@ -457,7 +451,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_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) { next_state = cx; goto end; } @@ -627,7 +621,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_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) return -ENODEV; #endif @@ -636,8 +631,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_gbl_FADT.C2latency; + pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.C3latency; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "lvl2[0x%08x] lvl3[0x%08x]\n", @@ -883,14 +878,13 @@ 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_gbl_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")); return; } - acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, - 0, ACPI_MTX_DO_NOT_LOCK); + acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0); } /* @@ -1096,7 +1090,7 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset) seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n", pr->power.states[i].latency, pr->power.states[i].usage, - pr->power.states[i].time); + (unsigned long long)pr->power.states[i].time); } end: @@ -1164,9 +1158,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, if (!pr) return -EINVAL; - if (acpi_fadt.cst_cnt && !nocst) { + if (acpi_gbl_FADT.cst_control && !nocst) { status = - acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8); + acpi_os_write_port(acpi_gbl_FADT.smi_command, acpi_gbl_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..058f13cf3b79 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_gbl_FADT.smi_command) || (!acpi_gbl_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_gbl_FADT.pstate_control, acpi_gbl_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_gbl_FADT.smi_command, + (u32) acpi_gbl_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_gbl_FADT.pstate_control, + acpi_gbl_FADT.smi_command)); module_put(calling_module); return status; } diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 0ec7dcde0063..89dff3639abe 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -125,7 +125,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state) /* Used to clear all duty_value bits */ duty_mask = pr->throttling.state_count - 1; - duty_mask <<= acpi_fadt.duty_offset; + duty_mask <<= acpi_gbl_FADT.duty_offset; duty_mask = ~duty_mask; } @@ -208,7 +208,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr) return 0; } - pr->throttling.state_count = 1 << acpi_fadt.duty_width; + pr->throttling.state_count = 1 << acpi_gbl_FADT.duty_width; /* * Compute state values. Note that throttling displays a linear power/ diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c index 8fa3213ce000..271e61509eeb 100644 --- a/drivers/acpi/resources/rsaddr.c +++ b/drivers/acpi/resources/rsaddr.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c index cf87b0230026..8c6d3fdec38a 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/resources/rscalc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c index 008058acdd39..1358c06a969c 100644 --- a/drivers/acpi/resources/rscreate.c +++ b/drivers/acpi/resources/rscreate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c index 9c99a723a860..de20a5d6decf 100644 --- a/drivers/acpi/resources/rsdump.c +++ b/drivers/acpi/resources/rsdump.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c index 9e7ae2f8a1d3..7e3c335ab320 100644 --- a/drivers/acpi/resources/rsinfo.c +++ b/drivers/acpi/resources/rsinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c index ea567167c4f2..b297bc3e4419 100644 --- a/drivers/acpi/resources/rsio.c +++ b/drivers/acpi/resources/rsio.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c index 1fa63bc2e36f..5657f7b95039 100644 --- a/drivers/acpi/resources/rsirq.c +++ b/drivers/acpi/resources/rsirq.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c index 29423ce030ca..a92755c8877d 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/resources/rslist.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c index a5131936d690..521eab7dd8df 100644 --- a/drivers/acpi/resources/rsmemory.c +++ b/drivers/acpi/resources/rsmemory.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c index faf6e106b785..3b63b561b94e 100644 --- a/drivers/acpi/resources/rsmisc.c +++ b/drivers/acpi/resources/rsmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c index a9cbee8e8b44..2442a8f8df57 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/resources/rsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c index 1999e2ab7daa..991f8901498c 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/resources/rsxface.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 283d87522c5d..64f26db10c8e 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -21,101 +21,305 @@ extern struct acpi_device *acpi_root; #define ACPI_BUS_DEVICE_NAME "System Bus" static LIST_HEAD(acpi_device_list); +static LIST_HEAD(acpi_bus_id_list); DEFINE_SPINLOCK(acpi_device_lock); LIST_HEAD(acpi_wakeup_device_list); - -static void acpi_device_release(struct kobject *kobj) +struct acpi_device_bus_id{ + char bus_id[15]; + unsigned int instance_no; + struct list_head node; +}; +static int acpi_eject_operation(acpi_handle handle, int lockable) { - struct acpi_device *dev = container_of(kobj, struct acpi_device, kobj); - kfree(dev->pnp.cid_list); - kfree(dev); + struct acpi_object_list arg_list; + union acpi_object arg; + acpi_status status = AE_OK; + + /* + * TBD: evaluate _PS3? + */ + + if (lockable) { + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 0; + acpi_evaluate_object(handle, "_LCK", &arg_list, NULL); + } + + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; + + /* + * TBD: _EJD support. + */ + + status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); + if (ACPI_FAILURE(status)) { + return (-ENODEV); + } + + return (0); } -struct acpi_device_attribute { - struct attribute attr; - ssize_t(*show) (struct acpi_device *, char *); - ssize_t(*store) (struct acpi_device *, const char *, size_t); -}; - -typedef void acpi_device_sysfs_files(struct kobject *, - const struct attribute *); - -static void setup_sys_fs_device_files(struct acpi_device *dev, - acpi_device_sysfs_files * func); - -#define create_sysfs_device_files(dev) \ - setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file) -#define remove_sysfs_device_files(dev) \ - setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file) - -#define to_acpi_device(n) container_of(n, struct acpi_device, kobj) -#define to_handle_attr(n) container_of(n, struct acpi_device_attribute, attr); - -static ssize_t acpi_device_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) +static ssize_t +acpi_eject_store(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) { - struct acpi_device *device = to_acpi_device(kobj); - struct acpi_device_attribute *attribute = to_handle_attr(attr); - return attribute->show ? attribute->show(device, buf) : -EIO; -} -static ssize_t acpi_device_attr_store(struct kobject *kobj, - struct attribute *attr, const char *buf, - size_t len) -{ - struct acpi_device *device = to_acpi_device(kobj); - struct acpi_device_attribute *attribute = to_handle_attr(attr); - return attribute->store ? attribute->store(device, buf, len) : -EIO; + int result; + int ret = count; + int islockable; + acpi_status status; + acpi_handle handle; + acpi_object_type type = 0; + struct acpi_device *acpi_device = to_acpi_device(d); + + if ((!count) || (buf[0] != '1')) { + return -EINVAL; + } +#ifndef FORCE_EJECT + if (acpi_device->driver == NULL) { + ret = -ENODEV; + goto err; + } +#endif + status = acpi_get_type(acpi_device->handle, &type); + if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) { + ret = -ENODEV; + goto err; + } + + islockable = acpi_device->flags.lockable; + handle = acpi_device->handle; + + result = acpi_bus_trim(acpi_device, 1); + + if (!result) + result = acpi_eject_operation(handle, islockable); + + if (result) { + ret = -EBUSY; + } + err: + return ret; } -static struct sysfs_ops acpi_device_sysfs_ops = { - .show = acpi_device_attr_show, - .store = acpi_device_attr_store, -}; +static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); -static struct kobj_type ktype_acpi_ns = { - .sysfs_ops = &acpi_device_sysfs_ops, - .release = acpi_device_release, -}; +static ssize_t +acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); -static int namespace_uevent(struct kset *kset, struct kobject *kobj, - char **envp, int num_envp, char *buffer, - int buffer_size) + return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id); +} +static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); + +static ssize_t +acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; + int result; + + result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path); + if(result) + goto end; + + result = sprintf(buf, "%s\n", (char*)path.pointer); + kfree(path.pointer); + end: + return result; +} +static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL); + +static int acpi_device_setup_files(struct acpi_device *dev) { - struct acpi_device *dev = to_acpi_device(kobj); - int i = 0; - int len = 0; + acpi_status status; + acpi_handle temp; + int result = 0; - if (!dev->driver) - return 0; + /* + * Devices gotten from FADT don't have a "path" attribute + */ + if(dev->handle) { + result = device_create_file(&dev->dev, &dev_attr_path); + if(result) + goto end; + } - if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, - "PHYSDEVDRIVER=%s", dev->driver->name)) - return -ENOMEM; + if(dev->flags.hardware_id) { + result = device_create_file(&dev->dev, &dev_attr_hid); + if(result) + goto end; + } - envp[i] = NULL; + /* + * If device has _EJ0, 'eject' file is created that is used to trigger + * hot-removal function from userland. + */ + status = acpi_get_handle(dev->handle, "_EJ0", &temp); + if (ACPI_SUCCESS(status)) + result = device_create_file(&dev->dev, &dev_attr_eject); + end: + return result; +} +static void acpi_device_remove_files(struct acpi_device *dev) +{ + acpi_status status; + acpi_handle temp; + + /* + * If device has _EJ0, 'eject' file is created that is used to trigger + * hot-removal function from userland. + */ + status = acpi_get_handle(dev->handle, "_EJ0", &temp); + if (ACPI_SUCCESS(status)) + device_remove_file(&dev->dev, &dev_attr_eject); + + if(dev->flags.hardware_id) + device_remove_file(&dev->dev, &dev_attr_hid); + if(dev->handle) + device_remove_file(&dev->dev, &dev_attr_path); +} +/* -------------------------------------------------------------------------- + ACPI Bus operations + -------------------------------------------------------------------------- */ +static void acpi_device_release(struct device *dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + + kfree(acpi_dev->pnp.cid_list); + kfree(acpi_dev); +} + +static int acpi_device_suspend(struct device *dev, pm_message_t state) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; + + if (acpi_drv && acpi_drv->ops.suspend) + return acpi_drv->ops.suspend(acpi_dev, state); return 0; } -static struct kset_uevent_ops namespace_uevent_ops = { - .uevent = &namespace_uevent, +static int acpi_device_resume(struct device *dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; + + if (acpi_drv && acpi_drv->ops.resume) + return acpi_drv->ops.resume(acpi_dev); + return 0; +} + +static int acpi_bus_match(struct device *dev, struct device_driver *drv) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = to_acpi_driver(drv); + + return !acpi_match_ids(acpi_dev, acpi_drv->ids); +} + +static int acpi_device_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + int i = 0, length = 0, ret = 0; + + if (acpi_dev->flags.hardware_id) + ret = add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "HWID=%s", acpi_dev->pnp.hardware_id); + if (ret) + return -ENOMEM; + if (acpi_dev->flags.compatible_ids) { + int j; + struct acpi_compatible_id_list *cid_list; + + cid_list = acpi_dev->pnp.cid_list; + + for (j = 0; j < cid_list->count; j++) { + ret = add_uevent_var(envp, num_envp, &i, buffer, + buffer_size, &length, "COMPTID=%s", + cid_list->id[j].value); + if (ret) + return -ENOMEM; + } + } + + envp[i] = NULL; + return 0; +} + +static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *); +static int acpi_start_single_object(struct acpi_device *); +static int acpi_device_probe(struct device * dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); + int ret; + + ret = acpi_bus_driver_init(acpi_dev, acpi_drv); + if (!ret) { + if (acpi_dev->bus_ops.acpi_op_start) + acpi_start_single_object(acpi_dev); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Found driver [%s] for device [%s]\n", + acpi_drv->name, acpi_dev->pnp.bus_id)); + get_device(dev); + } + return ret; +} + +static int acpi_device_remove(struct device * dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; + + if (acpi_drv) { + if (acpi_drv->ops.stop) + acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type); + if (acpi_drv->ops.remove) + acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type); + } + acpi_dev->driver = NULL; + acpi_driver_data(dev) = NULL; + + put_device(dev); + return 0; +} + +static void acpi_device_shutdown(struct device *dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; + + if (acpi_drv && acpi_drv->ops.shutdown) + acpi_drv->ops.shutdown(acpi_dev); + + return ; +} + +static struct bus_type acpi_bus_type = { + .name = "acpi", + .suspend = acpi_device_suspend, + .resume = acpi_device_resume, + .shutdown = acpi_device_shutdown, + .match = acpi_bus_match, + .probe = acpi_device_probe, + .remove = acpi_device_remove, + .uevent = acpi_device_uevent, }; -static struct kset acpi_namespace_kset = { - .kobj = { - .name = "namespace", - }, - .subsys = &acpi_subsys, - .ktype = &ktype_acpi_ns, - .uevent_ops = &namespace_uevent_ops, -}; - -static void acpi_device_register(struct acpi_device *device, +static int acpi_device_register(struct acpi_device *device, struct acpi_device *parent) { - int err; - + int result; + struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; + int found = 0; /* * Linkage * ------- @@ -126,7 +330,33 @@ static void acpi_device_register(struct acpi_device *device, INIT_LIST_HEAD(&device->g_list); INIT_LIST_HEAD(&device->wakeup_list); + new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); + if (!new_bus_id) { + printk(KERN_ERR PREFIX "Memory allocation error\n"); + return -ENOMEM; + } + spin_lock(&acpi_device_lock); + /* + * Find suitable bus_id and instance number in acpi_bus_id_list + * If failed, create one and link it into acpi_bus_id_list + */ + list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) { + if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) { + acpi_device_bus_id->instance_no ++; + found = 1; + kfree(new_bus_id); + break; + } + } + if(!found) { + acpi_device_bus_id = new_bus_id; + strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device"); + acpi_device_bus_id->instance_no = 0; + list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); + } + sprintf(device->dev.bus_id, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no); + if (device->parent) { list_add_tail(&device->node, &device->parent->children); list_add_tail(&device->g_list, &device->parent->g_list); @@ -136,16 +366,33 @@ static void acpi_device_register(struct acpi_device *device, list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); spin_unlock(&acpi_device_lock); - strlcpy(device->kobj.name, device->pnp.bus_id, KOBJ_NAME_LEN); - if (parent) - device->kobj.parent = &parent->kobj; - device->kobj.ktype = &ktype_acpi_ns; - device->kobj.kset = &acpi_namespace_kset; - err = kobject_register(&device->kobj); - if (err < 0) - printk(KERN_WARNING "%s: kobject_register error: %d\n", - __FUNCTION__, err); - create_sysfs_device_files(device); + if (device->parent) + device->dev.parent = &parent->dev; + device->dev.bus = &acpi_bus_type; + device_initialize(&device->dev); + device->dev.release = &acpi_device_release; + result = device_add(&device->dev); + if(result) { + printk("Error adding device %s", device->dev.bus_id); + goto end; + } + + result = acpi_device_setup_files(device); + if(result) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id)); + + device->removal_type = ACPI_BUS_REMOVAL_NORMAL; + return 0; + end: + spin_lock(&acpi_device_lock); + if (device->parent) { + list_del(&device->node); + list_del(&device->g_list); + } else + list_del(&device->g_list); + list_del(&device->wakeup_list); + spin_unlock(&acpi_device_lock); + return result; } static void acpi_device_unregister(struct acpi_device *device, int type) @@ -158,14 +405,137 @@ static void acpi_device_unregister(struct acpi_device *device, int type) list_del(&device->g_list); list_del(&device->wakeup_list); - spin_unlock(&acpi_device_lock); acpi_detach_data(device->handle, acpi_bus_data_handler); - remove_sysfs_device_files(device); - kobject_unregister(&device->kobj); + + acpi_device_remove_files(device); + device_unregister(&device->dev); } +/* -------------------------------------------------------------------------- + Driver Management + -------------------------------------------------------------------------- */ +/** + * acpi_bus_driver_init - add a device to a driver + * @device: the device to add and initialize + * @driver: driver for the device + * + * Used to initialize a device via its device driver. Called whenever a + * driver is bound to a device. Invokes the driver's add() ops. + */ +static int +acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver) +{ + int result = 0; + + + if (!device || !driver) + return -EINVAL; + + if (!driver->ops.add) + return -ENOSYS; + + result = driver->ops.add(device); + if (result) { + device->driver = NULL; + acpi_driver_data(device) = NULL; + return result; + } + + device->driver = driver; + + /* + * TBD - Configuration Management: Assign resources to device based + * upon possible configuration and currently allocated resources. + */ + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Driver successfully bound to device\n")); + return 0; +} + +static int acpi_start_single_object(struct acpi_device *device) +{ + int result = 0; + struct acpi_driver *driver; + + + if (!(driver = device->driver)) + return 0; + + if (driver->ops.start) { + result = driver->ops.start(device); + if (result && driver->ops.remove) + driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); + } + + return result; +} + +/** + * acpi_bus_register_driver - register a driver with the ACPI bus + * @driver: driver being registered + * + * Registers a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and binds. Returns zero for + * success or a negative error status for failure. + */ +int acpi_bus_register_driver(struct acpi_driver *driver) +{ + int ret; + + if (acpi_disabled) + return -ENODEV; + driver->drv.name = driver->name; + driver->drv.bus = &acpi_bus_type; + driver->drv.owner = driver->owner; + + ret = driver_register(&driver->drv); + return ret; +} + +EXPORT_SYMBOL(acpi_bus_register_driver); + +/** + * acpi_bus_unregister_driver - unregisters a driver with the APIC bus + * @driver: driver to unregister + * + * Unregisters a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and unbinds. + */ +void acpi_bus_unregister_driver(struct acpi_driver *driver) +{ + driver_unregister(&driver->drv); +} + +EXPORT_SYMBOL(acpi_bus_unregister_driver); + +/* -------------------------------------------------------------------------- + Device Enumeration + -------------------------------------------------------------------------- */ +acpi_status +acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) +{ + acpi_status status; + acpi_handle tmp; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *obj; + + status = acpi_get_handle(handle, "_EJD", &tmp); + if (ACPI_FAILURE(status)) + return status; + + status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); + if (ACPI_SUCCESS(status)) { + obj = buffer.pointer; + status = acpi_get_handle(NULL, obj->string.pointer, ejd); + kfree(buffer.pointer); + } + return status; +} +EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); + void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) { @@ -174,67 +544,6 @@ void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) return; } -static int acpi_bus_get_power_flags(struct acpi_device *device) -{ - acpi_status status = 0; - acpi_handle handle = NULL; - u32 i = 0; - - - /* - * Power Management Flags - */ - status = acpi_get_handle(device->handle, "_PSC", &handle); - if (ACPI_SUCCESS(status)) - device->power.flags.explicit_get = 1; - status = acpi_get_handle(device->handle, "_IRC", &handle); - if (ACPI_SUCCESS(status)) - device->power.flags.inrush_current = 1; - - /* - * Enumerate supported power management states - */ - for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { - struct acpi_device_power_state *ps = &device->power.states[i]; - char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' }; - - /* Evaluate "_PRx" to se if power resources are referenced */ - acpi_evaluate_reference(device->handle, object_name, NULL, - &ps->resources); - if (ps->resources.count) { - device->power.flags.power_resources = 1; - ps->flags.valid = 1; - } - - /* Evaluate "_PSx" to see if we can do explicit sets */ - object_name[2] = 'S'; - status = acpi_get_handle(device->handle, object_name, &handle); - if (ACPI_SUCCESS(status)) { - ps->flags.explicit_set = 1; - ps->flags.valid = 1; - } - - /* State is valid if we have some power control */ - if (ps->resources.count || ps->flags.explicit_set) - ps->flags.valid = 1; - - ps->power = -1; /* Unknown - driver assigned */ - ps->latency = -1; /* Unknown - driver assigned */ - } - - /* Set defaults for D0 and D3 states (always valid) */ - device->power.states[ACPI_STATE_D0].flags.valid = 1; - device->power.states[ACPI_STATE_D0].power = 100; - device->power.states[ACPI_STATE_D3].flags.valid = 1; - device->power.states[ACPI_STATE_D3].power = 0; - - /* TBD: System wake support and resource requirements. */ - - device->power.state = ACPI_STATE_UNKNOWN; - - return 0; -} - int acpi_match_ids(struct acpi_device *device, char *ids) { if (device->flags.hardware_id) @@ -254,6 +563,12 @@ int acpi_match_ids(struct acpi_device *device, char *ids) return -ENOENT; } +static int acpi_bus_get_perf_flags(struct acpi_device *device) +{ + device->performance.state = ACPI_STATE_UNKNOWN; + return 0; +} + static acpi_status acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, union acpi_object *package) @@ -338,360 +653,67 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) return 0; } -/* -------------------------------------------------------------------------- - ACPI sysfs device file support - -------------------------------------------------------------------------- */ -static ssize_t acpi_eject_store(struct acpi_device *device, - const char *buf, size_t count); - -#define ACPI_DEVICE_ATTR(_name,_mode,_show,_store) \ -static struct acpi_device_attribute acpi_device_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) - -ACPI_DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); - -/** - * setup_sys_fs_device_files - sets up the device files under device namespace - * @dev: acpi_device object - * @func: function pointer to create or destroy the device file - */ -static void -setup_sys_fs_device_files(struct acpi_device *dev, - acpi_device_sysfs_files * func) +static int acpi_bus_get_power_flags(struct acpi_device *device) { - acpi_status status; - acpi_handle temp = NULL; + acpi_status status = 0; + acpi_handle handle = NULL; + u32 i = 0; + /* - * If device has _EJ0, 'eject' file is created that is used to trigger - * hot-removal function from userland. + * Power Management Flags */ - status = acpi_get_handle(dev->handle, "_EJ0", &temp); + status = acpi_get_handle(device->handle, "_PSC", &handle); if (ACPI_SUCCESS(status)) - (*(func)) (&dev->kobj, &acpi_device_attr_eject.attr); -} - -static int acpi_eject_operation(acpi_handle handle, int lockable) -{ - struct acpi_object_list arg_list; - union acpi_object arg; - acpi_status status = AE_OK; + device->power.flags.explicit_get = 1; + status = acpi_get_handle(device->handle, "_IRC", &handle); + if (ACPI_SUCCESS(status)) + device->power.flags.inrush_current = 1; /* - * TBD: evaluate _PS3? + * Enumerate supported power management states */ + for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { + struct acpi_device_power_state *ps = &device->power.states[i]; + char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' }; - if (lockable) { - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 0; - acpi_evaluate_object(handle, "_LCK", &arg_list, NULL); - } - - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - /* - * TBD: _EJD support. - */ - - status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - return (-ENODEV); - } - - return (0); -} - -static ssize_t -acpi_eject_store(struct acpi_device *device, const char *buf, size_t count) -{ - int result; - int ret = count; - int islockable; - acpi_status status; - acpi_handle handle; - acpi_object_type type = 0; - - if ((!count) || (buf[0] != '1')) { - return -EINVAL; - } -#ifndef FORCE_EJECT - if (device->driver == NULL) { - ret = -ENODEV; - goto err; - } -#endif - status = acpi_get_type(device->handle, &type); - if (ACPI_FAILURE(status) || (!device->flags.ejectable)) { - ret = -ENODEV; - goto err; - } - - islockable = device->flags.lockable; - handle = device->handle; - - result = acpi_bus_trim(device, 1); - - if (!result) - result = acpi_eject_operation(handle, islockable); - - if (result) { - ret = -EBUSY; - } - err: - return ret; -} - -/* -------------------------------------------------------------------------- - Performance Management - -------------------------------------------------------------------------- */ - -static int acpi_bus_get_perf_flags(struct acpi_device *device) -{ - device->performance.state = ACPI_STATE_UNKNOWN; - return 0; -} - -/* -------------------------------------------------------------------------- - Driver Management - -------------------------------------------------------------------------- */ - -static LIST_HEAD(acpi_bus_drivers); - -/** - * acpi_bus_match - match device IDs to driver's supported IDs - * @device: the device that we are trying to match to a driver - * @driver: driver whose device id table is being checked - * - * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it - * matches the specified driver's criteria. - */ -static int -acpi_bus_match(struct acpi_device *device, struct acpi_driver *driver) -{ - if (driver && driver->ops.match) - return driver->ops.match(device, driver); - return acpi_match_ids(device, driver->ids); -} - -/** - * acpi_bus_driver_init - add a device to a driver - * @device: the device to add and initialize - * @driver: driver for the device - * - * Used to initialize a device via its device driver. Called whenever a - * driver is bound to a device. Invokes the driver's add() and start() ops. - */ -static int -acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver) -{ - int result = 0; - - - if (!device || !driver) - return -EINVAL; - - if (!driver->ops.add) - return -ENOSYS; - - result = driver->ops.add(device); - if (result) { - device->driver = NULL; - acpi_driver_data(device) = NULL; - return result; - } - - device->driver = driver; - - /* - * TBD - Configuration Management: Assign resources to device based - * upon possible configuration and currently allocated resources. - */ - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Driver successfully bound to device\n")); - return 0; -} - -static int acpi_start_single_object(struct acpi_device *device) -{ - int result = 0; - struct acpi_driver *driver; - - - if (!(driver = device->driver)) - return 0; - - if (driver->ops.start) { - result = driver->ops.start(device); - if (result && driver->ops.remove) - driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); - } - - return result; -} - -static void acpi_driver_attach(struct acpi_driver *drv) -{ - struct list_head *node, *next; - - - spin_lock(&acpi_device_lock); - list_for_each_safe(node, next, &acpi_device_list) { - struct acpi_device *dev = - container_of(node, struct acpi_device, g_list); - - if (dev->driver || !dev->status.present) - continue; - spin_unlock(&acpi_device_lock); - - if (!acpi_bus_match(dev, drv)) { - if (!acpi_bus_driver_init(dev, drv)) { - acpi_start_single_object(dev); - atomic_inc(&drv->references); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Found driver [%s] for device [%s]\n", - drv->name, dev->pnp.bus_id)); - } + /* Evaluate "_PRx" to se if power resources are referenced */ + acpi_evaluate_reference(device->handle, object_name, NULL, + &ps->resources); + if (ps->resources.count) { + device->power.flags.power_resources = 1; + ps->flags.valid = 1; } - spin_lock(&acpi_device_lock); - } - spin_unlock(&acpi_device_lock); -} -static void acpi_driver_detach(struct acpi_driver *drv) -{ - struct list_head *node, *next; - - - spin_lock(&acpi_device_lock); - list_for_each_safe(node, next, &acpi_device_list) { - struct acpi_device *dev = - container_of(node, struct acpi_device, g_list); - - if (dev->driver == drv) { - spin_unlock(&acpi_device_lock); - if (drv->ops.remove) - drv->ops.remove(dev, ACPI_BUS_REMOVAL_NORMAL); - spin_lock(&acpi_device_lock); - dev->driver = NULL; - dev->driver_data = NULL; - atomic_dec(&drv->references); + /* Evaluate "_PSx" to see if we can do explicit sets */ + object_name[2] = 'S'; + status = acpi_get_handle(device->handle, object_name, &handle); + if (ACPI_SUCCESS(status)) { + ps->flags.explicit_set = 1; + ps->flags.valid = 1; } + + /* State is valid if we have some power control */ + if (ps->resources.count || ps->flags.explicit_set) + ps->flags.valid = 1; + + ps->power = -1; /* Unknown - driver assigned */ + ps->latency = -1; /* Unknown - driver assigned */ } - spin_unlock(&acpi_device_lock); -} -/** - * acpi_bus_register_driver - register a driver with the ACPI bus - * @driver: driver being registered - * - * Registers a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and binds. Returns zero for - * success or a negative error status for failure. - */ -int acpi_bus_register_driver(struct acpi_driver *driver) -{ + /* Set defaults for D0 and D3 states (always valid) */ + device->power.states[ACPI_STATE_D0].flags.valid = 1; + device->power.states[ACPI_STATE_D0].power = 100; + device->power.states[ACPI_STATE_D3].flags.valid = 1; + device->power.states[ACPI_STATE_D3].power = 0; - if (acpi_disabled) - return -ENODEV; + /* TBD: System wake support and resource requirements. */ - spin_lock(&acpi_device_lock); - list_add_tail(&driver->node, &acpi_bus_drivers); - spin_unlock(&acpi_device_lock); - acpi_driver_attach(driver); + device->power.state = ACPI_STATE_UNKNOWN; return 0; } -EXPORT_SYMBOL(acpi_bus_register_driver); - -/** - * acpi_bus_unregister_driver - unregisters a driver with the APIC bus - * @driver: driver to unregister - * - * Unregisters a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and unbinds. - */ -void acpi_bus_unregister_driver(struct acpi_driver *driver) -{ - acpi_driver_detach(driver); - - if (!atomic_read(&driver->references)) { - spin_lock(&acpi_device_lock); - list_del_init(&driver->node); - spin_unlock(&acpi_device_lock); - } - return; -} - -EXPORT_SYMBOL(acpi_bus_unregister_driver); - -/** - * acpi_bus_find_driver - check if there is a driver installed for the device - * @device: device that we are trying to find a supporting driver for - * - * Parses the list of registered drivers looking for a driver applicable for - * the specified device. - */ -static int acpi_bus_find_driver(struct acpi_device *device) -{ - int result = 0; - struct list_head *node, *next; - - - spin_lock(&acpi_device_lock); - list_for_each_safe(node, next, &acpi_bus_drivers) { - struct acpi_driver *driver = - container_of(node, struct acpi_driver, node); - - atomic_inc(&driver->references); - spin_unlock(&acpi_device_lock); - if (!acpi_bus_match(device, driver)) { - result = acpi_bus_driver_init(device, driver); - if (!result) - goto Done; - } - atomic_dec(&driver->references); - spin_lock(&acpi_device_lock); - } - spin_unlock(&acpi_device_lock); - - Done: - return result; -} - -/* -------------------------------------------------------------------------- - Device Enumeration - -------------------------------------------------------------------------- */ - -acpi_status -acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) -{ - acpi_status status; - acpi_handle tmp; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object *obj; - - status = acpi_get_handle(handle, "_EJD", &tmp); - if (ACPI_FAILURE(status)) - return status; - - status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); - if (ACPI_SUCCESS(status)) { - obj = buffer.pointer; - status = acpi_get_handle(NULL, obj->string.pointer, ejd); - kfree(buffer.pointer); - } - return status; -} -EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); - - static int acpi_bus_get_flags(struct acpi_device *device) { acpi_status status = AE_OK; @@ -782,6 +804,75 @@ static void acpi_device_get_busid(struct acpi_device *device, } } +static int +acpi_video_bus_match(struct acpi_device *device) +{ + acpi_handle h_dummy1; + acpi_handle h_dummy2; + acpi_handle h_dummy3; + + + if (!device) + return -EINVAL; + + /* Since there is no HID, CID for ACPI Video drivers, we have + * to check well known required nodes for each feature we support. + */ + + /* Does this device able to support video switching ? */ + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2))) + return 0; + + /* Does this device able to retrieve a video ROM ? */ + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1))) + return 0; + + /* Does this device able to configure which video head to be POSTed ? */ + if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) && + ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3))) + return 0; + + return -ENODEV; +} + +/* + * acpi_bay_match - see if a device is an ejectable driver bay + * + * If an acpi object is ejectable and has one of the ACPI ATA methods defined, + * then we can safely call it an ejectable drive bay + */ +static int acpi_bay_match(struct acpi_device *device){ + acpi_status status; + acpi_handle handle; + acpi_handle tmp; + acpi_handle phandle; + + handle = device->handle; + + status = acpi_get_handle(handle, "_EJ0", &tmp); + if (ACPI_FAILURE(status)) + return -ENODEV; + + if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) + return 0; + + if (acpi_get_parent(handle, &phandle)) + return -ENODEV; + + if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) || + (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp)))) + return 0; + + return -ENODEV; +} + static void acpi_device_set_id(struct acpi_device *device, struct acpi_device *parent, acpi_handle handle, int type) @@ -812,6 +903,16 @@ static void acpi_device_set_id(struct acpi_device *device, device->pnp.bus_address = info->address; device->flags.bus_address = 1; } + + if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){ + status = acpi_video_bus_match(device); + if(ACPI_SUCCESS(status)) + hid = ACPI_VIDEO_HID; + + status = acpi_bay_match(device); + if (ACPI_SUCCESS(status)) + hid = ACPI_BAY_HID; + } break; case ACPI_BUS_TYPE_POWER: hid = ACPI_POWER_HID; @@ -888,86 +989,24 @@ static int acpi_device_set_context(struct acpi_device *device, int type) return result; } -static void acpi_device_get_debug_info(struct acpi_device *device, - acpi_handle handle, int type) -{ -#ifdef CONFIG_ACPI_DEBUG_OUTPUT - char *type_string = NULL; - char name[80] = { '?', '\0' }; - struct acpi_buffer buffer = { sizeof(name), name }; - - switch (type) { - case ACPI_BUS_TYPE_DEVICE: - type_string = "Device"; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - break; - case ACPI_BUS_TYPE_POWER: - type_string = "Power Resource"; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - break; - case ACPI_BUS_TYPE_PROCESSOR: - type_string = "Processor"; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - break; - case ACPI_BUS_TYPE_SYSTEM: - type_string = "System"; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - break; - case ACPI_BUS_TYPE_THERMAL: - type_string = "Thermal Zone"; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - break; - case ACPI_BUS_TYPE_POWER_BUTTON: - type_string = "Power Button"; - sprintf(name, "PWRB"); - break; - case ACPI_BUS_TYPE_SLEEP_BUTTON: - type_string = "Sleep Button"; - sprintf(name, "SLPB"); - break; - } - - printk(KERN_DEBUG "Found %s %s [%p]\n", type_string, name, handle); -#endif /*CONFIG_ACPI_DEBUG_OUTPUT */ -} - static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) { - int result = 0; - struct acpi_driver *driver; - - if (!dev) return -EINVAL; - driver = dev->driver; - - if ((driver) && (driver->ops.remove)) { - - if (driver->ops.stop) { - result = driver->ops.stop(dev, ACPI_BUS_REMOVAL_EJECT); - if (result) - return result; - } - - result = dev->driver->ops.remove(dev, ACPI_BUS_REMOVAL_EJECT); - if (result) { - return result; - } - - atomic_dec(&dev->driver->references); - dev->driver = NULL; - acpi_driver_data(dev) = NULL; - } + dev->removal_type = ACPI_BUS_REMOVAL_EJECT; + device_release_driver(&dev->dev); if (!rmdevice) return 0; + /* + * unbind _ADR-Based Devices when hot removal + */ if (dev->flags.bus_address) { if ((dev->parent) && (dev->parent->ops.unbind)) dev->parent->ops.unbind(dev); } - acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT); return 0; @@ -975,7 +1014,8 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) static int acpi_add_single_object(struct acpi_device **child, - struct acpi_device *parent, acpi_handle handle, int type) + struct acpi_device *parent, acpi_handle handle, int type, + struct acpi_bus_ops *ops) { int result = 0; struct acpi_device *device = NULL; @@ -992,6 +1032,8 @@ acpi_add_single_object(struct acpi_device **child, device->handle = handle; device->parent = parent; + device->bus_ops = *ops; /* workround for not call .start */ + acpi_device_get_busid(device, handle, type); @@ -1076,33 +1118,16 @@ acpi_add_single_object(struct acpi_device **child, if ((result = acpi_device_set_context(device, type))) goto end; - acpi_device_get_debug_info(device, handle, type); - - acpi_device_register(device, parent); + result = acpi_device_register(device, parent); /* - * Bind _ADR-Based Devices - * ----------------------- - * If there's a a bus address (_ADR) then we utilize the parent's - * 'bind' function (if exists) to bind the ACPI- and natively- - * enumerated device representations. + * Bind _ADR-Based Devices when hot add */ if (device->flags.bus_address) { if (device->parent && device->parent->ops.bind) device->parent->ops.bind(device); } - /* - * Locate & Attach Driver - * ---------------------- - * If there's a hardware id (_HID) or compatible ids (_CID) we check - * to see if there's a driver installed for this kind of device. Note - * that drivers can install before or after a device is enumerated. - * - * TBD: Assumes LDM provides driver hot-plug capability. - */ - acpi_bus_find_driver(device); - end: if (!result) *child = device; @@ -1188,14 +1213,14 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops) if (ops->acpi_op_add) status = acpi_add_single_object(&child, parent, - chandle, type); + chandle, type, ops); else status = acpi_bus_get_device(chandle, &child); if (ACPI_FAILURE(status)) continue; - if (ops->acpi_op_start) { + if (ops->acpi_op_start && !(ops->acpi_op_add)) { status = acpi_start_single_object(child); if (ACPI_FAILURE(status)) continue; @@ -1233,13 +1258,13 @@ acpi_bus_add(struct acpi_device **child, int result; struct acpi_bus_ops ops; + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; - result = acpi_add_single_object(child, parent, handle, type); - if (!result) { - memset(&ops, 0, sizeof(ops)); - ops.acpi_op_add = 1; + result = acpi_add_single_object(child, parent, handle, type, &ops); + if (!result) result = acpi_bus_scan(*child, &ops); - } + return result; } @@ -1325,127 +1350,35 @@ static int acpi_bus_scan_fixed(struct acpi_device *root) { int result = 0; struct acpi_device *device = NULL; - + struct acpi_bus_ops ops; if (!root) return -ENODEV; + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; + ops.acpi_op_start = 1; + /* * Enumerate all fixed-feature devices. */ - if (acpi_fadt.pwr_button == 0) { + if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) { result = acpi_add_single_object(&device, acpi_root, NULL, - ACPI_BUS_TYPE_POWER_BUTTON); - if (!result) - result = acpi_start_single_object(device); + ACPI_BUS_TYPE_POWER_BUTTON, + &ops); } - if (acpi_fadt.sleep_button == 0) { + if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { result = acpi_add_single_object(&device, acpi_root, NULL, - ACPI_BUS_TYPE_SLEEP_BUTTON); - if (!result) - result = acpi_start_single_object(device); + ACPI_BUS_TYPE_SLEEP_BUTTON, + &ops); } return result; } - -static inline struct acpi_device * to_acpi_dev(struct device * dev) -{ - return container_of(dev, struct acpi_device, dev); -} - - -static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state) -{ - struct acpi_device * dev, * next; - int result; - - spin_lock(&acpi_device_lock); - list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) { - if (dev->driver && dev->driver->ops.suspend) { - spin_unlock(&acpi_device_lock); - result = dev->driver->ops.suspend(dev, 0); - if (result) { - printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n", - acpi_device_name(dev), - acpi_device_bid(dev), result); - } - spin_lock(&acpi_device_lock); - } - } - spin_unlock(&acpi_device_lock); - return 0; -} - - -static int acpi_device_suspend(struct device * dev, pm_message_t state) -{ - struct acpi_device * acpi_dev = to_acpi_dev(dev); - - /* - * For now, we should only register 1 generic device - - * the ACPI root device - and from there, we walk the - * tree of ACPI devices to suspend each one using the - * ACPI driver methods. - */ - if (acpi_dev->handle == ACPI_ROOT_OBJECT) - root_suspend(acpi_dev, state); - return 0; -} - - - -static int root_resume(struct acpi_device * acpi_dev) -{ - struct acpi_device * dev, * next; - int result; - - spin_lock(&acpi_device_lock); - list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) { - if (dev->driver && dev->driver->ops.resume) { - spin_unlock(&acpi_device_lock); - result = dev->driver->ops.resume(dev, 0); - if (result) { - printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n", - acpi_device_name(dev), - acpi_device_bid(dev), result); - } - spin_lock(&acpi_device_lock); - } - } - spin_unlock(&acpi_device_lock); - return 0; -} - - -static int acpi_device_resume(struct device * dev) -{ - struct acpi_device * acpi_dev = to_acpi_dev(dev); - - /* - * For now, we should only register 1 generic device - - * the ACPI root device - and from there, we walk the - * tree of ACPI devices to resume each one using the - * ACPI driver methods. - */ - if (acpi_dev->handle == ACPI_ROOT_OBJECT) - root_resume(acpi_dev); - return 0; -} - - -static struct bus_type acpi_bus_type = { - .name = "acpi", - .suspend = acpi_device_suspend, - .resume = acpi_device_resume, -}; - - - static int __init acpi_scan_init(void) { int result; @@ -1455,9 +1388,9 @@ static int __init acpi_scan_init(void) if (acpi_disabled) return 0; - result = kset_register(&acpi_namespace_kset); - if (result < 0) - printk(KERN_ERR PREFIX "kset_register error: %d\n", result); + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; + ops.acpi_op_start = 1; result = bus_register(&acpi_bus_type); if (result) { @@ -1469,32 +1402,16 @@ static int __init acpi_scan_init(void) * Create the root device in the bus's device tree */ result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT, - ACPI_BUS_TYPE_SYSTEM); + ACPI_BUS_TYPE_SYSTEM, &ops); if (result) goto Done; - result = acpi_start_single_object(acpi_root); - if (result) - goto Done; - - acpi_root->dev.bus = &acpi_bus_type; - snprintf(acpi_root->dev.bus_id, BUS_ID_SIZE, "%s", acpi_bus_type.name); - result = device_register(&acpi_root->dev); - if (result) { - /* We don't want to quit even if we failed to add suspend/resume */ - printk(KERN_ERR PREFIX "Could not register device\n"); - } - /* * Enumerate devices in the ACPI namespace. */ result = acpi_bus_scan_fixed(acpi_root); - if (!result) { - memset(&ops, 0, sizeof(ops)); - ops.acpi_op_add = 1; - ops.acpi_op_start = 1; + if (!result) result = acpi_bus_scan(acpi_root, &ops); - } if (result) acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); 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..7147b0bdab0a 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -32,6 +32,11 @@ #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("acpi_system") +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif +#define MODULE_PARAM_PREFIX "acpi." + #define ACPI_SYSTEM_CLASS "system" #define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver" #define ACPI_SYSTEM_DEVICE_NAME "System" @@ -39,11 +44,24 @@ 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; + +/* + * Make ACPICA version work as module param + */ +static int param_get_acpica_version(char *buffer, struct kernel_param *kp) { + int result; + + result = sprintf(buffer, "%x", ACPI_CA_VERSION); + + return result; +} + +module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); /* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_PROCFS static int acpi_system_read_info(struct seq_file *seq, void *offset) { @@ -63,6 +81,7 @@ static const struct file_operations acpi_system_info_ops = { .llseek = seq_lseek, .release = single_release, }; +#endif static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t, loff_t *); @@ -76,17 +95,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 +121,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; } @@ -128,6 +145,7 @@ static int __init acpi_system_init(void) if (acpi_disabled) return 0; +#ifdef CONFIG_ACPI_PROCFS /* 'info' [R] */ name = ACPI_SYSTEM_FILE_INFO; entry = create_proc_entry(name, S_IRUGO, acpi_root_dir); @@ -136,6 +154,7 @@ static int __init acpi_system_init(void) else { entry->proc_fops = &acpi_system_info_ops; } +#endif /* 'dsdt' [R] */ name = ACPI_SYSTEM_FILE_DSDT; @@ -159,7 +178,9 @@ static int __init acpi_system_init(void) Error: remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir); remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir); +#ifdef CONFIG_ACPI_PROCFS remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir); +#endif error = -EFAULT; goto Done; diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index ffa30c9fccbf..ba4cb200314a 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -38,154 +38,97 @@ #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 struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; -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; - -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) +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, @@ -193,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; @@ -225,342 +168,76 @@ 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->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, - 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; - acpi_table_entry_header *entry; + struct acpi_table_header *madt = NULL; + struct acpi_subtable_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. */ - 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) { - 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; } 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(ACPI_APIC, + return acpi_table_parse_madt_family(ACPI_SIG_MADT, 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) && - (((struct acpi20_table_rsdp *)rsdp)->xsdt_address)) { - - struct acpi_table_xsdt *mapped_xsdt = NULL; - - sdt_pa = ((struct acpi20_table_rsdp *)rsdp)->xsdt_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->entry[i]; - } - - /* Then check RSDT */ - - else if (rsdp->rsdt_address) { - - struct acpi_table_rsdt *mapped_rsdt = NULL; - - sdt_pa = rsdp->rsdt_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->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; } /* @@ -568,54 +245,13 @@ static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp) * * find RSDP, find and checksum SDT/XSDT. * checksum all tables, print SDT/XSDT - * + * * result: sdt_entry[] is initialized */ + 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, - sizeof(struct acpi_table_rsdp)); - else - result = - acpi_table_compute_checksum(rsdp, - ((struct acpi20_table_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/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile index aa4c69594d97..0a7d7afac255 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 tbfadt.o EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c deleted file mode 100644 index d697fcb35d52..000000000000 --- a/drivers/acpi/tables/tbconvrt.c +++ /dev/null @@ -1,622 +0,0 @@ -/****************************************************************************** - * - * Module Name: tbconvrt - ACPI Table conversion utilities - * - *****************************************************************************/ - -/* - * 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. - */ - -#include -#include - -#define _COMPONENT ACPI_TABLES -ACPI_MODULE_NAME("tbconvrt") - -/* Local prototypes */ -static void -acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct, - u8 register_bit_width, - acpi_physical_address address); - -static void -acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt, - struct fadt_descriptor_rev1 *original_fadt); - -static void -acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt, - struct fadt_descriptor *original_fadt); - -u8 acpi_fadt_is_v1; -ACPI_EXPORT_SYMBOL(acpi_fadt_is_v1) - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_table_count - * - * PARAMETERS: RSDP - Pointer to the RSDP - * RSDT - Pointer to the RSDT/XSDT - * - * RETURN: The number of tables pointed to by the RSDT or XSDT. - * - * DESCRIPTION: Calculate the number of tables. Automatically handles either - * an RSDT or XSDT. - * - ******************************************************************************/ - -u32 -acpi_tb_get_table_count(struct rsdp_descriptor *RSDP, - struct acpi_table_header *RSDT) -{ - u32 pointer_size; - - ACPI_FUNCTION_ENTRY(); - - /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */ - - if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { - pointer_size = sizeof(u32); - } else { - pointer_size = sizeof(u64); - } - - /* - * Determine the number of tables pointed to by the RSDT/XSDT. - * This is defined by the ACPI Specification to be the number of - * pointers contained within the RSDT/XSDT. The size of the pointers - * is architecture-dependent. - */ - return ((RSDT->length - - sizeof(struct acpi_table_header)) / pointer_size); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_convert_to_xsdt - * - * PARAMETERS: table_info - Info about the RSDT - * - * RETURN: Status - * - * DESCRIPTION: Convert an RSDT to an XSDT (internal common format) - * - ******************************************************************************/ - -acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info) -{ - acpi_size table_size; - u32 i; - struct xsdt_descriptor *new_table; - - ACPI_FUNCTION_ENTRY(); - - /* Compute size of the converted XSDT */ - - table_size = ((acpi_size) acpi_gbl_rsdt_table_count * sizeof(u64)) + - sizeof(struct acpi_table_header); - - /* Allocate an XSDT */ - - new_table = ACPI_ALLOCATE_ZEROED(table_size); - if (!new_table) { - return (AE_NO_MEMORY); - } - - /* Copy the header and set the length */ - - ACPI_MEMCPY(new_table, table_info->pointer, - sizeof(struct acpi_table_header)); - new_table->length = (u32) table_size; - - /* Copy the table pointers */ - - for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { - - /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */ - - if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { - ACPI_STORE_ADDRESS(new_table->table_offset_entry[i], - (ACPI_CAST_PTR - (struct rsdt_descriptor, - table_info->pointer))-> - table_offset_entry[i]); - } else { - new_table->table_offset_entry[i] = - (ACPI_CAST_PTR(struct xsdt_descriptor, - table_info->pointer))-> - table_offset_entry[i]; - } - } - - /* Delete the original table (either mapped or in a buffer) */ - - acpi_tb_delete_single_table(table_info); - - /* Point the table descriptor to the new table */ - - table_info->pointer = - ACPI_CAST_PTR(struct acpi_table_header, new_table); - table_info->length = table_size; - table_info->allocation = ACPI_MEM_ALLOCATED; - - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_init_generic_address - * - * PARAMETERS: new_gas_struct - GAS struct to be initialized - * register_bit_width - Width of this register - * Address - Address of the register - * - * RETURN: None - * - * DESCRIPTION: Initialize a GAS structure. - * - ******************************************************************************/ - -static void -acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct, - u8 register_bit_width, - acpi_physical_address address) -{ - - ACPI_STORE_ADDRESS(new_gas_struct->address, address); - - new_gas_struct->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO; - new_gas_struct->register_bit_width = register_bit_width; - new_gas_struct->register_bit_offset = 0; - new_gas_struct->access_width = 0; -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_convert_fadt1 - * - * PARAMETERS: local_fadt - Pointer to new FADT - * original_fadt - Pointer to old FADT - * - * RETURN: None, populates local_fadt - * - * DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format - * - ******************************************************************************/ - -static void -acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt, - struct fadt_descriptor_rev1 *original_fadt) -{ - - /* ACPI 1.0 FACS */ - /* The BIOS stored FADT should agree with Revision 1.0 */ - acpi_fadt_is_v1 = 1; - - /* - * Copy the table header and the common part of the tables. - * - * The 2.0 table is an extension of the 1.0 table, so the entire 1.0 - * table can be copied first, then expand some fields to 64 bits. - */ - ACPI_MEMCPY(local_fadt, original_fadt, - sizeof(struct fadt_descriptor_rev1)); - - /* Convert table pointers to 64-bit fields */ - - ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl, - local_fadt->V1_firmware_ctrl); - ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt); - - /* - * System Interrupt Model isn't used in ACPI 2.0 - * (local_fadt->Reserved1 = 0;) - */ - - /* - * This field is set by the OEM to convey the preferred power management - * profile to OSPM. It doesn't have any 1.0 equivalence. Since we don't - * know what kind of 32-bit system this is, we will use "unspecified". - */ - local_fadt->prefer_PM_profile = PM_UNSPECIFIED; - - /* - * Processor Performance State Control. This is the value OSPM writes to - * the SMI_CMD register to assume processor performance state control - * responsibility. There isn't any equivalence in 1.0, but as many 1.x - * ACPI tables contain _PCT and _PSS we also keep this value, unless - * acpi_strict is set. - */ - if (acpi_strict) - local_fadt->pstate_cnt = 0; - - /* - * Support for the _CST object and C States change notification. - * This data item hasn't any 1.0 equivalence so leave it zero. - */ - local_fadt->cst_cnt = 0; - - /* - * FADT Rev 2 was an interim FADT released between ACPI 1.0 and ACPI 2.0. - * It primarily adds the FADT reset mechanism. - */ - if ((original_fadt->revision == 2) && - (original_fadt->length == - sizeof(struct fadt_descriptor_rev2_minus))) { - /* - * Grab the entire generic address struct, plus the 1-byte reset value - * that immediately follows. - */ - ACPI_MEMCPY(&local_fadt->reset_register, - &(ACPI_CAST_PTR(struct fadt_descriptor_rev2_minus, - original_fadt))->reset_register, - sizeof(struct acpi_generic_address) + 1); - } else { - /* - * Since there isn't any equivalence in 1.0 and since it is highly - * likely that a 1.0 system has legacy support. - */ - local_fadt->iapc_boot_arch = BAF_LEGACY_DEVICES; - } - - /* - * Convert the V1.0 block addresses to V2.0 GAS structures - */ - acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk, - local_fadt->pm1_evt_len, - (acpi_physical_address) local_fadt-> - V1_pm1a_evt_blk); - acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk, - local_fadt->pm1_evt_len, - (acpi_physical_address) local_fadt-> - V1_pm1b_evt_blk); - acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk, - local_fadt->pm1_cnt_len, - (acpi_physical_address) local_fadt-> - V1_pm1a_cnt_blk); - acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk, - local_fadt->pm1_cnt_len, - (acpi_physical_address) local_fadt-> - V1_pm1b_cnt_blk); - acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk, - local_fadt->pm2_cnt_len, - (acpi_physical_address) local_fadt-> - V1_pm2_cnt_blk); - acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk, - local_fadt->pm_tm_len, - (acpi_physical_address) local_fadt-> - V1_pm_tmr_blk); - acpi_tb_init_generic_address(&local_fadt->xgpe0_blk, 0, - (acpi_physical_address) local_fadt-> - V1_gpe0_blk); - acpi_tb_init_generic_address(&local_fadt->xgpe1_blk, 0, - (acpi_physical_address) local_fadt-> - V1_gpe1_blk); - - /* Create separate GAS structs for the PM1 Enable registers */ - - acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, - (u8) ACPI_DIV_2(acpi_gbl_FADT-> - pm1_evt_len), - (acpi_physical_address) - (local_fadt->xpm1a_evt_blk.address + - ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len))); - - /* PM1B is optional; leave null if not present */ - - if (local_fadt->xpm1b_evt_blk.address) { - acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, - (u8) ACPI_DIV_2(acpi_gbl_FADT-> - pm1_evt_len), - (acpi_physical_address) - (local_fadt->xpm1b_evt_blk. - address + - ACPI_DIV_2(acpi_gbl_FADT-> - pm1_evt_len))); - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_convert_fadt2 - * - * PARAMETERS: local_fadt - Pointer to new FADT - * original_fadt - Pointer to old FADT - * - * RETURN: None, populates local_fadt - * - * DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format. - * Handles optional "X" fields. - * - ******************************************************************************/ - -static void -acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt, - struct fadt_descriptor *original_fadt) -{ - - /* We have an ACPI 2.0 FADT but we must copy it to our local buffer */ - - ACPI_MEMCPY(local_fadt, original_fadt, sizeof(struct fadt_descriptor)); - - /* - * "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 (!(local_fadt->xfirmware_ctrl)) { - ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl, - local_fadt->V1_firmware_ctrl); - } - - if (!(local_fadt->Xdsdt)) { - ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt); - } - - if (!(local_fadt->xpm1a_evt_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk, - local_fadt->pm1_evt_len, - (acpi_physical_address) - local_fadt->V1_pm1a_evt_blk); - } - - if (!(local_fadt->xpm1b_evt_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk, - local_fadt->pm1_evt_len, - (acpi_physical_address) - local_fadt->V1_pm1b_evt_blk); - } - - if (!(local_fadt->xpm1a_cnt_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk, - local_fadt->pm1_cnt_len, - (acpi_physical_address) - local_fadt->V1_pm1a_cnt_blk); - } - - if (!(local_fadt->xpm1b_cnt_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk, - local_fadt->pm1_cnt_len, - (acpi_physical_address) - local_fadt->V1_pm1b_cnt_blk); - } - - if (!(local_fadt->xpm2_cnt_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk, - local_fadt->pm2_cnt_len, - (acpi_physical_address) - local_fadt->V1_pm2_cnt_blk); - } - - if (!(local_fadt->xpm_tmr_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk, - local_fadt->pm_tm_len, - (acpi_physical_address) - local_fadt->V1_pm_tmr_blk); - } - - if (!(local_fadt->xgpe0_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xgpe0_blk, - 0, - (acpi_physical_address) - local_fadt->V1_gpe0_blk); - } - - if (!(local_fadt->xgpe1_blk.address)) { - acpi_tb_init_generic_address(&local_fadt->xgpe1_blk, - 0, - (acpi_physical_address) - local_fadt->V1_gpe1_blk); - } - - /* Create separate GAS structs for the PM1 Enable registers */ - - acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, - (u8) ACPI_DIV_2(acpi_gbl_FADT-> - pm1_evt_len), - (acpi_physical_address) - (local_fadt->xpm1a_evt_blk.address + - ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len))); - - acpi_gbl_xpm1a_enable.address_space_id = - local_fadt->xpm1a_evt_blk.address_space_id; - - /* PM1B is optional; leave null if not present */ - - if (local_fadt->xpm1b_evt_blk.address) { - acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, - (u8) ACPI_DIV_2(acpi_gbl_FADT-> - pm1_evt_len), - (acpi_physical_address) - (local_fadt->xpm1b_evt_blk. - address + - ACPI_DIV_2(acpi_gbl_FADT-> - pm1_evt_len))); - - acpi_gbl_xpm1b_enable.address_space_id = - local_fadt->xpm1b_evt_blk.address_space_id; - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_convert_table_fadt - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Converts a BIOS supplied ACPI 1.0 FADT to a local - * ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply - * copied to the local FADT. The ACPI CA software uses this - * local FADT. Thus a significant amount of special #ifdef - * type codeing is saved. - * - ******************************************************************************/ - -acpi_status acpi_tb_convert_table_fadt(void) -{ - struct fadt_descriptor *local_fadt; - struct acpi_table_desc *table_desc; - - ACPI_FUNCTION_TRACE(tb_convert_table_fadt); - - /* - * acpi_gbl_FADT is valid. Validate the FADT length. The table must be - * at least as long as the version 1.0 FADT - */ - if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor_rev1)) { - ACPI_ERROR((AE_INFO, "FADT is invalid, too short: 0x%X", - acpi_gbl_FADT->length)); - return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); - } - - /* Allocate buffer for the ACPI 2.0(+) FADT */ - - local_fadt = ACPI_ALLOCATE_ZEROED(sizeof(struct fadt_descriptor)); - if (!local_fadt) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) { - if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor)) { - - /* Length is too short to be a V2.0 table */ - - ACPI_WARNING((AE_INFO, - "Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table", - acpi_gbl_FADT->length, - acpi_gbl_FADT->revision)); - - acpi_tb_convert_fadt1(local_fadt, - (void *)acpi_gbl_FADT); - } else { - /* Valid V2.0 table */ - - acpi_tb_convert_fadt2(local_fadt, acpi_gbl_FADT); - } - } else { - /* Valid V1.0 table */ - - acpi_tb_convert_fadt1(local_fadt, (void *)acpi_gbl_FADT); - } - - /* Global FADT pointer will point to the new common V2.0 FADT */ - - acpi_gbl_FADT = local_fadt; - acpi_gbl_FADT->length = sizeof(struct fadt_descriptor); - - /* Free the original table */ - - table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_FADT].next; - acpi_tb_delete_single_table(table_desc); - - /* Install the new table */ - - table_desc->pointer = - ACPI_CAST_PTR(struct acpi_table_header, acpi_gbl_FADT); - table_desc->allocation = ACPI_MEM_ALLOCATED; - table_desc->length = sizeof(struct fadt_descriptor); - - /* Dump the entire FADT */ - - ACPI_DEBUG_PRINT((ACPI_DB_TABLES, - "Hex dump of common internal FADT, size %d (%X)\n", - acpi_gbl_FADT->length, acpi_gbl_FADT->length)); - - ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_FADT), - acpi_gbl_FADT->length); - - return_ACPI_STATUS(AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_build_common_facs - * - * PARAMETERS: table_info - Info for currently installed FACS - * - * RETURN: Status - * - * DESCRIPTION: Convert ACPI 1.0 and ACPI 2.0 FACS to a common internal - * table format. - * - ******************************************************************************/ - -acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info) -{ - - ACPI_FUNCTION_TRACE(tb_build_common_facs); - - /* Absolute minimum length is 24, but the ACPI spec says 64 */ - - if (acpi_gbl_FACS->length < 24) { - ACPI_ERROR((AE_INFO, "Invalid FACS table length: 0x%X", - acpi_gbl_FACS->length)); - return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); - } - - if (acpi_gbl_FACS->length < 64) { - ACPI_WARNING((AE_INFO, - "FACS is shorter than the ACPI specification allows: 0x%X, using anyway", - acpi_gbl_FACS->length)); - } - - /* Copy fields to the new FACS */ - - acpi_gbl_common_fACS.global_lock = &(acpi_gbl_FACS->global_lock); - - if ((acpi_gbl_RSDP->revision < 2) || - (acpi_gbl_FACS->length < 32) || - (!(acpi_gbl_FACS->xfirmware_waking_vector))) { - - /* ACPI 1.0 FACS or short table or optional X_ field is zero */ - - acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR(u64, - & - (acpi_gbl_FACS-> - firmware_waking_vector)); - acpi_gbl_common_fACS.vector_width = 32; - } else { - /* ACPI 2.0 FACS with valid X_ field */ - - acpi_gbl_common_fACS.firmware_waking_vector = - &acpi_gbl_FACS->xfirmware_waking_vector; - acpi_gbl_common_fACS.vector_width = 64; - } - - return_ACPI_STATUS(AE_OK); -} diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c new file mode 100644 index 000000000000..807c7116e94b --- /dev/null +++ b/drivers/acpi/tables/tbfadt.c @@ -0,0 +1,434 @@ +/****************************************************************************** + * + * Module Name: tbfadt - FADT table utilities + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2007, 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. + */ + +#include +#include + +#define _COMPONENT ACPI_TABLES +ACPI_MODULE_NAME("tbfadt") + +/* Local prototypes */ +static void inline +acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, + u8 bit_width, u64 address); + +static void acpi_tb_convert_fadt(void); + +static void acpi_tb_validate_fadt(void); + +/* Table for conversion of FADT to common internal format and FADT validation */ + +typedef struct acpi_fadt_info { + char *name; + u8 target; + u8 source; + u8 length; + u8 type; + +} acpi_fadt_info; + +#define ACPI_FADT_REQUIRED 1 +#define ACPI_FADT_SEPARATE_LENGTH 2 + +static struct acpi_fadt_info fadt_info_table[] = { + {"Pm1aEventBlock", ACPI_FADT_OFFSET(xpm1a_event_block), + ACPI_FADT_OFFSET(pm1a_event_block), + ACPI_FADT_OFFSET(pm1_event_length), ACPI_FADT_REQUIRED}, + + {"Pm1bEventBlock", ACPI_FADT_OFFSET(xpm1b_event_block), + ACPI_FADT_OFFSET(pm1b_event_block), + ACPI_FADT_OFFSET(pm1_event_length), 0}, + + {"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block), + ACPI_FADT_OFFSET(pm1a_control_block), + ACPI_FADT_OFFSET(pm1_control_length), ACPI_FADT_REQUIRED}, + + {"Pm1bControlBlock", ACPI_FADT_OFFSET(xpm1b_control_block), + ACPI_FADT_OFFSET(pm1b_control_block), + ACPI_FADT_OFFSET(pm1_control_length), 0}, + + {"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block), + ACPI_FADT_OFFSET(pm2_control_block), + ACPI_FADT_OFFSET(pm2_control_length), ACPI_FADT_SEPARATE_LENGTH}, + + {"PmTimerBlock", ACPI_FADT_OFFSET(xpm_timer_block), + ACPI_FADT_OFFSET(pm_timer_block), + ACPI_FADT_OFFSET(pm_timer_length), ACPI_FADT_REQUIRED}, + + {"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block), + ACPI_FADT_OFFSET(gpe0_block), + ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_SEPARATE_LENGTH}, + + {"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block), + ACPI_FADT_OFFSET(gpe1_block), + ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_SEPARATE_LENGTH} +}; + +#define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info)) + +/******************************************************************************* + * + * FUNCTION: acpi_tb_init_generic_address + * + * PARAMETERS: generic_address - GAS struct to be initialized + * bit_width - Width of this register + * Address - Address of the register + * + * RETURN: None + * + * DESCRIPTION: Initialize a Generic Address Structure (GAS) + * See the ACPI specification for a full description and + * definition of this structure. + * + ******************************************************************************/ + +static void inline +acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, + u8 bit_width, u64 address) +{ + + /* + * The 64-bit Address field is non-aligned in the byte packed + * GAS struct. + */ + ACPI_MOVE_64_TO_64(&generic_address->address, &address); + + /* All other fields are byte-wide */ + + generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO; + generic_address->bit_width = bit_width; + generic_address->bit_offset = 0; + generic_address->access_width = 0; +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_parse_fadt + * + * PARAMETERS: table_index - Index for the FADT + * Flags - Flags + * + * RETURN: None + * + * DESCRIPTION: Initialize the FADT, DSDT and FACS tables + * (FADT contains the addresses of the DSDT and FACS) + * + ******************************************************************************/ + +void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags) +{ + u32 length; + struct acpi_table_header *table; + + /* + * The FADT has multiple versions with different lengths, + * and it contains pointers to both the DSDT and FACS tables. + * + * Get a local copy of the FADT and convert it to a common format + * Map entire FADT, assumed to be smaller than one page. + */ + length = acpi_gbl_root_table_list.tables[table_index].length; + + table = + acpi_os_map_memory(acpi_gbl_root_table_list.tables[table_index]. + address, length); + if (!table) { + return; + } + + /* + * Validate the FADT checksum before we copy the table. Ignore + * checksum error as we want to try to get the DSDT and FACS. + */ + (void)acpi_tb_verify_checksum(table, length); + + /* Obtain a local copy of the FADT in common ACPI 2.0+ format */ + + acpi_tb_create_local_fadt(table, length); + + /* All done with the real FADT, unmap it */ + + acpi_os_unmap_memory(table, length); + + /* Obtain the DSDT and FACS tables via their addresses within the FADT */ + + acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, + flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); + + acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs, + flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_create_local_fadt + * + * PARAMETERS: Table - Pointer to BIOS FADT + * Length - Length of the table + * + * RETURN: None + * + * DESCRIPTION: Get a local copy of the FADT and convert it to a common format. + * Performs validation on some important FADT fields. + * + ******************************************************************************/ + +void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) +{ + + /* + * Check if the FADT is larger than what we know about (ACPI 2.0 version). + * Truncate the table, but make some noise. + */ + if (length > sizeof(struct acpi_table_fadt)) { + ACPI_WARNING((AE_INFO, + "FADT (revision %u) is longer than ACPI 2.0 version, truncating length 0x%X to 0x%zX", + table->revision, (unsigned)length, + sizeof(struct acpi_table_fadt))); + } + + /* Copy the entire FADT locally. Zero first for tb_convert_fadt */ + + ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt)); + + ACPI_MEMCPY(&acpi_gbl_FADT, table, + ACPI_MIN(length, sizeof(struct acpi_table_fadt))); + + /* + * 1) Convert the local copy of the FADT to the common internal format + * 2) Validate some of the important values within the FADT + */ + acpi_tb_convert_fadt(); + acpi_tb_validate_fadt(); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_convert_fadt + * + * PARAMETERS: None, uses acpi_gbl_FADT + * + * RETURN: None + * + * DESCRIPTION: Converts all versions of the FADT to a common internal format. + * -> Expand all 32-bit addresses to 64-bit. + * + * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), + * and must contain a copy of the actual FADT. + * + * ACPICA will use the "X" fields of the FADT for all addresses. + * + * "X" fields are optional extensions to the original V1.0 fields. Even if + * they are present in the structure, they can be optionally not used by + * setting them to zero. Therefore, we must selectively expand V1.0 fields + * if the corresponding X field is zero. + * + * For ACPI 1.0 FADTs, all address fields are expanded to the corresponding + * "X" fields. + * + * For ACPI 2.0 FADTs, any "X" fields that are NULL are filled in by + * expanding the corresponding ACPI 1.0 field. + * + ******************************************************************************/ + +static void acpi_tb_convert_fadt(void) +{ + u8 pm1_register_length; + struct acpi_generic_address *target; + acpi_native_uint i; + + /* Update the local FADT table header length */ + + acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); + + /* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary */ + + if (!acpi_gbl_FADT.Xfacs) { + acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs; + } + + if (!acpi_gbl_FADT.Xdsdt) { + acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt; + } + + /* + * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address + * structures as necessary. + */ + for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { + target = + ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, + fadt_info_table[i].target); + + /* Expand only if the X target is null */ + + if (!target->address) { + acpi_tb_init_generic_address(target, + *ACPI_ADD_PTR(u8, + &acpi_gbl_FADT, + fadt_info_table + [i].length), + (u64) * ACPI_ADD_PTR(u32, + &acpi_gbl_FADT, + fadt_info_table + [i]. + source)); + } + } + + /* + * Calculate separate GAS structs for the PM1 Enable registers. + * These addresses do not appear (directly) in the FADT, so it is + * useful to calculate them once, here. + * + * The PM event blocks are split into two register blocks, first is the + * PM Status Register block, followed immediately by the PM Enable Register + * block. Each is of length (pm1_event_length/2) + */ + pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length); + + /* The PM1A register block is required */ + + acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, + pm1_register_length, + (acpi_gbl_FADT.xpm1a_event_block.address + + pm1_register_length)); + /* Don't forget to copy space_id of the GAS */ + acpi_gbl_xpm1a_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id; + + /* The PM1B register block is optional, ignore if not present */ + + if (acpi_gbl_FADT.xpm1b_event_block.address) { + acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, + pm1_register_length, + (acpi_gbl_FADT.xpm1b_event_block. + address + pm1_register_length)); + /* Don't forget to copy space_id of the GAS */ + acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id; + + } +} + +/****************************************************************************** + * + * FUNCTION: acpi_tb_validate_fadt + * + * PARAMETERS: Table - Pointer to the FADT to be validated + * + * RETURN: None + * + * DESCRIPTION: Validate various important fields within the FADT. If a problem + * is found, issue a message, but no status is returned. + * Used by both the table manager and the disassembler. + * + * Possible additional checks: + * (acpi_gbl_FADT.pm1_event_length >= 4) + * (acpi_gbl_FADT.pm1_control_length >= 2) + * (acpi_gbl_FADT.pm_timer_length >= 4) + * Gpe block lengths must be multiple of 2 + * + ******************************************************************************/ + +static void acpi_tb_validate_fadt(void) +{ + u32 *address32; + struct acpi_generic_address *address64; + u8 length; + acpi_native_uint i; + + /* Examine all of the 64-bit extended address fields (X fields) */ + + for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { + + /* Generate pointers to the 32-bit and 64-bit addresses and get the length */ + + address64 = + ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, + fadt_info_table[i].target); + address32 = + ACPI_ADD_PTR(u32, &acpi_gbl_FADT, + fadt_info_table[i].source); + length = + *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, + fadt_info_table[i].length); + + if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) { + /* + * Field is required (Pm1a_event, Pm1a_control, pm_timer). + * Both the address and length must be non-zero. + */ + if (!address64->address || !length) { + ACPI_ERROR((AE_INFO, + "Required field \"%s\" has zero address and/or length: %8.8X%8.8X/%X", + fadt_info_table[i].name, + ACPI_FORMAT_UINT64(address64-> + address), + length)); + } + } else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) { + /* + * Field is optional (PM2Control, GPE0, GPE1) AND has its own + * length field. If present, both the address and length must be valid. + */ + if ((address64->address && !length) + || (!address64->address && length)) { + ACPI_WARNING((AE_INFO, + "Optional field \"%s\" has zero address or length: %8.8X%8.8X/%X", + fadt_info_table[i].name, + ACPI_FORMAT_UINT64(address64-> + address), + length)); + } + } + + /* If both 32- and 64-bit addresses are valid (non-zero), they must match */ + + if (address64->address && *address32 && + (address64->address != (u64) * address32)) { + ACPI_ERROR((AE_INFO, + "32/64X address mismatch in \"%s\": [%8.8X] [%8.8X%8.8X], using 64X", + fadt_info_table[i].name, *address32, + ACPI_FORMAT_UINT64(address64->address))); + } + } +} diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/tables/tbfind.c new file mode 100644 index 000000000000..058c064948e1 --- /dev/null +++ b/drivers/acpi/tables/tbfind.c @@ -0,0 +1,126 @@ +/****************************************************************************** + * + * Module Name: tbfind - find table + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2007, 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. + */ + +#include +#include + +#define _COMPONENT ACPI_TABLES +ACPI_MODULE_NAME("tbfind") + +/******************************************************************************* + * + * FUNCTION: acpi_tb_find_table + * + * PARAMETERS: Signature - String with ACPI table signature + * oem_id - String with the table OEM ID + * oem_table_id - String with the OEM Table ID + * table_index - Where the table index is returned + * + * RETURN: Status and table index + * + * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the + * Signature, OEM ID and OEM Table ID. Returns an index that can + * be used to get the table header or entire table. + * + ******************************************************************************/ +acpi_status +acpi_tb_find_table(char *signature, + char *oem_id, + char *oem_table_id, acpi_native_uint * table_index) +{ + acpi_native_uint i; + acpi_status status; + + ACPI_FUNCTION_TRACE(tb_find_table); + + for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { + if (ACPI_MEMCMP(&(acpi_gbl_root_table_list.tables[i].signature), + signature, ACPI_NAME_SIZE)) { + + /* Not the requested table */ + + continue; + } + + /* Table with matching signature has been found */ + + if (!acpi_gbl_root_table_list.tables[i].pointer) { + + /* Table is not currently mapped, map it */ + + status = + acpi_tb_verify_table(&acpi_gbl_root_table_list. + tables[i]); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + if (!acpi_gbl_root_table_list.tables[i].pointer) { + continue; + } + } + + /* Check for table match on all IDs */ + + if (!ACPI_MEMCMP + (acpi_gbl_root_table_list.tables[i].pointer->signature, + signature, ACPI_NAME_SIZE) && (!oem_id[0] + || + !ACPI_MEMCMP + (acpi_gbl_root_table_list. + tables[i].pointer->oem_id, + oem_id, ACPI_OEM_ID_SIZE)) + && (!oem_table_id[0] + || !ACPI_MEMCMP(acpi_gbl_root_table_list.tables[i]. + pointer->oem_table_id, oem_table_id, + ACPI_OEM_TABLE_ID_SIZE))) { + *table_index = i; + + ACPI_DEBUG_PRINT((ACPI_DB_TABLES, + "Found table [%4.4s]\n", signature)); + return_ACPI_STATUS(AE_OK); + } + } + + return_ACPI_STATUS(AE_NOT_FOUND); +} diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c deleted file mode 100644 index 11e2d4454e05..000000000000 --- a/drivers/acpi/tables/tbget.c +++ /dev/null @@ -1,471 +0,0 @@ -/****************************************************************************** - * - * Module Name: tbget - ACPI Table get* routines - * - *****************************************************************************/ - -/* - * 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. - */ - -#include -#include - -#define _COMPONENT ACPI_TABLES -ACPI_MODULE_NAME("tbget") - -/* Local prototypes */ -static acpi_status -acpi_tb_get_this_table(struct acpi_pointer *address, - struct acpi_table_header *header, - struct acpi_table_desc *table_info); - -static acpi_status -acpi_tb_table_override(struct acpi_table_header *header, - struct acpi_table_desc *table_info); - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_table - * - * PARAMETERS: Address - Address of table to retrieve. Can be - * Logical or Physical - * table_info - Where table info is returned - * - * RETURN: None - * - * DESCRIPTION: Get entire table of unknown size. - * - ******************************************************************************/ - -acpi_status -acpi_tb_get_table(struct acpi_pointer *address, - struct acpi_table_desc *table_info) -{ - acpi_status status; - struct acpi_table_header header; - - ACPI_FUNCTION_TRACE(tb_get_table); - - /* Get the header in order to get signature and table size */ - - status = acpi_tb_get_table_header(address, &header); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Get the entire table */ - - status = acpi_tb_get_table_body(address, &header, table_info); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not get ACPI table (size %X)", - header.length)); - return_ACPI_STATUS(status); - } - - return_ACPI_STATUS(AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_table_header - * - * PARAMETERS: Address - Address of table to retrieve. Can be - * Logical or Physical - * return_header - Where the table header is returned - * - * RETURN: Status - * - * DESCRIPTION: Get an ACPI table header. Works in both physical or virtual - * addressing mode. Works with both physical or logical pointers. - * Table is either copied or mapped, depending on the pointer - * type and mode of the processor. - * - ******************************************************************************/ - -acpi_status -acpi_tb_get_table_header(struct acpi_pointer *address, - struct acpi_table_header *return_header) -{ - acpi_status status = AE_OK; - struct acpi_table_header *header = NULL; - - ACPI_FUNCTION_TRACE(tb_get_table_header); - - /* - * Flags contains the current processor mode (Virtual or Physical - * addressing) The pointer_type is either Logical or Physical - */ - switch (address->pointer_type) { - case ACPI_PHYSMODE_PHYSPTR: - case ACPI_LOGMODE_LOGPTR: - - /* Pointer matches processor mode, copy the header */ - - ACPI_MEMCPY(return_header, address->pointer.logical, - sizeof(struct acpi_table_header)); - break; - - case ACPI_LOGMODE_PHYSPTR: - - /* Create a logical address for the physical pointer */ - - status = acpi_os_map_memory(address->pointer.physical, - sizeof(struct acpi_table_header), - (void *)&header); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not map memory at %8.8X%8.8X for table header", - ACPI_FORMAT_UINT64(address->pointer. - physical))); - return_ACPI_STATUS(status); - } - - /* Copy header and delete mapping */ - - ACPI_MEMCPY(return_header, header, - sizeof(struct acpi_table_header)); - acpi_os_unmap_memory(header, sizeof(struct acpi_table_header)); - break; - - default: - - ACPI_ERROR((AE_INFO, "Invalid address flags %X", - address->pointer_type)); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Table Signature: [%4.4s]\n", - return_header->signature)); - - return_ACPI_STATUS(AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_table_body - * - * PARAMETERS: Address - Address of table to retrieve. Can be - * Logical or Physical - * Header - Header of the table to retrieve - * table_info - Where the table info is returned - * - * RETURN: Status - * - * DESCRIPTION: Get an entire ACPI table with support to allow the host OS to - * replace the table with a newer version (table override.) - * Works in both physical or virtual - * addressing mode. Works with both physical or logical pointers. - * Table is either copied or mapped, depending on the pointer - * type and mode of the processor. - * - ******************************************************************************/ - -acpi_status -acpi_tb_get_table_body(struct acpi_pointer *address, - struct acpi_table_header *header, - struct acpi_table_desc *table_info) -{ - acpi_status status; - - ACPI_FUNCTION_TRACE(tb_get_table_body); - - if (!table_info || !address) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Attempt table override. */ - - status = acpi_tb_table_override(header, table_info); - if (ACPI_SUCCESS(status)) { - - /* Table was overridden by the host OS */ - - return_ACPI_STATUS(status); - } - - /* No override, get the original table */ - - status = acpi_tb_get_this_table(address, header, table_info); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_table_override - * - * PARAMETERS: Header - Pointer to table header - * table_info - Return info if table is overridden - * - * RETURN: None - * - * DESCRIPTION: Attempts override of current table with a new one if provided - * by the host OS. - * - ******************************************************************************/ - -static acpi_status -acpi_tb_table_override(struct acpi_table_header *header, - struct acpi_table_desc *table_info) -{ - struct acpi_table_header *new_table; - acpi_status status; - struct acpi_pointer address; - - ACPI_FUNCTION_TRACE(tb_table_override); - - /* - * The OSL will examine the header and decide whether to override this - * table. If it decides to override, a table will be returned in new_table, - * which we will then copy. - */ - status = acpi_os_table_override(header, &new_table); - if (ACPI_FAILURE(status)) { - - /* Some severe error from the OSL, but we basically ignore it */ - - ACPI_EXCEPTION((AE_INFO, status, - "Could not override ACPI table")); - return_ACPI_STATUS(status); - } - - if (!new_table) { - - /* No table override */ - - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - - /* - * We have a new table to override the old one. Get a copy of - * the new one. We know that the new table has a logical pointer. - */ - address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING; - address.pointer.logical = new_table; - - status = acpi_tb_get_this_table(&address, new_table, table_info); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Could not copy ACPI table")); - return_ACPI_STATUS(status); - } - - /* Copy the table info */ - - ACPI_INFO((AE_INFO, "Table [%4.4s] replaced by host OS", - table_info->pointer->signature)); - - return_ACPI_STATUS(AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_this_table - * - * PARAMETERS: Address - Address of table to retrieve. Can be - * Logical or Physical - * Header - Header of the table to retrieve - * table_info - Where the table info is returned - * - * RETURN: Status - * - * DESCRIPTION: Get an entire ACPI table. Works in both physical or virtual - * addressing mode. Works with both physical or logical pointers. - * Table is either copied or mapped, depending on the pointer - * type and mode of the processor. - * - ******************************************************************************/ - -static acpi_status -acpi_tb_get_this_table(struct acpi_pointer *address, - struct acpi_table_header *header, - struct acpi_table_desc *table_info) -{ - struct acpi_table_header *full_table = NULL; - u8 allocation; - acpi_status status = AE_OK; - - ACPI_FUNCTION_TRACE(tb_get_this_table); - - /* Validate minimum length */ - - if (header->length < sizeof(struct acpi_table_header)) { - ACPI_ERROR((AE_INFO, - "Table length (%X) is smaller than minimum (%zX)", - header->length, sizeof(struct acpi_table_header))); - - return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); - } - - /* - * Flags contains the current processor mode (Virtual or Physical - * addressing) The pointer_type is either Logical or Physical - */ - switch (address->pointer_type) { - case ACPI_PHYSMODE_PHYSPTR: - case ACPI_LOGMODE_LOGPTR: - - /* Pointer matches processor mode, copy the table to a new buffer */ - - full_table = ACPI_ALLOCATE(header->length); - if (!full_table) { - ACPI_ERROR((AE_INFO, - "Could not allocate table memory for [%4.4s] length %X", - header->signature, header->length)); - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* Copy the entire table (including header) to the local buffer */ - - ACPI_MEMCPY(full_table, address->pointer.logical, - header->length); - - /* Save allocation type */ - - allocation = ACPI_MEM_ALLOCATED; - break; - - case ACPI_LOGMODE_PHYSPTR: - - /* - * Just map the table's physical memory - * into our address space. - */ - status = acpi_os_map_memory(address->pointer.physical, - (acpi_size) header->length, - ACPI_CAST_PTR(void, &full_table)); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X", - header->signature, - ACPI_FORMAT_UINT64(address->pointer. - physical), - header->length)); - return (status); - } - - /* Save allocation type */ - - allocation = ACPI_MEM_MAPPED; - break; - - default: - - ACPI_ERROR((AE_INFO, "Invalid address flags %X", - address->pointer_type)); - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* - * Validate checksum for _most_ tables, - * even the ones whose signature we don't recognize - */ - if (table_info->type != ACPI_TABLE_ID_FACS) { - status = acpi_tb_verify_table_checksum(full_table); - -#if (!ACPI_CHECKSUM_ABORT) - if (ACPI_FAILURE(status)) { - - /* Ignore the error if configuration says so */ - - status = AE_OK; - } -#endif - } - - /* Return values */ - - table_info->pointer = full_table; - table_info->length = (acpi_size) header->length; - table_info->allocation = allocation; - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n", - full_table->signature, - ACPI_FORMAT_UINT64(address->pointer.physical), - full_table)); - - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_table_ptr - * - * PARAMETERS: table_type - one of the defined table types - * Instance - Which table of this type - * return_table - pointer to location to place the pointer for - * return - * - * RETURN: Status - * - * DESCRIPTION: This function is called to get the pointer to an ACPI table. - * - ******************************************************************************/ - -acpi_status -acpi_tb_get_table_ptr(acpi_table_type table_type, - u32 instance, struct acpi_table_header **return_table) -{ - struct acpi_table_desc *table_desc; - u32 i; - - ACPI_FUNCTION_TRACE(tb_get_table_ptr); - - if (table_type > ACPI_TABLE_ID_MAX) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Check for instance out of range of the current table count */ - - if (instance > acpi_gbl_table_lists[table_type].count) { - return_ACPI_STATUS(AE_NOT_EXIST); - } - - /* - * Walk the list to get the desired table - * Note: Instance is one-based - */ - table_desc = acpi_gbl_table_lists[table_type].next; - for (i = 1; i < instance; i++) { - table_desc = table_desc->next; - } - - /* We are now pointing to the requested table's descriptor */ - - *return_table = table_desc->pointer; - return_ACPI_STATUS(AE_OK); -} diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c deleted file mode 100644 index ad982112e4c6..000000000000 --- a/drivers/acpi/tables/tbgetall.c +++ /dev/null @@ -1,311 +0,0 @@ -/****************************************************************************** - * - * Module Name: tbgetall - Get all required ACPI 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. - */ - -#include -#include - -#define _COMPONENT ACPI_TABLES -ACPI_MODULE_NAME("tbgetall") - -/* Local prototypes */ -static acpi_status -acpi_tb_get_primary_table(struct acpi_pointer *address, - struct acpi_table_desc *table_info); - -static acpi_status -acpi_tb_get_secondary_table(struct acpi_pointer *address, - acpi_string signature, - struct acpi_table_desc *table_info); - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_primary_table - * - * PARAMETERS: Address - Physical address of table to retrieve - * *table_info - Where the table info is returned - * - * RETURN: Status - * - * DESCRIPTION: Maps the physical address of table into a logical address - * - ******************************************************************************/ - -static acpi_status -acpi_tb_get_primary_table(struct acpi_pointer *address, - struct acpi_table_desc *table_info) -{ - acpi_status status; - struct acpi_table_header header; - - ACPI_FUNCTION_TRACE(tb_get_primary_table); - - /* Ignore a NULL address in the RSDT */ - - if (!address->pointer.value) { - return_ACPI_STATUS(AE_OK); - } - - /* Get the header in order to get signature and table size */ - - status = acpi_tb_get_table_header(address, &header); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Clear the table_info */ - - ACPI_MEMSET(table_info, 0, sizeof(struct acpi_table_desc)); - - /* - * Check the table signature and make sure it is recognized. - * Also checks the header checksum - */ - table_info->pointer = &header; - status = acpi_tb_recognize_table(table_info, ACPI_TABLE_PRIMARY); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Get the entire table */ - - status = acpi_tb_get_table_body(address, &header, table_info); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Install the table */ - - status = acpi_tb_install_table(table_info); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_secondary_table - * - * PARAMETERS: Address - Physical address of table to retrieve - * *table_info - Where the table info is returned - * - * RETURN: Status - * - * DESCRIPTION: Maps the physical address of table into a logical address - * - ******************************************************************************/ - -static acpi_status -acpi_tb_get_secondary_table(struct acpi_pointer *address, - acpi_string signature, - struct acpi_table_desc *table_info) -{ - acpi_status status; - struct acpi_table_header header; - - ACPI_FUNCTION_TRACE_STR(tb_get_secondary_table, signature); - - /* Get the header in order to match the signature */ - - status = acpi_tb_get_table_header(address, &header); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Signature must match request */ - - if (!ACPI_COMPARE_NAME(header.signature, signature)) { - ACPI_ERROR((AE_INFO, - "Incorrect table signature - wanted [%s] found [%4.4s]", - signature, header.signature)); - return_ACPI_STATUS(AE_BAD_SIGNATURE); - } - - /* - * Check the table signature and make sure it is recognized. - * Also checks the header checksum - */ - table_info->pointer = &header; - status = acpi_tb_recognize_table(table_info, ACPI_TABLE_SECONDARY); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Get the entire table */ - - status = acpi_tb_get_table_body(address, &header, table_info); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Install the table */ - - status = acpi_tb_install_table(table_info); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_required_tables - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Load and validate tables other than the RSDT. The RSDT must - * already be loaded and validated. - * - * Get the minimum set of ACPI tables, namely: - * - * 1) FADT (via RSDT in loop below) - * 2) FACS (via FADT) - * 3) DSDT (via FADT) - * - ******************************************************************************/ - -acpi_status acpi_tb_get_required_tables(void) -{ - acpi_status status = AE_OK; - u32 i; - struct acpi_table_desc table_info; - struct acpi_pointer address; - - ACPI_FUNCTION_TRACE(tb_get_required_tables); - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%d ACPI tables in RSDT\n", - acpi_gbl_rsdt_table_count)); - - address.pointer_type = acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING; - - /* - * Loop through all table pointers found in RSDT. - * This will NOT include the FACS and DSDT - we must get - * them after the loop. - * - * The only tables we are interested in getting here is the FADT and - * any SSDTs. - */ - for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { - - /* Get the table address from the common internal XSDT */ - - address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i]; - - /* - * Get the tables needed by this subsystem (FADT and any SSDTs). - * NOTE: All other tables are completely ignored at this time. - */ - status = acpi_tb_get_primary_table(&address, &table_info); - if ((status != AE_OK) && (status != AE_TABLE_NOT_SUPPORTED)) { - ACPI_WARNING((AE_INFO, - "%s, while getting table at %8.8X%8.8X", - acpi_format_exception(status), - ACPI_FORMAT_UINT64(address.pointer. - value))); - } - } - - /* We must have a FADT to continue */ - - if (!acpi_gbl_FADT) { - ACPI_ERROR((AE_INFO, "No FADT present in RSDT/XSDT")); - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - - /* - * Convert the FADT to a common format. This allows earlier revisions of - * the table to coexist with newer versions, using common access code. - */ - status = acpi_tb_convert_table_fadt(); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not convert FADT to internal common format")); - return_ACPI_STATUS(status); - } - - /* Get the FACS (Pointed to by the FADT) */ - - address.pointer.value = acpi_gbl_FADT->xfirmware_ctrl; - - status = acpi_tb_get_secondary_table(&address, FACS_SIG, &table_info); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not get/install the FACS")); - return_ACPI_STATUS(status); - } - - /* - * Create the common FACS pointer table - * (Contains pointers to the original table) - */ - status = acpi_tb_build_common_facs(&table_info); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Get/install the DSDT (Pointed to by the FADT) */ - - address.pointer.value = acpi_gbl_FADT->Xdsdt; - - status = acpi_tb_get_secondary_table(&address, DSDT_SIG, &table_info); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, "Could not get/install the DSDT")); - return_ACPI_STATUS(status); - } - - /* Set Integer Width (32/64) based upon DSDT revision */ - - acpi_ut_set_integer_width(acpi_gbl_DSDT->revision); - - /* Dump the entire DSDT */ - - ACPI_DEBUG_PRINT((ACPI_DB_TABLES, - "Hex dump of entire DSDT, size %d (0x%X), Integer width = %d\n", - acpi_gbl_DSDT->length, acpi_gbl_DSDT->length, - acpi_gbl_integer_bit_width)); - - ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_DSDT), - acpi_gbl_DSDT->length); - - /* Always delete the RSDP mapping, we are done with it */ - - acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_RSDP); - return_ACPI_STATUS(status); -} diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c index 1668a232fb67..0e7b121a99ce 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/tables/tbinstal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,510 +42,498 @@ */ #include +#include #include #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbinstal") -/* Local prototypes */ -static acpi_status -acpi_tb_match_signature(char *signature, - struct acpi_table_desc *table_info, u8 search_type); - -/******************************************************************************* +/****************************************************************************** * - * FUNCTION: acpi_tb_match_signature + * FUNCTION: acpi_tb_verify_table * - * PARAMETERS: Signature - Table signature to match - * table_info - Return data - * search_type - Table type to match (primary/secondary) + * PARAMETERS: table_desc - table * * RETURN: Status * - * DESCRIPTION: Compare signature against the list of "ACPI-subsystem-owned" - * tables (DSDT/FADT/SSDT, etc.) Returns the table_type_iD on match. + * DESCRIPTION: this function is called to verify and map table * - ******************************************************************************/ - -static acpi_status -acpi_tb_match_signature(char *signature, - struct acpi_table_desc *table_info, u8 search_type) + *****************************************************************************/ +acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc) { - acpi_native_uint i; + acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE(tb_match_signature); + ACPI_FUNCTION_TRACE(tb_verify_table); - /* Search for a signature match among the known table types */ + /* Map the table if necessary */ - for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) { - if (!(acpi_gbl_table_data[i].flags & search_type)) { - continue; + if (!table_desc->pointer) { + if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == + ACPI_TABLE_ORIGIN_MAPPED) { + table_desc->pointer = + acpi_os_map_memory(table_desc->address, + table_desc->length); } - - if (!ACPI_STRNCMP(signature, acpi_gbl_table_data[i].signature, - acpi_gbl_table_data[i].sig_length)) { - - /* Found a signature match, return index if requested */ - - if (table_info) { - table_info->type = (u8) i; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Table [%4.4s] is an ACPI table consumed by the core subsystem\n", - (char *)acpi_gbl_table_data[i]. - signature)); - - return_ACPI_STATUS(AE_OK); + if (!table_desc->pointer) { + return_ACPI_STATUS(AE_NO_MEMORY); } } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Table [%4.4s] is not an ACPI table consumed by the core subsystem - ignored\n", - (char *)signature)); + /* FACS is the odd table, has no standard ACPI header and no checksum */ - return_ACPI_STATUS(AE_TABLE_NOT_SUPPORTED); + if (!ACPI_COMPARE_NAME(&table_desc->signature, ACPI_SIG_FACS)) { + + /* Always calculate checksum, ignore bad checksum if requested */ + + status = + acpi_tb_verify_checksum(table_desc->pointer, + table_desc->length); + } + + return_ACPI_STATUS(status); } /******************************************************************************* * - * FUNCTION: acpi_tb_install_table + * FUNCTION: acpi_tb_add_table * - * PARAMETERS: table_info - Return value from acpi_tb_get_table_body + * PARAMETERS: table_desc - Table descriptor + * table_index - Where the table index is returned * * RETURN: Status * - * DESCRIPTION: Install the table into the global data structures. + * DESCRIPTION: This function is called to add the ACPI table * ******************************************************************************/ -acpi_status acpi_tb_install_table(struct acpi_table_desc *table_info) +acpi_status +acpi_tb_add_table(struct acpi_table_desc *table_desc, + acpi_native_uint * table_index) { - acpi_status status; + acpi_native_uint i; + acpi_native_uint length; + acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE(tb_install_table); + ACPI_FUNCTION_TRACE(tb_add_table); - /* Lock tables while installing */ + if (!table_desc->pointer) { + status = acpi_tb_verify_table(table_desc); + if (ACPI_FAILURE(status) || !table_desc->pointer) { + return_ACPI_STATUS(status); + } + } - status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not acquire table mutex")); - return_ACPI_STATUS(status); + /* The table must be either an SSDT or a PSDT */ + + if ((!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT)) + && + (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT))) + { + ACPI_ERROR((AE_INFO, + "Table has invalid signature [%4.4s], must be SSDT or PSDT", + table_desc->pointer->signature)); + return_ACPI_STATUS(AE_BAD_SIGNATURE); + } + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + + /* Check if table is already registered */ + + for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { + if (!acpi_gbl_root_table_list.tables[i].pointer) { + status = + acpi_tb_verify_table(&acpi_gbl_root_table_list. + tables[i]); + if (ACPI_FAILURE(status) + || !acpi_gbl_root_table_list.tables[i].pointer) { + continue; + } + } + + length = ACPI_MIN(table_desc->length, + acpi_gbl_root_table_list.tables[i].length); + if (ACPI_MEMCMP(table_desc->pointer, + acpi_gbl_root_table_list.tables[i].pointer, + length)) { + continue; + } + + /* Table is already registered */ + + acpi_tb_delete_table(table_desc); + *table_index = i; + goto release; } /* - * Ignore a table that is already installed. For example, some BIOS - * ASL code will repeatedly attempt to load the same SSDT. + * Add the table to the global table list */ - status = acpi_tb_is_table_installed(table_info); + status = acpi_tb_store_table(table_desc->address, table_desc->pointer, + table_desc->length, table_desc->flags, + table_index); if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + goto release; } - /* Install the table into the global data structure */ + acpi_tb_print_table_header(table_desc->address, table_desc->pointer); - status = acpi_tb_init_table_descriptor(table_info->type, table_info); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not install table [%4.4s]", - table_info->pointer->signature)); - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s located at %p\n", - acpi_gbl_table_data[table_info->type].name, - table_info->pointer)); - - unlock_and_exit: + release: (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(status); } /******************************************************************************* * - * FUNCTION: acpi_tb_recognize_table + * FUNCTION: acpi_tb_resize_root_table_list * - * PARAMETERS: table_info - Return value from acpi_tb_get_table_body - * search_type - Table type to match (primary/secondary) + * PARAMETERS: None * * RETURN: Status * - * DESCRIPTION: Check a table signature for a match against known table types - * - * NOTE: All table pointers are validated as follows: - * 1) Table pointer must point to valid physical memory - * 2) Signature must be 4 ASCII chars, even if we don't recognize the - * name - * 3) Table must be readable for length specified in the header - * 4) Table checksum must be valid (with the exception of the FACS - * which has no checksum for some odd reason) + * DESCRIPTION: Expand the size of global table array * ******************************************************************************/ -acpi_status -acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type) +acpi_status acpi_tb_resize_root_table_list(void) { - struct acpi_table_header *table_header; - acpi_status status; + struct acpi_table_desc *tables; - ACPI_FUNCTION_TRACE(tb_recognize_table); + ACPI_FUNCTION_TRACE(tb_resize_root_table_list); - /* Ensure that we have a valid table pointer */ + /* allow_resize flag is a parameter to acpi_initialize_tables */ - table_header = (struct acpi_table_header *)table_info->pointer; - if (!table_header) { - return_ACPI_STATUS(AE_BAD_PARAMETER); + if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) { + ACPI_ERROR((AE_INFO, + "Resize of Root Table Array is not allowed")); + return_ACPI_STATUS(AE_SUPPORT); } - /* - * We only "recognize" a limited number of ACPI tables -- namely, the - * ones that are used by the subsystem (DSDT, FADT, etc.) - * - * An AE_TABLE_NOT_SUPPORTED means that the table was not recognized. - * This can be any one of many valid ACPI tables, it just isn't one of - * the tables that is consumed by the core subsystem - */ - status = acpi_tb_match_signature(table_header->signature, - table_info, search_type); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + /* Increase the Table Array size */ - status = acpi_tb_validate_table_header(table_header); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Return the table type and length via the info struct */ - - table_info->length = (acpi_size) table_header->length; - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_init_table_descriptor - * - * PARAMETERS: table_type - The type of the table - * table_info - A table info struct - * - * RETURN: None. - * - * DESCRIPTION: Install a table into the global data structs. - * - ******************************************************************************/ - -acpi_status -acpi_tb_init_table_descriptor(acpi_table_type table_type, - struct acpi_table_desc *table_info) -{ - struct acpi_table_list *list_head; - struct acpi_table_desc *table_desc; - acpi_status status; - - ACPI_FUNCTION_TRACE_U32(tb_init_table_descriptor, table_type); - - /* Allocate a descriptor for this table */ - - table_desc = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc)); - if (!table_desc) { + tables = ACPI_ALLOCATE_ZEROED((acpi_gbl_root_table_list.size + + ACPI_ROOT_TABLE_SIZE_INCREMENT) + * sizeof(struct acpi_table_desc)); + if (!tables) { + ACPI_ERROR((AE_INFO, + "Could not allocate new root table array")); return_ACPI_STATUS(AE_NO_MEMORY); } - /* Get a new owner ID for the table */ + /* Copy and free the previous table array */ - status = acpi_ut_allocate_owner_id(&table_desc->owner_id); - if (ACPI_FAILURE(status)) { - goto error_exit1; - } + if (acpi_gbl_root_table_list.tables) { + ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, + acpi_gbl_root_table_list.size * + sizeof(struct acpi_table_desc)); - /* Install the table into the global data structure */ - - list_head = &acpi_gbl_table_lists[table_type]; - - /* - * Two major types of tables: 1) Only one instance is allowed. This - * includes most ACPI tables such as the DSDT. 2) Multiple instances of - * the table are allowed. This includes SSDT and PSDTs. - */ - if (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags)) { - /* - * Only one table allowed, and a table has alread been installed - * at this location, so return an error. - */ - if (list_head->next) { - status = AE_ALREADY_EXISTS; - goto error_exit2; - } - - table_desc->next = list_head->next; - list_head->next = table_desc; - - if (table_desc->next) { - table_desc->next->prev = table_desc; - } - - list_head->count++; - } else { - /* - * Link the new table in to the list of tables of this type. - * Insert at the end of the list, order IS IMPORTANT. - * - * table_desc->Prev & Next are already NULL from calloc() - */ - list_head->count++; - - if (!list_head->next) { - list_head->next = table_desc; - } else { - table_desc->next = list_head->next; - - while (table_desc->next->next) { - table_desc->next = table_desc->next->next; - } - - table_desc->next->next = table_desc; - table_desc->prev = table_desc->next; - table_desc->next = NULL; + if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { + ACPI_FREE(acpi_gbl_root_table_list.tables); } } - /* Finish initialization of the table descriptor */ + acpi_gbl_root_table_list.tables = tables; + acpi_gbl_root_table_list.size += ACPI_ROOT_TABLE_SIZE_INCREMENT; + acpi_gbl_root_table_list.flags |= (u8) ACPI_ROOT_ORIGIN_ALLOCATED; - table_desc->loaded_into_namespace = FALSE; - table_desc->type = (u8) table_type; - table_desc->pointer = table_info->pointer; - table_desc->length = table_info->length; - table_desc->allocation = table_info->allocation; - table_desc->aml_start = (u8 *) (table_desc->pointer + 1), - table_desc->aml_length = (u32) - (table_desc->length - (u32) sizeof(struct acpi_table_header)); - - /* - * Set the appropriate global pointer (if there is one) to point to the - * newly installed table - */ - if (acpi_gbl_table_data[table_type].global_ptr) { - *(acpi_gbl_table_data[table_type].global_ptr) = - table_info->pointer; - } - - /* Return Data */ - - table_info->owner_id = table_desc->owner_id; - table_info->installed_desc = table_desc; return_ACPI_STATUS(AE_OK); - - /* Error exit with cleanup */ - - error_exit2: - - acpi_ut_release_owner_id(&table_desc->owner_id); - - error_exit1: - - ACPI_FREE(table_desc); - return_ACPI_STATUS(status); } /******************************************************************************* * - * FUNCTION: acpi_tb_delete_all_tables + * FUNCTION: acpi_tb_store_table * - * PARAMETERS: None. + * PARAMETERS: Address - Table address + * Table - Table header + * Length - Table length + * Flags - flags * - * RETURN: None. + * RETURN: Status and table index. + * + * DESCRIPTION: Add an ACPI table to the global table list + * + ******************************************************************************/ + +acpi_status +acpi_tb_store_table(acpi_physical_address address, + struct acpi_table_header *table, + u32 length, u8 flags, acpi_native_uint * table_index) +{ + acpi_status status = AE_OK; + + /* Ensure that there is room for the table in the Root Table List */ + + if (acpi_gbl_root_table_list.count >= acpi_gbl_root_table_list.size) { + status = acpi_tb_resize_root_table_list(); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + /* Initialize added table */ + + acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count]. + address = address; + acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count]. + pointer = table; + acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].length = + length; + acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count]. + owner_id = 0; + acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].flags = + flags; + + ACPI_MOVE_32_TO_32(& + (acpi_gbl_root_table_list. + tables[acpi_gbl_root_table_list.count].signature), + table->signature); + + *table_index = acpi_gbl_root_table_list.count; + acpi_gbl_root_table_list.count++; + return (status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_delete_table + * + * PARAMETERS: table_index - Table index + * + * RETURN: None + * + * DESCRIPTION: Delete one internal ACPI table + * + ******************************************************************************/ + +void acpi_tb_delete_table(struct acpi_table_desc *table_desc) +{ + /* Table must be mapped or allocated */ + if (!table_desc->pointer) { + return; + } + switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { + case ACPI_TABLE_ORIGIN_MAPPED: + acpi_os_unmap_memory(table_desc->pointer, table_desc->length); + break; + case ACPI_TABLE_ORIGIN_ALLOCATED: + ACPI_FREE(table_desc->pointer); + break; + default:; + } + + table_desc->pointer = NULL; +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_terminate + * + * PARAMETERS: None + * + * RETURN: None * * DESCRIPTION: Delete all internal ACPI tables * ******************************************************************************/ -void acpi_tb_delete_all_tables(void) +void acpi_tb_terminate(void) { - acpi_table_type type; + acpi_native_uint i; + + ACPI_FUNCTION_TRACE(tb_terminate); + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + + /* Delete the individual tables */ + + for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { + acpi_tb_delete_table(&acpi_gbl_root_table_list.tables[i]); + } /* - * Free memory allocated for ACPI tables - * Memory can either be mapped or allocated + * Delete the root table array if allocated locally. Array cannot be + * mapped, so we don't need to check for that flag. */ - for (type = 0; type < (ACPI_TABLE_ID_MAX + 1); type++) { - acpi_tb_delete_tables_by_type(type); + if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { + ACPI_FREE(acpi_gbl_root_table_list.tables); } + + acpi_gbl_root_table_list.tables = NULL; + acpi_gbl_root_table_list.flags = 0; + acpi_gbl_root_table_list.count = 0; + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); } /******************************************************************************* * - * FUNCTION: acpi_tb_delete_tables_by_type + * FUNCTION: acpi_tb_delete_namespace_by_owner * - * PARAMETERS: Type - The table type to be deleted + * PARAMETERS: table_index - Table index * - * RETURN: None. + * RETURN: None * - * DESCRIPTION: Delete an internal ACPI table - * Locks the ACPI table mutex + * DESCRIPTION: Delete all namespace objects created when this table was loaded. * ******************************************************************************/ -void acpi_tb_delete_tables_by_type(acpi_table_type type) +void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index) { - struct acpi_table_desc *table_desc; - u32 count; - u32 i; + acpi_owner_id owner_id; - ACPI_FUNCTION_TRACE_U32(tb_delete_tables_by_type, type); - - if (type > ACPI_TABLE_ID_MAX) { - return_VOID; - } - - if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_TABLES))) { + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.count) { + owner_id = + acpi_gbl_root_table_list.tables[table_index].owner_id; + } else { + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return; } - /* Clear the appropriate "typed" global table pointer */ - - switch (type) { - case ACPI_TABLE_ID_RSDP: - acpi_gbl_RSDP = NULL; - break; - - case ACPI_TABLE_ID_DSDT: - acpi_gbl_DSDT = NULL; - break; - - case ACPI_TABLE_ID_FADT: - acpi_gbl_FADT = NULL; - break; - - case ACPI_TABLE_ID_FACS: - acpi_gbl_FACS = NULL; - break; - - case ACPI_TABLE_ID_XSDT: - acpi_gbl_XSDT = NULL; - break; - - case ACPI_TABLE_ID_SSDT: - case ACPI_TABLE_ID_PSDT: - default: - break; - } - - /* - * Free the table - * 1) Get the head of the list - */ - table_desc = acpi_gbl_table_lists[type].next; - count = acpi_gbl_table_lists[type].count; - - /* - * 2) Walk the entire list, deleting both the allocated tables - * and the table descriptors - */ - for (i = 0; i < count; i++) { - table_desc = acpi_tb_uninstall_table(table_desc); - } - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_VOID; + acpi_ns_delete_namespace_by_owner(owner_id); } /******************************************************************************* * - * FUNCTION: acpi_tb_delete_single_table + * FUNCTION: acpi_tb_allocate_owner_id * - * PARAMETERS: table_info - A table info struct + * PARAMETERS: table_index - Table index * - * RETURN: None. + * RETURN: Status * - * DESCRIPTION: Low-level free for a single ACPI table. Handles cases where - * the table was allocated a buffer or was mapped. + * DESCRIPTION: Allocates owner_id in table_desc * ******************************************************************************/ -void acpi_tb_delete_single_table(struct acpi_table_desc *table_desc) +acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index) { + acpi_status status = AE_BAD_PARAMETER; - /* Must have a valid table descriptor and pointer */ + ACPI_FUNCTION_TRACE(tb_allocate_owner_id); - if ((!table_desc) || (!table_desc->pointer)) { - return; + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.count) { + status = acpi_ut_allocate_owner_id + (&(acpi_gbl_root_table_list.tables[table_index].owner_id)); } - /* Valid table, determine type of memory allocation */ - - switch (table_desc->allocation) { - case ACPI_MEM_NOT_ALLOCATED: - break; - - case ACPI_MEM_ALLOCATED: - - ACPI_FREE(table_desc->pointer); - break; - - case ACPI_MEM_MAPPED: - - acpi_os_unmap_memory(table_desc->pointer, table_desc->length); - break; - - default: - break; - } + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); } /******************************************************************************* * - * FUNCTION: acpi_tb_uninstall_table + * FUNCTION: acpi_tb_release_owner_id * - * PARAMETERS: table_info - A table info struct + * PARAMETERS: table_index - Table index * - * RETURN: Pointer to the next table in the list (of same type) + * RETURN: Status * - * DESCRIPTION: Free the memory associated with an internal ACPI table that - * is either installed or has never been installed. - * Table mutex should be locked. + * DESCRIPTION: Releases owner_id in table_desc * ******************************************************************************/ -struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc - *table_desc) +acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index) { - struct acpi_table_desc *next_desc; + acpi_status status = AE_BAD_PARAMETER; - ACPI_FUNCTION_TRACE_PTR(tb_uninstall_table, table_desc); + ACPI_FUNCTION_TRACE(tb_release_owner_id); - if (!table_desc) { - return_PTR(NULL); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.count) { + acpi_ut_release_owner_id(& + (acpi_gbl_root_table_list. + tables[table_index].owner_id)); + status = AE_OK; } - /* Unlink the descriptor from the doubly linked list */ - - if (table_desc->prev) { - table_desc->prev->next = table_desc->next; - } else { - /* Is first on list, update list head */ - - acpi_gbl_table_lists[table_desc->type].next = table_desc->next; - } - - if (table_desc->next) { - table_desc->next->prev = table_desc->prev; - } - - /* Free the memory allocated for the table itself */ - - acpi_tb_delete_single_table(table_desc); - - /* Free the owner ID associated with this table */ - - acpi_ut_release_owner_id(&table_desc->owner_id); - - /* Free the table descriptor */ - - next_desc = table_desc->next; - ACPI_FREE(table_desc); - - /* Return pointer to the next descriptor */ - - return_PTR(next_desc); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_owner_id + * + * PARAMETERS: table_index - Table index + * owner_id - Where the table owner_id is returned + * + * RETURN: Status + * + * DESCRIPTION: returns owner_id for the ACPI table + * + ******************************************************************************/ + +acpi_status +acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id) +{ + acpi_status status = AE_BAD_PARAMETER; + + ACPI_FUNCTION_TRACE(tb_get_owner_id); + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.count) { + *owner_id = + acpi_gbl_root_table_list.tables[table_index].owner_id; + status = AE_OK; + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_is_table_loaded + * + * PARAMETERS: table_index - Table index + * + * RETURN: Table Loaded Flag + * + ******************************************************************************/ + +u8 acpi_tb_is_table_loaded(acpi_native_uint table_index) +{ + u8 is_loaded = FALSE; + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.count) { + is_loaded = (u8) + (acpi_gbl_root_table_list.tables[table_index]. + flags & ACPI_TABLE_IS_LOADED); + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return (is_loaded); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_set_table_loaded_flag + * + * PARAMETERS: table_index - Table index + * is_loaded - TRUE if table is loaded, FALSE otherwise + * + * RETURN: None + * + * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE. + * + ******************************************************************************/ + +void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded) +{ + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (table_index < acpi_gbl_root_table_list.count) { + if (is_loaded) { + acpi_gbl_root_table_list.tables[table_index].flags |= + ACPI_TABLE_IS_LOADED; + } else { + acpi_gbl_root_table_list.tables[table_index].flags &= + ~ACPI_TABLE_IS_LOADED; + } + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); } diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c deleted file mode 100644 index 86a5fca9b739..000000000000 --- a/drivers/acpi/tables/tbrsdt.c +++ /dev/null @@ -1,307 +0,0 @@ -/****************************************************************************** - * - * Module Name: tbrsdt - ACPI RSDT table utilities - * - *****************************************************************************/ - -/* - * 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. - */ - -#include -#include - -#define _COMPONENT ACPI_TABLES -ACPI_MODULE_NAME("tbrsdt") - -/******************************************************************************* - * - * FUNCTION: acpi_tb_verify_rsdp - * - * PARAMETERS: Address - RSDP (Pointer to RSDT) - * - * RETURN: Status - * - * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table) - * - ******************************************************************************/ -acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address) -{ - struct acpi_table_desc table_info; - acpi_status status; - struct rsdp_descriptor *rsdp; - - ACPI_FUNCTION_TRACE(tb_verify_rsdp); - - switch (address->pointer_type) { - case ACPI_LOGICAL_POINTER: - - rsdp = address->pointer.logical; - break; - - case ACPI_PHYSICAL_POINTER: - /* - * Obtain access to the RSDP structure - */ - status = acpi_os_map_memory(address->pointer.physical, - sizeof(struct rsdp_descriptor), - ACPI_CAST_PTR(void, &rsdp)); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - break; - - default: - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Verify RSDP signature and checksum */ - - status = acpi_tb_validate_rsdp(rsdp); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - /* RSDP is ok. Init the table info */ - - table_info.pointer = ACPI_CAST_PTR(struct acpi_table_header, rsdp); - table_info.length = sizeof(struct rsdp_descriptor); - - if (address->pointer_type == ACPI_PHYSICAL_POINTER) { - table_info.allocation = ACPI_MEM_MAPPED; - } else { - table_info.allocation = ACPI_MEM_NOT_ALLOCATED; - } - - /* Save the table pointers and allocation info */ - - status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_RSDP, &table_info); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - /* Save the RSDP in a global for easy access */ - - acpi_gbl_RSDP = - ACPI_CAST_PTR(struct rsdp_descriptor, table_info.pointer); - return_ACPI_STATUS(status); - - /* Error exit */ - cleanup: - - if (acpi_gbl_table_flags & ACPI_PHYSICAL_POINTER) { - acpi_os_unmap_memory(rsdp, sizeof(struct rsdp_descriptor)); - } - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_rsdt_address - * - * PARAMETERS: out_address - Where the address is returned - * - * RETURN: None, Address - * - * DESCRIPTION: Extract the address of either the RSDT or XSDT, depending on the - * version of the RSDP and whether the XSDT pointer is valid - * - ******************************************************************************/ - -void acpi_tb_get_rsdt_address(struct acpi_pointer *out_address) -{ - - ACPI_FUNCTION_ENTRY(); - - out_address->pointer_type = - acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING; - - /* Use XSDT if it is present */ - - if ((acpi_gbl_RSDP->revision >= 2) && - acpi_gbl_RSDP->xsdt_physical_address) { - out_address->pointer.value = - acpi_gbl_RSDP->xsdt_physical_address; - acpi_gbl_root_table_type = ACPI_TABLE_TYPE_XSDT; - } else { - /* No XSDT, use the RSDT */ - - out_address->pointer.value = - acpi_gbl_RSDP->rsdt_physical_address; - acpi_gbl_root_table_type = ACPI_TABLE_TYPE_RSDT; - } -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_validate_rsdt - * - * PARAMETERS: table_ptr - Addressable pointer to the RSDT. - * - * RETURN: Status - * - * DESCRIPTION: Validate signature for the RSDT or XSDT - * - ******************************************************************************/ - -acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr) -{ - char *signature; - - ACPI_FUNCTION_ENTRY(); - - /* Validate minimum length */ - - if (table_ptr->length < sizeof(struct acpi_table_header)) { - ACPI_ERROR((AE_INFO, - "RSDT/XSDT length (%X) is smaller than minimum (%zX)", - table_ptr->length, - sizeof(struct acpi_table_header))); - - return (AE_INVALID_TABLE_LENGTH); - } - - /* Search for appropriate signature, RSDT or XSDT */ - - if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { - signature = RSDT_SIG; - } else { - signature = XSDT_SIG; - } - - if (!ACPI_COMPARE_NAME(table_ptr->signature, signature)) { - - /* Invalid RSDT or XSDT signature */ - - ACPI_ERROR((AE_INFO, - "Invalid signature where RSDP indicates RSDT/XSDT should be located. RSDP:")); - - ACPI_DUMP_BUFFER(acpi_gbl_RSDP, 20); - - ACPI_ERROR((AE_INFO, - "RSDT/XSDT signature at %X is invalid", - acpi_gbl_RSDP->rsdt_physical_address)); - - if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { - ACPI_ERROR((AE_INFO, "Looking for RSDT")); - } else { - ACPI_ERROR((AE_INFO, "Looking for XSDT")); - } - - ACPI_DUMP_BUFFER(ACPI_CAST_PTR(char, table_ptr), 48); - return (AE_BAD_SIGNATURE); - } - - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_get_table_rsdt - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table) - * - ******************************************************************************/ - -acpi_status acpi_tb_get_table_rsdt(void) -{ - struct acpi_table_desc table_info; - acpi_status status; - struct acpi_pointer address; - - ACPI_FUNCTION_TRACE(tb_get_table_rsdt); - - /* Get the RSDT/XSDT via the RSDP */ - - acpi_tb_get_rsdt_address(&address); - - table_info.type = ACPI_TABLE_ID_XSDT; - status = acpi_tb_get_table(&address, &table_info); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not get the RSDT/XSDT")); - return_ACPI_STATUS(status); - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "RSDP located at %p, points to RSDT physical=%8.8X%8.8X\n", - acpi_gbl_RSDP, - ACPI_FORMAT_UINT64(address.pointer.value))); - - /* Check the RSDT or XSDT signature */ - - status = acpi_tb_validate_rsdt(table_info.pointer); - if (ACPI_FAILURE(status)) { - goto error_cleanup; - } - - /* Get the number of tables defined in the RSDT or XSDT */ - - acpi_gbl_rsdt_table_count = acpi_tb_get_table_count(acpi_gbl_RSDP, - table_info.pointer); - - /* Convert and/or copy to an XSDT structure */ - - status = acpi_tb_convert_to_xsdt(&table_info); - if (ACPI_FAILURE(status)) { - goto error_cleanup; - } - - /* Save the table pointers and allocation info */ - - status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_XSDT, &table_info); - if (ACPI_FAILURE(status)) { - goto error_cleanup; - } - - acpi_gbl_XSDT = - ACPI_CAST_PTR(struct xsdt_descriptor, table_info.pointer); - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT)); - return_ACPI_STATUS(status); - - error_cleanup: - - /* Free table allocated by acpi_tb_get_table */ - - acpi_tb_delete_single_table(&table_info); - - return_ACPI_STATUS(status); -} diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c index 209a401801e3..1da64b4518c0 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/tables/tbutils.c @@ -1,11 +1,11 @@ /****************************************************************************** * - * Module Name: tbutils - Table manipulation utilities + * Module Name: tbutils - table utilities * *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,137 +48,119 @@ ACPI_MODULE_NAME("tbutils") /* Local prototypes */ -#ifdef ACPI_OBSOLETE_FUNCTIONS -acpi_status -acpi_tb_handle_to_object(u16 table_id, struct acpi_table_desc **table_desc); -#endif +static acpi_physical_address +acpi_tb_get_root_table_entry(u8 * table_entry, + acpi_native_uint table_entry_size); /******************************************************************************* * - * FUNCTION: acpi_tb_is_table_installed + * FUNCTION: acpi_tb_tables_loaded * - * PARAMETERS: new_table_desc - Descriptor for new table being installed + * PARAMETERS: None * - * RETURN: Status - AE_ALREADY_EXISTS if the table is already installed + * RETURN: TRUE if required ACPI tables are loaded * - * DESCRIPTION: Determine if an ACPI table is already installed - * - * MUTEX: Table data structures should be locked + * DESCRIPTION: Determine if the minimum required ACPI tables are present + * (FADT, FACS, DSDT) * ******************************************************************************/ -acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc) +u8 acpi_tb_tables_loaded(void) { - struct acpi_table_desc *table_desc; - ACPI_FUNCTION_TRACE(tb_is_table_installed); - - /* Get the list descriptor and first table descriptor */ - - table_desc = acpi_gbl_table_lists[new_table_desc->type].next; - - /* Examine all installed tables of this type */ - - while (table_desc) { - /* - * If the table lengths match, perform a full bytewise compare. This - * means that we will allow tables with duplicate oem_table_id(s), as - * long as the tables are different in some way. - * - * Checking if the table has been loaded into the namespace means that - * we don't check for duplicate tables during the initial installation - * of tables within the RSDT/XSDT. - */ - if ((table_desc->loaded_into_namespace) && - (table_desc->pointer->length == - new_table_desc->pointer->length) - && - (!ACPI_MEMCMP - (table_desc->pointer, new_table_desc->pointer, - new_table_desc->pointer->length))) { - - /* Match: this table is already installed */ - - ACPI_DEBUG_PRINT((ACPI_DB_TABLES, - "Table [%4.4s] already installed: Rev %X OemTableId [%8.8s]\n", - new_table_desc->pointer->signature, - new_table_desc->pointer->revision, - new_table_desc->pointer-> - oem_table_id)); - - new_table_desc->owner_id = table_desc->owner_id; - new_table_desc->installed_desc = table_desc; - - return_ACPI_STATUS(AE_ALREADY_EXISTS); - } - - /* Get next table on the list */ - - table_desc = table_desc->next; + if (acpi_gbl_root_table_list.count >= 3) { + return (TRUE); } - return_ACPI_STATUS(AE_OK); + return (FALSE); } /******************************************************************************* * - * FUNCTION: acpi_tb_validate_table_header + * FUNCTION: acpi_tb_print_table_header * - * PARAMETERS: table_header - Logical pointer to the table + * PARAMETERS: Address - Table physical address + * Header - Table header * - * RETURN: Status + * RETURN: None * - * DESCRIPTION: Check an ACPI table header for validity - * - * NOTE: Table pointers are validated as follows: - * 1) Table pointer must point to valid physical memory - * 2) Signature must be 4 ASCII chars, even if we don't recognize the - * name - * 3) Table must be readable for length specified in the header - * 4) Table checksum must be valid (with the exception of the FACS - * which has no checksum because it contains variable fields) + * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP. * ******************************************************************************/ -acpi_status -acpi_tb_validate_table_header(struct acpi_table_header *table_header) +void +acpi_tb_print_table_header(acpi_physical_address address, + struct acpi_table_header *header) { - acpi_name signature; - ACPI_FUNCTION_ENTRY(); + if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) { - /* Verify that this is a valid address */ + /* FACS only has signature and length fields of common table header */ - if (!acpi_os_readable(table_header, sizeof(struct acpi_table_header))) { - ACPI_ERROR((AE_INFO, - "Cannot read table header at %p", table_header)); + ACPI_INFO((AE_INFO, "%4.4s %08lX, %04X", + header->signature, (unsigned long)address, + header->length)); + } else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) { - return (AE_BAD_ADDRESS); + /* RSDP has no common fields */ + + ACPI_INFO((AE_INFO, "RSDP %08lX, %04X (r%d %6.6s)", + (unsigned long)address, + (ACPI_CAST_PTR(struct acpi_table_rsdp, header)-> + revision > + 0) ? ACPI_CAST_PTR(struct acpi_table_rsdp, + header)->length : 20, + ACPI_CAST_PTR(struct acpi_table_rsdp, + header)->revision, + ACPI_CAST_PTR(struct acpi_table_rsdp, + header)->oem_id)); + } else { + /* Standard ACPI table with full common header */ + + ACPI_INFO((AE_INFO, + "%4.4s %08lX, %04X (r%d %6.6s %8.8s %8X %4.4s %8X)", + header->signature, (unsigned long)address, + header->length, header->revision, header->oem_id, + header->oem_table_id, header->oem_revision, + header->asl_compiler_id, + header->asl_compiler_revision)); } +} - /* Ensure that the signature is 4 ASCII characters */ +/******************************************************************************* + * + * FUNCTION: acpi_tb_validate_checksum + * + * PARAMETERS: Table - ACPI table to verify + * Length - Length of entire table + * + * RETURN: Status + * + * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns + * exception on bad checksum. + * + ******************************************************************************/ - ACPI_MOVE_32_TO_32(&signature, table_header->signature); - if (!acpi_ut_valid_acpi_name(signature)) { - ACPI_ERROR((AE_INFO, "Invalid table signature 0x%8.8X", - signature)); +acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length) +{ + u8 checksum; - ACPI_DUMP_BUFFER(table_header, - sizeof(struct acpi_table_header)); - return (AE_BAD_SIGNATURE); - } + /* Compute the checksum on the table */ - /* Validate the table length */ + checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length); - if (table_header->length < sizeof(struct acpi_table_header)) { - ACPI_ERROR((AE_INFO, - "Invalid length 0x%X in table with signature %4.4s", - (u32) table_header->length, - ACPI_CAST_PTR(char, &signature))); + /* Checksum ok? (should be zero) */ - ACPI_DUMP_BUFFER(table_header, - sizeof(struct acpi_table_header)); - return (AE_BAD_HEADER); + if (checksum) { + ACPI_WARNING((AE_INFO, + "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X", + table->signature, table->checksum, + (u8) (table->checksum - checksum))); + +#if (ACPI_CHECKSUM_ABORT) + + return (AE_BAD_CHECKSUM); +#endif } return (AE_OK); @@ -186,157 +168,320 @@ acpi_tb_validate_table_header(struct acpi_table_header *table_header) /******************************************************************************* * - * FUNCTION: acpi_tb_sum_table + * FUNCTION: acpi_tb_checksum * - * PARAMETERS: Buffer - Buffer to sum - * Length - Size of the buffer + * PARAMETERS: Buffer - Pointer to memory region to be checked + * Length - Length of this memory region * - * RETURN: 8 bit sum of buffer + * RETURN: Checksum (u8) * - * DESCRIPTION: Computes an 8 bit sum of the buffer(length) and returns it. + * DESCRIPTION: Calculates circular checksum of memory region. * ******************************************************************************/ -u8 acpi_tb_sum_table(void *buffer, u32 length) +u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length) { - acpi_native_uint i; u8 sum = 0; + u8 *end = buffer + length; - if (!buffer || !length) { - return (0); + while (buffer < end) { + sum = (u8) (sum + *(buffer++)); } - for (i = 0; i < length; i++) { - sum = (u8) (sum + ((u8 *) buffer)[i]); - } - return (sum); + return sum; } /******************************************************************************* * - * FUNCTION: acpi_tb_generate_checksum + * FUNCTION: acpi_tb_install_table * - * PARAMETERS: Table - Pointer to a valid ACPI table (with a - * standard ACPI header) + * PARAMETERS: Address - Physical address of DSDT or FACS + * Flags - Flags + * Signature - Table signature, NULL if no need to + * match + * table_index - Index into root table array * - * RETURN: 8 bit checksum of buffer + * RETURN: None * - * DESCRIPTION: Computes an 8 bit checksum of the table. + * DESCRIPTION: Install an ACPI table into the global data structure. * ******************************************************************************/ -u8 acpi_tb_generate_checksum(struct acpi_table_header * table) +void +acpi_tb_install_table(acpi_physical_address address, + u8 flags, char *signature, acpi_native_uint table_index) { - u8 checksum; + struct acpi_table_header *table; - /* Sum the entire table as-is */ - - checksum = acpi_tb_sum_table(table, table->length); - - /* Subtract off the existing checksum value in the table */ - - checksum = (u8) (checksum - table->checksum); - - /* Compute the final checksum */ - - checksum = (u8) (0 - checksum); - return (checksum); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_set_checksum - * - * PARAMETERS: Table - Pointer to a valid ACPI table (with a - * standard ACPI header) - * - * RETURN: None. Sets the table checksum field - * - * DESCRIPTION: Computes an 8 bit checksum of the table and inserts the - * checksum into the table header. - * - ******************************************************************************/ - -void acpi_tb_set_checksum(struct acpi_table_header *table) -{ - - table->checksum = acpi_tb_generate_checksum(table); -} - -/******************************************************************************* - * - * FUNCTION: acpi_tb_verify_table_checksum - * - * PARAMETERS: *table_header - ACPI table to verify - * - * RETURN: 8 bit checksum of table - * - * DESCRIPTION: Generates an 8 bit checksum of table and returns and compares - * it to the existing checksum value. - * - ******************************************************************************/ - -acpi_status -acpi_tb_verify_table_checksum(struct acpi_table_header *table_header) -{ - u8 checksum; - - ACPI_FUNCTION_TRACE(tb_verify_table_checksum); - - /* Compute the checksum on the table */ - - checksum = acpi_tb_generate_checksum(table_header); - - /* Checksum ok? */ - - if (checksum == table_header->checksum) { - return_ACPI_STATUS(AE_OK); + if (!address) { + ACPI_ERROR((AE_INFO, + "Null physical address for ACPI table [%s]", + signature)); + return; } - ACPI_WARNING((AE_INFO, - "Incorrect checksum in table [%4.4s] - is %2.2X, should be %2.2X", - table_header->signature, table_header->checksum, - checksum)); + /* Map just the table header */ - return_ACPI_STATUS(AE_BAD_CHECKSUM); + table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); + if (!table) { + return; + } + + /* If a particular signature is expected, signature must match */ + + if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) { + ACPI_ERROR((AE_INFO, + "Invalid signature 0x%X for ACPI table [%s]", + *ACPI_CAST_PTR(u32, table->signature), signature)); + goto unmap_and_exit; + } + + /* Initialize the table entry */ + + acpi_gbl_root_table_list.tables[table_index].address = address; + acpi_gbl_root_table_list.tables[table_index].length = table->length; + acpi_gbl_root_table_list.tables[table_index].flags = flags; + + ACPI_MOVE_32_TO_32(& + (acpi_gbl_root_table_list.tables[table_index]. + signature), table->signature); + + acpi_tb_print_table_header(address, table); + + if (table_index == ACPI_TABLE_INDEX_DSDT) { + + /* Global integer width is based upon revision of the DSDT */ + + acpi_ut_set_integer_width(table->revision); + } + + unmap_and_exit: + acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); } -#ifdef ACPI_OBSOLETE_FUNCTIONS /******************************************************************************* * - * FUNCTION: acpi_tb_handle_to_object + * FUNCTION: acpi_tb_get_root_table_entry * - * PARAMETERS: table_id - Id for which the function is searching - * table_desc - Pointer to return the matching table - * descriptor. + * PARAMETERS: table_entry - Pointer to the RSDT/XSDT table entry + * table_entry_size - sizeof 32 or 64 (RSDT or XSDT) * - * RETURN: Search the tables to find one with a matching table_id and - * return a pointer to that table descriptor. + * RETURN: Physical address extracted from the root table + * + * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on + * both 32-bit and 64-bit platforms + * + * NOTE: acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on + * 64-bit platforms. * ******************************************************************************/ -acpi_status -acpi_tb_handle_to_object(u16 table_id, - struct acpi_table_desc **return_table_desc) +static acpi_physical_address +acpi_tb_get_root_table_entry(u8 * table_entry, + acpi_native_uint table_entry_size) { - u32 i; - struct acpi_table_desc *table_desc; + u64 address64; - ACPI_FUNCTION_NAME(tb_handle_to_object); + /* + * Get the table physical address (32-bit for RSDT, 64-bit for XSDT): + * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT + */ + if (table_entry_size == sizeof(u32)) { + /* + * 32-bit platform, RSDT: Return 32-bit table entry + * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return + */ + return ((acpi_physical_address) + (*ACPI_CAST_PTR(u32, table_entry))); + } else { + /* + * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return + * 64-bit platform, XSDT: Move (unaligned) 64-bit to local, return 64-bit + */ + ACPI_MOVE_64_TO_64(&address64, table_entry); - for (i = 0; i < ACPI_TABLE_MAX; i++) { - table_desc = acpi_gbl_table_lists[i].next; - while (table_desc) { - if (table_desc->table_id == table_id) { - *return_table_desc = table_desc; - return (AE_OK); +#if ACPI_MACHINE_WIDTH == 32 + if (address64 > ACPI_UINT32_MAX) { + + /* Will truncate 64-bit address to 32 bits, issue warning */ + + ACPI_WARNING((AE_INFO, + "64-bit Physical Address in XSDT is too large (%8.8X%8.8X), truncating", + ACPI_FORMAT_UINT64(address64))); + } +#endif + return ((acpi_physical_address) (address64)); + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_parse_root_table + * + * PARAMETERS: Rsdp - Pointer to the RSDP + * Flags - Flags + * + * RETURN: Status + * + * DESCRIPTION: This function is called to parse the Root System Description + * Table (RSDT or XSDT) + * + * NOTE: Tables are mapped (not copied) for efficiency. The FACS must + * be mapped and cannot be copied because it contains the actual + * memory location of the ACPI Global Lock. + * + ******************************************************************************/ + +acpi_status __init +acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags) +{ + struct acpi_table_rsdp *rsdp; + acpi_native_uint table_entry_size; + acpi_native_uint i; + u32 table_count; + struct acpi_table_header *table; + acpi_physical_address address; + u32 length; + u8 *table_entry; + acpi_status status; + + ACPI_FUNCTION_TRACE(tb_parse_root_table); + + /* + * Map the entire RSDP and extract the address of the RSDT or XSDT + */ + rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp)); + if (!rsdp) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + acpi_tb_print_table_header(rsdp_address, + ACPI_CAST_PTR(struct acpi_table_header, + rsdp)); + + /* Differentiate between RSDT and XSDT root tables */ + + if (rsdp->revision > 1 && rsdp->xsdt_physical_address) { + /* + * Root table is an XSDT (64-bit physical addresses). We must use the + * XSDT if the revision is > 1 and the XSDT pointer is present, as per + * the ACPI specification. + */ + address = (acpi_physical_address) rsdp->xsdt_physical_address; + table_entry_size = sizeof(u64); + } else { + /* Root table is an RSDT (32-bit physical addresses) */ + + address = (acpi_physical_address) rsdp->rsdt_physical_address; + table_entry_size = sizeof(u32); + } + + /* + * It is not possible to map more than one entry in some environments, + * so unmap the RSDP here before mapping other tables + */ + acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); + + /* Map the RSDT/XSDT table header to get the full table length */ + + table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); + if (!table) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + acpi_tb_print_table_header(address, table); + + /* Get the length of the full table, verify length and map entire table */ + + length = table->length; + acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); + + if (length < sizeof(struct acpi_table_header)) { + ACPI_ERROR((AE_INFO, "Invalid length 0x%X in RSDT/XSDT", + length)); + return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH); + } + + table = acpi_os_map_memory(address, length); + if (!table) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* Validate the root table checksum */ + + status = acpi_tb_verify_checksum(table, length); + if (ACPI_FAILURE(status)) { + acpi_os_unmap_memory(table, length); + return_ACPI_STATUS(status); + } + + /* Calculate the number of tables described in the root table */ + + table_count = + (u32) ((table->length - + sizeof(struct acpi_table_header)) / table_entry_size); + + /* + * First two entries in the table array are reserved for the DSDT and FACS, + * which are not actually present in the RSDT/XSDT - they come from the FADT + */ + table_entry = + ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header); + acpi_gbl_root_table_list.count = 2; + + /* + * Initialize the root table array from the RSDT/XSDT + */ + for (i = 0; i < table_count; i++) { + if (acpi_gbl_root_table_list.count >= + acpi_gbl_root_table_list.size) { + + /* There is no more room in the root table array, attempt resize */ + + status = acpi_tb_resize_root_table_list(); + if (ACPI_FAILURE(status)) { + ACPI_WARNING((AE_INFO, + "Truncating %u table entries!", + (unsigned) + (acpi_gbl_root_table_list.size - + acpi_gbl_root_table_list. + count))); + break; } + } - table_desc = table_desc->next; + /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ + + acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count]. + address = + acpi_tb_get_root_table_entry(table_entry, table_entry_size); + + table_entry += table_entry_size; + acpi_gbl_root_table_list.count++; + } + + /* + * It is not possible to map more than one entry in some environments, + * so unmap the root table here before mapping other tables + */ + acpi_os_unmap_memory(table, length); + + /* + * Complete the initialization of the root table array by examining + * the header of each table + */ + for (i = 2; i < acpi_gbl_root_table_list.count; i++) { + acpi_tb_install_table(acpi_gbl_root_table_list.tables[i]. + address, flags, NULL, i); + + /* Special case for FADT - get the DSDT and FACS */ + + if (ACPI_COMPARE_NAME + (&acpi_gbl_root_table_list.tables[i].signature, + ACPI_SIG_FADT)) { + acpi_tb_parse_fadt(i, flags); } } - ACPI_ERROR((AE_INFO, "TableId=%X does not exist", table_id)); - return (AE_BAD_PARAMETER); + return_ACPI_STATUS(AE_OK); } -#endif diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 5ba9303293ad..807978d5381a 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,80 +49,158 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbxface") +/* Local prototypes */ +static acpi_status acpi_tb_load_namespace(void); + /******************************************************************************* * - * FUNCTION: acpi_load_tables + * FUNCTION: acpi_allocate_root_table + * + * PARAMETERS: initial_table_count - Size of initial_table_array, in number of + * struct acpi_table_desc structures + * + * RETURN: Status + * + * DESCRIPTION: Allocate a root table array. Used by i_aSL compiler and + * acpi_initialize_tables. + * + ******************************************************************************/ + +acpi_status acpi_allocate_root_table(u32 initial_table_count) +{ + + acpi_gbl_root_table_list.size = initial_table_count; + acpi_gbl_root_table_list.flags = ACPI_ROOT_ALLOW_RESIZE; + + return (acpi_tb_resize_root_table_list()); +} + +/******************************************************************************* + * + * FUNCTION: acpi_initialize_tables + * + * PARAMETERS: initial_table_array - Pointer to an array of pre-allocated + * struct acpi_table_desc structures. If NULL, the + * array is dynamically allocated. + * initial_table_count - Size of initial_table_array, in number of + * struct acpi_table_desc structures + * allow_realloc - Flag to tell Table Manager if resize of + * pre-allocated array is allowed. Ignored + * if initial_table_array is NULL. + * + * RETURN: Status + * + * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT. + * + * NOTE: Allows static allocation of the initial table array in order + * to avoid the use of dynamic memory in confined environments + * such as the kernel boot sequence where it may not be available. + * + * If the host OS memory managers are initialized, use NULL for + * initial_table_array, and the table will be dynamically allocated. + * + ******************************************************************************/ + +acpi_status __init +acpi_initialize_tables(struct acpi_table_desc * initial_table_array, + u32 initial_table_count, u8 allow_resize) +{ + acpi_physical_address rsdp_address; + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_initialize_tables); + + /* + * Set up the Root Table Array + * Allocate the table array if requested + */ + if (!initial_table_array) { + status = acpi_allocate_root_table(initial_table_count); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + } else { + /* Root Table Array has been statically allocated by the host */ + + ACPI_MEMSET(initial_table_array, 0, + initial_table_count * + sizeof(struct acpi_table_desc)); + + acpi_gbl_root_table_list.tables = initial_table_array; + acpi_gbl_root_table_list.size = initial_table_count; + acpi_gbl_root_table_list.flags = ACPI_ROOT_ORIGIN_UNKNOWN; + if (allow_resize) { + acpi_gbl_root_table_list.flags |= + ACPI_ROOT_ALLOW_RESIZE; + } + } + + /* Get the address of the RSDP */ + + rsdp_address = acpi_os_get_root_pointer(); + if (!rsdp_address) { + return_ACPI_STATUS(AE_NOT_FOUND); + } + + /* + * Get the root table (RSDT or XSDT) and extract all entries to the local + * Root Table Array. This array contains the information of the RSDT/XSDT + * in a common, more useable format. + */ + status = + acpi_tb_parse_root_table(rsdp_address, ACPI_TABLE_ORIGIN_MAPPED); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_reallocate_root_table * * PARAMETERS: None * * RETURN: Status * - * DESCRIPTION: This function is called to load the ACPI tables from the - * provided RSDT + * DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the + * root list from the previously provided scratch area. Should + * be called once dynamic memory allocation is available in the + * kernel * ******************************************************************************/ -acpi_status acpi_load_tables(void) +acpi_status acpi_reallocate_root_table(void) { - struct acpi_pointer rsdp_address; - acpi_status status; + struct acpi_table_desc *tables; + acpi_size new_size; - ACPI_FUNCTION_TRACE(acpi_load_tables); + ACPI_FUNCTION_TRACE(acpi_reallocate_root_table); - /* Get the RSDP */ - - status = acpi_os_get_root_pointer(ACPI_LOGICAL_ADDRESSING, - &rsdp_address); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Could not get the RSDP")); - goto error_exit; + /* + * Only reallocate the root table if the host provided a static buffer + * for the table array in the call to acpi_initialize_tables. + */ + if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) { + return_ACPI_STATUS(AE_SUPPORT); } - /* Map and validate the RSDP */ + new_size = + (acpi_gbl_root_table_list.count + + ACPI_ROOT_TABLE_SIZE_INCREMENT) * sizeof(struct acpi_table_desc); - acpi_gbl_table_flags = rsdp_address.pointer_type; + /* Create new array and copy the old array */ - status = acpi_tb_verify_rsdp(&rsdp_address); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "During RSDP validation")); - goto error_exit; + tables = ACPI_ALLOCATE_ZEROED(new_size); + if (!tables) { + return_ACPI_STATUS(AE_NO_MEMORY); } - /* Get the RSDT via the RSDP */ + ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, new_size); - status = acpi_tb_get_table_rsdt(); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Could not load RSDT")); - goto error_exit; - } - - /* Now get the tables needed by this subsystem (FADT, DSDT, etc.) */ - - status = acpi_tb_get_required_tables(); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "Could not get all required tables (DSDT/FADT/FACS)")); - goto error_exit; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n")); - - /* Load the namespace from the tables */ - - status = acpi_ns_load_namespace(); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Could not load namespace")); - goto error_exit; - } + acpi_gbl_root_table_list.size = acpi_gbl_root_table_list.count; + acpi_gbl_root_table_list.tables = tables; + acpi_gbl_root_table_list.flags = + ACPI_ROOT_ORIGIN_ALLOCATED | ACPI_ROOT_ALLOW_RESIZE; return_ACPI_STATUS(AE_OK); - - error_exit: - ACPI_EXCEPTION((AE_INFO, status, "Could not load tables")); - return_ACPI_STATUS(status); } - -ACPI_EXPORT_SYMBOL(acpi_load_tables) - /******************************************************************************* * * FUNCTION: acpi_load_table @@ -141,342 +219,405 @@ ACPI_EXPORT_SYMBOL(acpi_load_tables) acpi_status acpi_load_table(struct acpi_table_header *table_ptr) { acpi_status status; - struct acpi_table_desc table_info; - struct acpi_pointer address; + acpi_native_uint table_index; + struct acpi_table_desc table_desc; - ACPI_FUNCTION_TRACE(acpi_load_table); + if (!table_ptr) + return AE_BAD_PARAMETER; - if (!table_ptr) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } + ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc)); + table_desc.pointer = table_ptr; + table_desc.length = table_ptr->length; + table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN; - /* Copy the table to a local buffer */ - - address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING; - address.pointer.logical = table_ptr; - - status = acpi_tb_get_table_body(&address, table_ptr, &table_info); + /* + * Install the new table into the local data structures + */ + status = acpi_tb_add_table(&table_desc, &table_index); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + return status; } - - /* Check signature for a valid table type */ - - status = acpi_tb_recognize_table(&table_info, ACPI_TABLE_ALL); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Install the new table into the local data structures */ - - status = acpi_tb_install_table(&table_info); - if (ACPI_FAILURE(status)) { - if (status == AE_ALREADY_EXISTS) { - - /* Table already exists, no error */ - - status = AE_OK; - } - - /* Free table allocated by acpi_tb_get_table_body */ - - acpi_tb_delete_single_table(&table_info); - return_ACPI_STATUS(status); - } - - /* Convert the table to common format if necessary */ - - switch (table_info.type) { - case ACPI_TABLE_ID_FADT: - - status = acpi_tb_convert_table_fadt(); - break; - - case ACPI_TABLE_ID_FACS: - - status = acpi_tb_build_common_facs(&table_info); - break; - - default: - /* Load table into namespace if it contains executable AML */ - - status = - acpi_ns_load_table(table_info.installed_desc, - acpi_gbl_root_node); - break; - } - - if (ACPI_FAILURE(status)) { - - /* Uninstall table and free the buffer */ - - (void)acpi_tb_uninstall_table(table_info.installed_desc); - } - - return_ACPI_STATUS(status); + status = acpi_ns_load_table(table_index, acpi_gbl_root_node); + return status; } ACPI_EXPORT_SYMBOL(acpi_load_table) -/******************************************************************************* +/****************************************************************************** + * + * FUNCTION: acpi_get_table_header + * + * PARAMETERS: Signature - ACPI signature of needed table + * Instance - Which instance (for SSDTs) + * out_table_header - The pointer to the table header to fill + * + * RETURN: Status and pointer to mapped table header + * + * DESCRIPTION: Finds an ACPI table header. + * + * NOTE: Caller is responsible in unmapping the header with + * acpi_os_unmap_memory + * + *****************************************************************************/ +acpi_status +acpi_get_table_header(char *signature, + acpi_native_uint instance, + struct acpi_table_header *out_table_header) +{ + acpi_native_uint i; + acpi_native_uint j; + struct acpi_table_header *header; + + /* Parameter validation */ + + if (!signature || !out_table_header) { + return (AE_BAD_PARAMETER); + } + + /* + * Walk the root table list + */ + for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) { + if (!ACPI_COMPARE_NAME + (&(acpi_gbl_root_table_list.tables[i].signature), + signature)) { + continue; + } + + if (++j < instance) { + continue; + } + + if (!acpi_gbl_root_table_list.tables[i].pointer) { + if ((acpi_gbl_root_table_list.tables[i]. + flags & ACPI_TABLE_ORIGIN_MASK) == + ACPI_TABLE_ORIGIN_MAPPED) { + header = + acpi_os_map_memory(acpi_gbl_root_table_list. + tables[i].address, + sizeof(struct + acpi_table_header)); + if (!header) { + return AE_NO_MEMORY; + } + ACPI_MEMCPY(out_table_header, header, + sizeof(struct acpi_table_header)); + acpi_os_unmap_memory(header, + sizeof(struct + acpi_table_header)); + } else { + return AE_NOT_FOUND; + } + } else { + ACPI_MEMCPY(out_table_header, + acpi_gbl_root_table_list.tables[i].pointer, + sizeof(struct acpi_table_header)); + } + return (AE_OK); + } + + return (AE_NOT_FOUND); +} + +ACPI_EXPORT_SYMBOL(acpi_get_table_header) + + +/****************************************************************************** * * FUNCTION: acpi_unload_table_id * - * PARAMETERS: table_type - Type of table to be unloaded - * id - Owner ID of the table to be removed. + * PARAMETERS: id - Owner ID of the table to be removed. * * RETURN: Status * * DESCRIPTION: This routine is used to force the unload of a table (by id) * ******************************************************************************/ -acpi_status acpi_unload_table_id(acpi_table_type table_type, acpi_owner_id id) +acpi_status acpi_unload_table_id(acpi_owner_id id) { - struct acpi_table_desc *table_desc; - acpi_status status; + int i; + acpi_status status = AE_NOT_EXIST; ACPI_FUNCTION_TRACE(acpi_unload_table); - /* Parameter validation */ - if (table_type > ACPI_TABLE_ID_MAX) - return_ACPI_STATUS(AE_BAD_PARAMETER); - /* Find table from the requested type list */ - table_desc = acpi_gbl_table_lists[table_type].next; - while (table_desc && table_desc->owner_id != id) - table_desc = table_desc->next; - - if (!table_desc) - return_ACPI_STATUS(AE_NOT_EXIST); - - /* - * Delete all namespace objects owned by this table. Note that these - * objects can appear anywhere in the namespace by virtue of the AML - * "Scope" operator. Thus, we need to track ownership by an ID, not - * simply a position within the hierarchy - */ - acpi_ns_delete_namespace_by_owner(table_desc->owner_id); - - status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - if (ACPI_FAILURE(status)) - return_ACPI_STATUS(status); - - (void)acpi_tb_uninstall_table(table_desc); - - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - - return_ACPI_STATUS(AE_OK); -} - -ACPI_EXPORT_SYMBOL(acpi_unload_table_id) - -#ifdef ACPI_FUTURE_USAGE -/******************************************************************************* - * - * FUNCTION: acpi_unload_table - * - * PARAMETERS: table_type - Type of table to be unloaded - * - * RETURN: Status - * - * DESCRIPTION: This routine is used to force the unload of a table - * - ******************************************************************************/ -acpi_status acpi_unload_table(acpi_table_type table_type) -{ - struct acpi_table_desc *table_desc; - - ACPI_FUNCTION_TRACE(acpi_unload_table); - - /* Parameter validation */ - - if (table_type > ACPI_TABLE_ID_MAX) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Find all tables of the requested type */ - - table_desc = acpi_gbl_table_lists[table_type].next; - if (!table_desc) { - return_ACPI_STATUS(AE_NOT_EXIST); - } - - while (table_desc) { + for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { + if (id != acpi_gbl_root_table_list.tables[i].owner_id) { + continue; + } /* - * Delete all namespace objects owned by this table. Note that these - * objects can appear anywhere in the namespace by virtue of the AML - * "Scope" operator. Thus, we need to track ownership by an ID, not - * simply a position within the hierarchy - */ - acpi_ns_delete_namespace_by_owner(table_desc->owner_id); - table_desc = table_desc->next; + * Delete all namespace objects owned by this table. Note that these + * objects can appear anywhere in the namespace by virtue of the AML + * "Scope" operator. Thus, we need to track ownership by an ID, not + * simply a position within the hierarchy + */ + acpi_tb_delete_namespace_by_owner(i); + acpi_tb_release_owner_id(i); + acpi_tb_set_table_loaded_flag(i, FALSE); } - - /* Delete (or unmap) all tables of this type */ - - acpi_tb_delete_tables_by_type(table_type); - return_ACPI_STATUS(AE_OK); -} - -ACPI_EXPORT_SYMBOL(acpi_unload_table) - -/******************************************************************************* - * - * FUNCTION: acpi_get_table_header - * - * PARAMETERS: table_type - one of the defined table types - * Instance - the non zero instance of the table, allows - * support for multiple tables of the same type - * see acpi_gbl_acpi_table_flag - * out_table_header - pointer to the struct acpi_table_header if successful - * - * DESCRIPTION: This function is called to get an ACPI table header. The caller - * supplies an pointer to a data area sufficient to contain an ACPI - * struct acpi_table_header structure. - * - * The header contains a length field that can be used to determine - * the size of the buffer needed to contain the entire table. This - * function is not valid for the RSD PTR table since it does not - * have a standard header and is fixed length. - * - ******************************************************************************/ -acpi_status -acpi_get_table_header(acpi_table_type table_type, - u32 instance, struct acpi_table_header *out_table_header) -{ - struct acpi_table_header *tbl_ptr; - acpi_status status; - - ACPI_FUNCTION_TRACE(acpi_get_table_header); - - if ((instance == 0) || - (table_type == ACPI_TABLE_ID_RSDP) || (!out_table_header)) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Check the table type and instance */ - - if ((table_type > ACPI_TABLE_ID_MAX) || - (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) && - instance > 1)) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Get a pointer to the entire table */ - - status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* The function will return a NULL pointer if the table is not loaded */ - - if (tbl_ptr == NULL) { - return_ACPI_STATUS(AE_NOT_EXIST); - } - - /* Copy the header to the caller's buffer */ - - ACPI_MEMCPY(ACPI_CAST_PTR(void, out_table_header), - ACPI_CAST_PTR(void, tbl_ptr), - sizeof(struct acpi_table_header)); - return_ACPI_STATUS(status); } -ACPI_EXPORT_SYMBOL(acpi_get_table_header) -#endif /* ACPI_FUTURE_USAGE */ +ACPI_EXPORT_SYMBOL(acpi_unload_table_id) /******************************************************************************* * * FUNCTION: acpi_get_table * - * PARAMETERS: table_type - one of the defined table types - * Instance - the non zero instance of the table, allows - * support for multiple tables of the same type - * see acpi_gbl_acpi_table_flag - * ret_buffer - pointer to a structure containing a buffer to - * receive the table + * PARAMETERS: Signature - ACPI signature of needed table + * Instance - Which instance (for SSDTs) + * out_table - Where the pointer to the table is returned * - * RETURN: Status + * RETURN: Status and pointer to table * - * DESCRIPTION: This function is called to get an ACPI table. The caller - * supplies an out_buffer large enough to contain the entire ACPI - * table. The caller should call the acpi_get_table_header function - * first to determine the buffer size needed. Upon completion - * the out_buffer->Length field will indicate the number of bytes - * copied into the out_buffer->buf_ptr buffer. This table will be - * a complete table including the header. + * DESCRIPTION: Finds and verifies an ACPI table. * - ******************************************************************************/ + *****************************************************************************/ acpi_status -acpi_get_table(acpi_table_type table_type, - u32 instance, struct acpi_buffer *ret_buffer) +acpi_get_table(char *signature, + acpi_native_uint instance, struct acpi_table_header ** out_table) { - struct acpi_table_header *tbl_ptr; + acpi_native_uint i; + acpi_native_uint j; acpi_status status; - acpi_size table_length; - - ACPI_FUNCTION_TRACE(acpi_get_table); /* Parameter validation */ - if (instance == 0) { + if (!signature || !out_table) { + return (AE_BAD_PARAMETER); + } + + /* + * Walk the root table list + */ + for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) { + if (!ACPI_COMPARE_NAME + (&(acpi_gbl_root_table_list.tables[i].signature), + signature)) { + continue; + } + + if (++j < instance) { + continue; + } + + status = + acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]); + if (ACPI_SUCCESS(status)) { + *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); + } + + return (AE_NOT_FOUND); +} + +ACPI_EXPORT_SYMBOL(acpi_get_table) + +/******************************************************************************* + * + * FUNCTION: acpi_get_table_by_index + * + * PARAMETERS: table_index - Table index + * Table - Where the pointer to the table is returned + * + * RETURN: Status and pointer to the table + * + * DESCRIPTION: Obtain a table by an index into the global table list. + * + ******************************************************************************/ +acpi_status +acpi_get_table_by_index(acpi_native_uint table_index, + struct acpi_table_header ** table) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_get_table_by_index); + + /* Parameter validation */ + + if (!table) { return_ACPI_STATUS(AE_BAD_PARAMETER); } - status = acpi_ut_validate_buffer(ret_buffer); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + + /* Validate index */ + + if (table_index >= acpi_gbl_root_table_list.count) { + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + if (!acpi_gbl_root_table_list.tables[table_index].pointer) { + + /* Table is not mapped, map it */ + + status = + acpi_tb_verify_table(&acpi_gbl_root_table_list. + tables[table_index]); + if (ACPI_FAILURE(status)) { + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); + } + } + + *table = acpi_gbl_root_table_list.tables[table_index].pointer; + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(AE_OK); +} + +ACPI_EXPORT_SYMBOL(acpi_get_table_by_index) + +/******************************************************************************* + * + * FUNCTION: acpi_tb_load_namespace + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in + * the RSDT/XSDT. + * + ******************************************************************************/ +static acpi_status acpi_tb_load_namespace(void) +{ + acpi_status status; + struct acpi_table_header *table; + acpi_native_uint i; + + ACPI_FUNCTION_TRACE(tb_load_namespace); + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + + /* + * Load the namespace. The DSDT is required, but any SSDT and PSDT tables + * are optional. + */ + if (!acpi_gbl_root_table_list.count || + !ACPI_COMPARE_NAME(& + (acpi_gbl_root_table_list. + tables[ACPI_TABLE_INDEX_DSDT].signature), + ACPI_SIG_DSDT) + || + ACPI_FAILURE(acpi_tb_verify_table + (&acpi_gbl_root_table_list. + tables[ACPI_TABLE_INDEX_DSDT]))) { + status = AE_NO_ACPI_TABLES; + goto unlock_and_exit; + } + + /* + * Find DSDT table + */ + status = + acpi_os_table_override(acpi_gbl_root_table_list. + tables[ACPI_TABLE_INDEX_DSDT].pointer, + &table); + if (ACPI_SUCCESS(status) && table) { + /* + * DSDT table has been found + */ + acpi_tb_delete_table(&acpi_gbl_root_table_list. + tables[ACPI_TABLE_INDEX_DSDT]); + acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer = + table; + acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].length = + table->length; + acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].flags = + ACPI_TABLE_ORIGIN_UNKNOWN; + + ACPI_INFO((AE_INFO, "Table DSDT replaced by host OS")); + acpi_tb_print_table_header(0, table); + } + + status = + acpi_tb_verify_table(&acpi_gbl_root_table_list. + tables[ACPI_TABLE_INDEX_DSDT]); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + + /* A valid DSDT is required */ + + status = AE_NO_ACPI_TABLES; + goto unlock_and_exit; } - /* Check the table type and instance */ + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - if ((table_type > ACPI_TABLE_ID_MAX) || - (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) && - instance > 1)) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Get a pointer to the entire table */ - - status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr); + /* + * Load and parse tables. + */ + status = acpi_ns_load_table(ACPI_TABLE_INDEX_DSDT, acpi_gbl_root_node); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* - * acpi_tb_get_table_ptr will return a NULL pointer if the - * table is not loaded. + * Load any SSDT or PSDT tables. Note: Loop leaves tables locked */ - if (tbl_ptr == NULL) { - return_ACPI_STATUS(AE_NOT_EXIST); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { + if ((!ACPI_COMPARE_NAME + (&(acpi_gbl_root_table_list.tables[i].signature), + ACPI_SIG_SSDT) + && + !ACPI_COMPARE_NAME(& + (acpi_gbl_root_table_list.tables[i]. + signature), ACPI_SIG_PSDT)) + || + ACPI_FAILURE(acpi_tb_verify_table + (&acpi_gbl_root_table_list.tables[i]))) { + continue; + } + + /* Ignore errors while loading tables, get as many as possible */ + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + (void)acpi_ns_load_table(i, acpi_gbl_root_node); + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); } - /* Get the table length */ + ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n")); - if (table_type == ACPI_TABLE_ID_RSDP) { - - /* RSD PTR is the only "table" without a header */ - - table_length = sizeof(struct rsdp_descriptor); - } else { - table_length = (acpi_size) tbl_ptr->length; - } - - /* Validate/Allocate/Clear caller buffer */ - - status = acpi_ut_initialize_buffer(ret_buffer, table_length); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Copy the table to the buffer */ - - ACPI_MEMCPY(ACPI_CAST_PTR(void, ret_buffer->pointer), - ACPI_CAST_PTR(void, tbl_ptr), table_length); - - return_ACPI_STATUS(AE_OK); + unlock_and_exit: + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_ACPI_STATUS(status); } -ACPI_EXPORT_SYMBOL(acpi_get_table) +/******************************************************************************* + * + * FUNCTION: acpi_load_tables + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT + * + ******************************************************************************/ + +acpi_status acpi_load_tables(void) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_load_tables); + + /* + * Load the namespace from the tables + */ + status = acpi_tb_load_namespace(); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "While loading namespace from ACPI tables")); + } + + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_load_tables) diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c index da2648bbdbc0..cf8fa514189f 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/tables/tbxfroot.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,16 +48,15 @@ ACPI_MODULE_NAME("tbxfroot") /* Local prototypes */ -static acpi_status -acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags); - static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length); +static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp); + /******************************************************************************* * * FUNCTION: acpi_tb_validate_rsdp * - * PARAMETERS: Rsdp - Pointer to unvalidated RSDP + * PARAMETERS: Rsdp - Pointer to unvalidated RSDP * * RETURN: Status * @@ -65,14 +64,18 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length); * ******************************************************************************/ -acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp) +static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp) { ACPI_FUNCTION_ENTRY(); /* - * The signature and checksum must both be correct + * The signature and checksum must both be correct + * + * Note: Sometimes there exists more than one RSDP in memory; the valid + * RSDP has a valid checksum, all others have an invalid checksum. */ - if (ACPI_STRNCMP((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) { + if (ACPI_STRNCMP((char *)rsdp, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1) + != 0) { /* Nope, BAD Signature */ @@ -81,14 +84,14 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp) /* Check the standard checksum */ - if (acpi_tb_sum_table(rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) { + if (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) { return (AE_BAD_CHECKSUM); } /* Check extended checksum if table version >= 2 */ if ((rsdp->revision >= 2) && - (acpi_tb_sum_table(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) { + (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) { return (AE_BAD_CHECKSUM); } @@ -97,314 +100,123 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp) /******************************************************************************* * - * FUNCTION: acpi_tb_find_table + * FUNCTION: acpi_tb_find_rsdp * - * PARAMETERS: Signature - String with ACPI table signature - * oem_id - String with the table OEM ID - * oem_table_id - String with the OEM Table ID - * table_ptr - Where the table pointer is returned + * PARAMETERS: table_address - Where the table pointer is returned * - * RETURN: Status + * RETURN: Status, RSDP physical address * - * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the - * Signature, OEM ID and OEM Table ID. + * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor + * pointer structure. If it is found, set *RSDP to point to it. + * + * NOTE1: The RSDP must be either in the first 1_k of the Extended + * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.) + * Only a 32-bit physical address is necessary. + * + * NOTE2: This function is always available, regardless of the + * initialization state of the rest of ACPI. * ******************************************************************************/ -acpi_status -acpi_tb_find_table(char *signature, - char *oem_id, - char *oem_table_id, struct acpi_table_header ** table_ptr) +acpi_status acpi_find_root_pointer(acpi_native_uint * table_address) { - acpi_status status; - struct acpi_table_header *table; - - ACPI_FUNCTION_TRACE(tb_find_table); - - /* Validate string lengths */ - - if ((ACPI_STRLEN(signature) > ACPI_NAME_SIZE) || - (ACPI_STRLEN(oem_id) > sizeof(table->oem_id)) || - (ACPI_STRLEN(oem_table_id) > sizeof(table->oem_table_id))) { - return_ACPI_STATUS(AE_AML_STRING_LIMIT); - } - - if (ACPI_COMPARE_NAME(signature, DSDT_SIG)) { - /* - * The DSDT pointer is contained in the FADT, not the RSDT. - * This code should suffice, because the only code that would perform - * a "find" on the DSDT is the data_table_region() AML opcode -- in - * which case, the DSDT is guaranteed to be already loaded. - * If this becomes insufficient, the FADT will have to be found first. - */ - if (!acpi_gbl_DSDT) { - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - table = acpi_gbl_DSDT; - } else { - /* Find the table */ - - status = acpi_get_firmware_table(signature, 1, - ACPI_LOGICAL_ADDRESSING, - &table); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } - - /* Check oem_id and oem_table_id */ - - if ((oem_id[0] && - ACPI_STRNCMP(oem_id, table->oem_id, - sizeof(table->oem_id))) || - (oem_table_id[0] && - ACPI_STRNCMP(oem_table_id, table->oem_table_id, - sizeof(table->oem_table_id)))) { - return_ACPI_STATUS(AE_AML_NAME_NOT_FOUND); - } - - ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Found table [%4.4s]\n", - table->signature)); - - *table_ptr = table; - return_ACPI_STATUS(AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_get_firmware_table - * - * PARAMETERS: Signature - Any ACPI table signature - * Instance - the non zero instance of the table, allows - * support for multiple tables of the same type - * Flags - Physical/Virtual support - * table_pointer - Where a buffer containing the table is - * returned - * - * RETURN: Status - * - * DESCRIPTION: This function is called to get an ACPI table. A buffer is - * allocated for the table and returned in table_pointer. - * This table will be a complete table including the header. - * - ******************************************************************************/ - -acpi_status -acpi_get_firmware_table(acpi_string signature, - u32 instance, - u32 flags, struct acpi_table_header **table_pointer) -{ - acpi_status status; - struct acpi_pointer address; - struct acpi_table_header *header = NULL; - struct acpi_table_desc *table_info = NULL; - struct acpi_table_desc *rsdt_info; - u32 table_count; - u32 i; - u32 j; - - ACPI_FUNCTION_TRACE(acpi_get_firmware_table); - - /* - * Ensure that at least the table manager is initialized. We don't - * require that the entire ACPI subsystem is up for this interface. - * If we have a buffer, we must have a length too - */ - if ((instance == 0) || (!signature) || (!table_pointer)) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - /* Ensure that we have a RSDP */ - - if (!acpi_gbl_RSDP) { - - /* Get the RSDP */ - - status = acpi_os_get_root_pointer(flags, &address); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "RSDP not found\n")); - return_ACPI_STATUS(AE_NO_ACPI_TABLES); - } - - /* Map and validate the RSDP */ - - if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { - status = acpi_os_map_memory(address.pointer.physical, - sizeof(struct - rsdp_descriptor), - (void *)&acpi_gbl_RSDP); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } else { - acpi_gbl_RSDP = address.pointer.logical; - } - - /* The RDSP signature and checksum must both be correct */ - - status = acpi_tb_validate_rsdp(acpi_gbl_RSDP); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } - - /* Get the RSDT address via the RSDP */ - - acpi_tb_get_rsdt_address(&address); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "RSDP located at %p, RSDT physical=%8.8X%8.8X\n", - acpi_gbl_RSDP, - ACPI_FORMAT_UINT64(address.pointer.value))); - - /* Insert processor_mode flags */ - - address.pointer_type |= flags; - - /* Get and validate the RSDT */ - - rsdt_info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc)); - if (!rsdt_info) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - status = acpi_tb_get_table(&address, rsdt_info); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - status = acpi_tb_validate_rsdt(rsdt_info->pointer); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - /* Allocate a scratch table header and table descriptor */ - - header = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); - if (!header) { - status = AE_NO_MEMORY; - goto cleanup; - } - - table_info = ACPI_ALLOCATE(sizeof(struct acpi_table_desc)); - if (!table_info) { - status = AE_NO_MEMORY; - goto cleanup; - } - - /* Get the number of table pointers within the RSDT */ - - table_count = - acpi_tb_get_table_count(acpi_gbl_RSDP, rsdt_info->pointer); - address.pointer_type = acpi_gbl_table_flags | flags; - - /* - * Search the RSDT/XSDT for the correct instance of the - * requested table - */ - for (i = 0, j = 0; i < table_count; i++) { - /* - * Get the next table pointer, handle RSDT vs. XSDT - * RSDT pointers are 32 bits, XSDT pointers are 64 bits - */ - if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { - address.pointer.value = - (ACPI_CAST_PTR - (struct rsdt_descriptor, - rsdt_info->pointer))->table_offset_entry[i]; - } else { - address.pointer.value = - (ACPI_CAST_PTR - (struct xsdt_descriptor, - rsdt_info->pointer))->table_offset_entry[i]; - } - - /* Get the table header */ - - status = acpi_tb_get_table_header(&address, header); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - /* Compare table signatures and table instance */ - - if (ACPI_COMPARE_NAME(header->signature, signature)) { - - /* An instance of the table was found */ - - j++; - if (j >= instance) { - - /* Found the correct instance, get the entire table */ - - status = - acpi_tb_get_table_body(&address, header, - table_info); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - *table_pointer = table_info->pointer; - goto cleanup; - } - } - } - - /* Did not find the table */ - - status = AE_NOT_EXIST; - - cleanup: - if (rsdt_info->pointer) { - acpi_os_unmap_memory(rsdt_info->pointer, - (acpi_size) rsdt_info->pointer->length); - } - ACPI_FREE(rsdt_info); - - if (header) { - ACPI_FREE(header); - } - if (table_info) { - ACPI_FREE(table_info); - } - return_ACPI_STATUS(status); -} - -ACPI_EXPORT_SYMBOL(acpi_get_firmware_table) - -/* TBD: Move to a new file */ -#if ACPI_MACHINE_WIDTH != 16 -/******************************************************************************* - * - * FUNCTION: acpi_find_root_pointer - * - * PARAMETERS: Flags - Logical/Physical addressing - * rsdp_address - Where to place the RSDP address - * - * RETURN: Status, Physical address of the RSDP - * - * DESCRIPTION: Find the RSDP - * - ******************************************************************************/ -acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address) -{ - struct acpi_table_desc table_info; - acpi_status status; + u8 *table_ptr; + u8 *mem_rover; + u32 physical_address; ACPI_FUNCTION_TRACE(acpi_find_root_pointer); - /* Get the RSDP */ + /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */ - status = acpi_tb_find_rsdp(&table_info, flags); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "RSDP structure not found - Flags=%X", flags)); + table_ptr = acpi_os_map_memory((acpi_physical_address) + ACPI_EBDA_PTR_LOCATION, + ACPI_EBDA_PTR_LENGTH); + if (!table_ptr) { + ACPI_ERROR((AE_INFO, + "Could not map memory at %8.8X for length %X", + ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH)); - return_ACPI_STATUS(AE_NO_ACPI_TABLES); + return_ACPI_STATUS(AE_NO_MEMORY); } - rsdp_address->pointer_type = ACPI_PHYSICAL_POINTER; - rsdp_address->pointer.physical = table_info.physical_address; - return_ACPI_STATUS(AE_OK); + ACPI_MOVE_16_TO_32(&physical_address, table_ptr); + + /* Convert segment part to physical address */ + + physical_address <<= 4; + acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH); + + /* EBDA present? */ + + if (physical_address > 0x400) { + /* + * 1b) Search EBDA paragraphs (EBDA is required to be a + * minimum of 1_k length) + */ + table_ptr = acpi_os_map_memory((acpi_native_uint) + physical_address, + ACPI_EBDA_WINDOW_SIZE); + if (!table_ptr) { + ACPI_ERROR((AE_INFO, + "Could not map memory at %8.8X for length %X", + physical_address, ACPI_EBDA_WINDOW_SIZE)); + + return_ACPI_STATUS(AE_NO_MEMORY); + } + + mem_rover = + acpi_tb_scan_memory_for_rsdp(table_ptr, + ACPI_EBDA_WINDOW_SIZE); + acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE); + + if (mem_rover) { + + /* Return the physical address */ + + physical_address += + (u32) ACPI_PTR_DIFF(mem_rover, table_ptr); + + *table_address = physical_address; + return_ACPI_STATUS(AE_OK); + } + } + + /* + * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh + */ + table_ptr = acpi_os_map_memory((acpi_physical_address) + ACPI_HI_RSDP_WINDOW_BASE, + ACPI_HI_RSDP_WINDOW_SIZE); + + if (!table_ptr) { + ACPI_ERROR((AE_INFO, + "Could not map memory at %8.8X for length %X", + ACPI_HI_RSDP_WINDOW_BASE, + ACPI_HI_RSDP_WINDOW_SIZE)); + + return_ACPI_STATUS(AE_NO_MEMORY); + } + + mem_rover = + acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); + acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); + + if (mem_rover) { + + /* Return the physical address */ + + physical_address = (u32) + (ACPI_HI_RSDP_WINDOW_BASE + + ACPI_PTR_DIFF(mem_rover, table_ptr)); + + *table_address = physical_address; + return_ACPI_STATUS(AE_OK); + } + + /* A valid RSDP was not found */ + + ACPI_ERROR((AE_INFO, "A valid RSDP was not found")); + return_ACPI_STATUS(AE_NOT_FOUND); } ACPI_EXPORT_SYMBOL(acpi_find_root_pointer) @@ -440,7 +252,7 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length) status = acpi_tb_validate_rsdp(ACPI_CAST_PTR - (struct rsdp_descriptor, mem_rover)); + (struct acpi_table_rsdp, mem_rover)); if (ACPI_SUCCESS(status)) { /* Sig and checksum valid, we have found a real RSDP */ @@ -461,189 +273,3 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length) start_address)); return_PTR(NULL); } - -/******************************************************************************* - * - * FUNCTION: acpi_tb_find_rsdp - * - * PARAMETERS: table_info - Where the table info is returned - * Flags - Current memory mode (logical vs. - * physical addressing) - * - * RETURN: Status, RSDP physical address - * - * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor - * pointer structure. If it is found, set *RSDP to point to it. - * - * NOTE1: The RSDP must be either in the first 1_k of the Extended - * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.) - * Only a 32-bit physical address is necessary. - * - * NOTE2: This function is always available, regardless of the - * initialization state of the rest of ACPI. - * - ******************************************************************************/ - -static acpi_status -acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags) -{ - u8 *table_ptr; - u8 *mem_rover; - u32 physical_address; - acpi_status status; - - ACPI_FUNCTION_TRACE(tb_find_rsdp); - - /* - * Scan supports either logical addressing or physical addressing - */ - if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { - - /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */ - - status = acpi_os_map_memory((acpi_physical_address) - ACPI_EBDA_PTR_LOCATION, - ACPI_EBDA_PTR_LENGTH, - (void *)&table_ptr); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not map memory at %8.8X for length %X", - ACPI_EBDA_PTR_LOCATION, - ACPI_EBDA_PTR_LENGTH)); - - return_ACPI_STATUS(status); - } - - ACPI_MOVE_16_TO_32(&physical_address, table_ptr); - - /* Convert segment part to physical address */ - - physical_address <<= 4; - acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH); - - /* EBDA present? */ - - if (physical_address > 0x400) { - /* - * 1b) Search EBDA paragraphs (EBDA is required to be a - * minimum of 1_k length) - */ - status = acpi_os_map_memory((acpi_physical_address) - physical_address, - ACPI_EBDA_WINDOW_SIZE, - (void *)&table_ptr); - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not map memory at %8.8X for length %X", - physical_address, - ACPI_EBDA_WINDOW_SIZE)); - - return_ACPI_STATUS(status); - } - - mem_rover = acpi_tb_scan_memory_for_rsdp(table_ptr, - ACPI_EBDA_WINDOW_SIZE); - acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE); - - if (mem_rover) { - - /* Return the physical address */ - - physical_address += - (u32) ACPI_PTR_DIFF(mem_rover, table_ptr); - - table_info->physical_address = - (acpi_physical_address) physical_address; - return_ACPI_STATUS(AE_OK); - } - } - - /* - * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh - */ - status = acpi_os_map_memory((acpi_physical_address) - ACPI_HI_RSDP_WINDOW_BASE, - ACPI_HI_RSDP_WINDOW_SIZE, - (void *)&table_ptr); - - if (ACPI_FAILURE(status)) { - ACPI_ERROR((AE_INFO, - "Could not map memory at %8.8X for length %X", - ACPI_HI_RSDP_WINDOW_BASE, - ACPI_HI_RSDP_WINDOW_SIZE)); - - return_ACPI_STATUS(status); - } - - mem_rover = - acpi_tb_scan_memory_for_rsdp(table_ptr, - ACPI_HI_RSDP_WINDOW_SIZE); - acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); - - if (mem_rover) { - - /* Return the physical address */ - - physical_address = (u32) - (ACPI_HI_RSDP_WINDOW_BASE + - ACPI_PTR_DIFF(mem_rover, table_ptr)); - - table_info->physical_address = - (acpi_physical_address) physical_address; - return_ACPI_STATUS(AE_OK); - } - } - - /* - * Physical addressing - */ - else { - /* 1a) Get the location of the EBDA */ - - ACPI_MOVE_16_TO_32(&physical_address, ACPI_EBDA_PTR_LOCATION); - physical_address <<= 4; /* Convert segment to physical address */ - - /* EBDA present? */ - - if (physical_address > 0x400) { - /* - * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of - * 1_k length) - */ - mem_rover = - acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR - (physical_address), - ACPI_EBDA_WINDOW_SIZE); - if (mem_rover) { - - /* Return the physical address */ - - table_info->physical_address = - ACPI_TO_INTEGER(mem_rover); - return_ACPI_STATUS(AE_OK); - } - } - - /* 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ - - mem_rover = - acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR - (ACPI_HI_RSDP_WINDOW_BASE), - ACPI_HI_RSDP_WINDOW_SIZE); - if (mem_rover) { - - /* Found it, return the physical address */ - - table_info->physical_address = - ACPI_TO_INTEGER(mem_rover); - return_ACPI_STATUS(AE_OK); - } - } - - /* A valid RSDP was not found */ - - ACPI_ERROR((AE_INFO, "No valid RSDP was found")); - return_ACPI_STATUS(AE_NOT_FOUND); -} - -#endif diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 40ddb4dd9631..f76d3168c2b2 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -82,7 +82,7 @@ MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n"); static int acpi_thermal_add(struct acpi_device *device); static int acpi_thermal_remove(struct acpi_device *device, int type); -static int acpi_thermal_resume(struct acpi_device *device, int state); +static int acpi_thermal_resume(struct acpi_device *device); static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file); static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file); static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file); @@ -1353,7 +1353,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type) return 0; } -static int acpi_thermal_resume(struct acpi_device *device, int state) +static int acpi_thermal_resume(struct acpi_device *device) { struct acpi_thermal *tz = NULL; int i; diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index f6cbc0b1bfd0..55a764807499 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,6 +42,7 @@ */ #include +#include #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utalloc") @@ -142,6 +143,14 @@ acpi_status acpi_ut_create_caches(void) acpi_status acpi_ut_delete_caches(void) { +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + char buffer[7]; + + if (acpi_gbl_display_final_mem_stats) { + ACPI_STRCPY(buffer, "MEMORY"); + acpi_db_display_statistics(buffer); + } +#endif (void)acpi_os_delete_cache(acpi_gbl_namespace_cache); acpi_gbl_namespace_cache = NULL; diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c index 1a1f8109159c..870f6edeb5f2 100644 --- a/drivers/acpi/utilities/utcache.c +++ b/drivers/acpi/utilities/utcache.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -289,6 +289,14 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache) ACPI_MEM_TRACKING(cache->total_allocated++); +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + if ((cache->total_allocated - cache->total_freed) > + cache->max_occupied) { + cache->max_occupied = + cache->total_allocated - cache->total_freed; + } +#endif + /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ status = acpi_ut_release_mutex(ACPI_MTX_CACHES); diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c index 5e1a80d1bc36..84d529db0a66 100644 --- a/drivers/acpi/utilities/utcopy.c +++ b/drivers/acpi/utilities/utcopy.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -719,6 +719,15 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, acpi_ut_add_reference(source_desc->reference.object); break; + case ACPI_TYPE_REGION: + /* + * We copied the Region Handler, so we now must add a reference + */ + if (dest_desc->region.handler) { + acpi_ut_add_reference(dest_desc->region.handler); + } + break; + default: /* Nothing to do for other simple objects */ break; diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c index 9e9054e155c1..61ad4f2daee2 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/utilities/utdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -181,8 +181,7 @@ acpi_ut_debug_print(u32 requested_debug_level, if (ACPI_LV_THREADS & acpi_dbg_level) { acpi_os_printf ("\n**** Context Switch from TID %lX to TID %lX ****\n\n", - (unsigned long) acpi_gbl_prev_thread_id, - (unsigned long) thread_id); + (unsigned long)acpi_gbl_prev_thread_id, (unsigned long)thread_id); } acpi_gbl_prev_thread_id = thread_id; @@ -195,7 +194,7 @@ acpi_ut_debug_print(u32 requested_debug_level, acpi_os_printf("%8s-%04ld ", module_name, line_number); if (ACPI_LV_THREADS & acpi_dbg_level) { - acpi_os_printf("[%04lX] ", thread_id); + acpi_os_printf("[%04lX] ", (unsigned long)thread_id); } acpi_os_printf("[%02ld] %-22.22s: ", diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index 9d3f1149ba21..f777cebdc46d 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -158,16 +158,20 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) "***** Mutex %p, OS Mutex %p\n", object, object->mutex.os_mutex)); - if (object->mutex.os_mutex != ACPI_GLOBAL_LOCK) { - acpi_ex_unlink_mutex(object); - acpi_os_delete_mutex(object->mutex.os_mutex); - } else { - /* Global Lock "mutex" is actually a counting semaphore */ + if (object->mutex.os_mutex == acpi_gbl_global_lock_mutex) { + + /* Global Lock has extra semaphore */ (void) acpi_os_delete_semaphore (acpi_gbl_global_lock_semaphore); acpi_gbl_global_lock_semaphore = NULL; + + acpi_os_delete_mutex(object->mutex.os_mutex); + acpi_gbl_global_lock_mutex = NULL; + } else { + acpi_ex_unlink_mutex(object); + acpi_os_delete_mutex(object->mutex.os_mutex); } break; diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c index d6d7121583c0..13d5879cd98b 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c index 014030af8b50..af33358a964b 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/utilities/utglobal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,89 +46,9 @@ #include #include +ACPI_EXPORT_SYMBOL(acpi_gbl_FADT) #define _COMPONENT ACPI_UTILITIES -ACPI_MODULE_NAME("utglobal") - -/******************************************************************************* - * - * FUNCTION: acpi_format_exception - * - * PARAMETERS: Status - The acpi_status code to be formatted - * - * RETURN: A string containing the exception text. A valid pointer is - * always returned. - * - * DESCRIPTION: This function translates an ACPI exception into an ASCII string. - * - ******************************************************************************/ -const char *acpi_format_exception(acpi_status status) -{ - acpi_status sub_status; - const char *exception = NULL; - - ACPI_FUNCTION_ENTRY(); - - /* - * Status is composed of two parts, a "type" and an actual code - */ - sub_status = (status & ~AE_CODE_MASK); - - switch (status & AE_CODE_MASK) { - case AE_CODE_ENVIRONMENTAL: - - if (sub_status <= AE_CODE_ENV_MAX) { - exception = acpi_gbl_exception_names_env[sub_status]; - } - break; - - case AE_CODE_PROGRAMMER: - - if (sub_status <= AE_CODE_PGM_MAX) { - exception = - acpi_gbl_exception_names_pgm[sub_status - 1]; - } - break; - - case AE_CODE_ACPI_TABLES: - - if (sub_status <= AE_CODE_TBL_MAX) { - exception = - acpi_gbl_exception_names_tbl[sub_status - 1]; - } - break; - - case AE_CODE_AML: - - if (sub_status <= AE_CODE_AML_MAX) { - exception = - acpi_gbl_exception_names_aml[sub_status - 1]; - } - break; - - case AE_CODE_CONTROL: - - if (sub_status <= AE_CODE_CTRL_MAX) { - exception = - acpi_gbl_exception_names_ctrl[sub_status - 1]; - } - break; - - default: - break; - } - - if (!exception) { - - /* Exception code was not recognized */ - - ACPI_ERROR((AE_INFO, - "Unknown exception code: 0x%8.8X", status)); - - exception = "UNKNOWN_STATUS_CODE"; - } - - return (ACPI_CAST_PTR(const char, exception)); -} + ACPI_MODULE_NAME("utglobal") /******************************************************************************* * @@ -163,8 +83,6 @@ u32 acpi_gbl_startup_flags = 0; u8 acpi_gbl_shutdown = TRUE; -const u8 acpi_gbl_decode_to8bit[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; - const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = { "\\_S0_", "\\_S1_", @@ -183,10 +101,45 @@ const char *acpi_gbl_highest_dstate_names[4] = { /******************************************************************************* * - * Namespace globals + * FUNCTION: acpi_format_exception + * + * PARAMETERS: Status - The acpi_status code to be formatted + * + * RETURN: A string containing the exception text. A valid pointer is + * always returned. + * + * DESCRIPTION: This function translates an ACPI exception into an ASCII string + * It is here instead of utxface.c so it is always present. * ******************************************************************************/ +const char *acpi_format_exception(acpi_status status) +{ + const char *exception = NULL; + + ACPI_FUNCTION_ENTRY(); + + exception = acpi_ut_validate_exception(status); + if (!exception) { + + /* Exception code was not recognized */ + + ACPI_ERROR((AE_INFO, + "Unknown exception code: 0x%8.8X", status)); + + exception = "UNKNOWN_STATUS_CODE"; + } + + return (ACPI_CAST_PTR(const char, exception)); +} + +ACPI_EXPORT_SYMBOL(acpi_format_exception) + +/******************************************************************************* + * + * Namespace globals + * + ******************************************************************************/ /* * Predefined ACPI Names (Built-in to the Interpreter) * @@ -280,53 +233,6 @@ char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position) return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]); } -/******************************************************************************* - * - * Table name globals - * - * NOTE: This table includes ONLY the ACPI tables that the subsystem consumes. - * it is NOT an exhaustive list of all possible ACPI tables. All ACPI tables - * that are not used by the subsystem are simply ignored. - * - * Do NOT add any table to this list that is not consumed directly by this - * subsystem (No MADT, ECDT, SBST, etc.) - * - ******************************************************************************/ - -struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1]; - -struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1] = { - /*********** Name, Signature, Global typed pointer Signature size, Type How many allowed?, Contains valid AML? */ - - /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL, sizeof(RSDP_SIG) - 1, - ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE} - , - /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, (void *)&acpi_gbl_DSDT, - sizeof(DSDT_SIG) - 1, - ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE | - ACPI_TABLE_EXECUTABLE} - , - /* FADT 2 */ {FADT_SIG, FADT_SIG, (void *)&acpi_gbl_FADT, - sizeof(FADT_SIG) - 1, - ACPI_TABLE_PRIMARY | ACPI_TABLE_SINGLE} - , - /* FACS 3 */ {FACS_SIG, FACS_SIG, (void *)&acpi_gbl_FACS, - sizeof(FACS_SIG) - 1, - ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE} - , - /* PSDT 4 */ {PSDT_SIG, PSDT_SIG, NULL, sizeof(PSDT_SIG) - 1, - ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE | - ACPI_TABLE_EXECUTABLE} - , - /* SSDT 5 */ {SSDT_SIG, SSDT_SIG, NULL, sizeof(SSDT_SIG) - 1, - ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE | - ACPI_TABLE_EXECUTABLE} - , - /* XSDT 6 */ {XSDT_SIG, XSDT_SIG, NULL, sizeof(RSDT_SIG) - 1, - ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE} - , -}; - /****************************************************************************** * * Event and Hardware globals @@ -612,7 +518,7 @@ char *acpi_ut_get_node_name(void *object) /* Name must be a valid ACPI name */ if (!acpi_ut_valid_acpi_name(node->name.integer)) { - node->name.integer = acpi_ut_repair_name(node->name.integer); + node->name.integer = acpi_ut_repair_name(node->name.ascii); } /* Return the name */ @@ -751,13 +657,6 @@ void acpi_ut_init_globals(void) return; } - /* ACPI table structure */ - - for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) { - acpi_gbl_table_lists[i].next = NULL; - acpi_gbl_table_lists[i].count = 0; - } - /* Mutex locked flags */ for (i = 0; i < ACPI_NUM_MUTEX; i++) { @@ -773,6 +672,7 @@ void acpi_ut_init_globals(void) /* GPE support */ + acpi_gpe_count = 0; acpi_gbl_gpe_xrupt_list_head = NULL; acpi_gbl_gpe_fadt_blocks[0] = NULL; acpi_gbl_gpe_fadt_blocks[1] = NULL; @@ -784,25 +684,15 @@ void acpi_ut_init_globals(void) acpi_gbl_exception_handler = NULL; acpi_gbl_init_handler = NULL; - /* Global "typed" ACPI table pointers */ - - acpi_gbl_RSDP = NULL; - acpi_gbl_XSDT = NULL; - acpi_gbl_FACS = NULL; - acpi_gbl_FADT = NULL; - acpi_gbl_DSDT = NULL; - /* Global Lock support */ acpi_gbl_global_lock_semaphore = NULL; + acpi_gbl_global_lock_mutex = NULL; acpi_gbl_global_lock_acquired = FALSE; - acpi_gbl_global_lock_thread_count = 0; acpi_gbl_global_lock_handle = 0; /* Miscellaneous variables */ - acpi_gbl_table_flags = ACPI_PHYSICAL_POINTER; - acpi_gbl_rsdp_original_location = 0; acpi_gbl_cm_single_step = FALSE; acpi_gbl_db_terminate_threads = FALSE; acpi_gbl_shutdown = FALSE; @@ -837,8 +727,13 @@ void acpi_ut_init_globals(void) acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX; #endif +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + acpi_gbl_display_final_mem_stats = FALSE; +#endif + return_VOID; } ACPI_EXPORT_SYMBOL(acpi_dbg_level) ACPI_EXPORT_SYMBOL(acpi_dbg_layer) +ACPI_EXPORT_SYMBOL(acpi_gpe_count) diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c index ff76055eb7d6..ad3c0d0a5cf8 100644 --- a/drivers/acpi/utilities/utinit.c +++ b/drivers/acpi/utilities/utinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,119 +44,14 @@ #include #include #include +#include #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utinit") /* Local prototypes */ -static void -acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset); - static void acpi_ut_terminate(void); -/******************************************************************************* - * - * FUNCTION: acpi_ut_fadt_register_error - * - * PARAMETERS: register_name - Pointer to string identifying register - * Value - Actual register contents value - * Offset - Byte offset in the FADT - * - * RETURN: AE_BAD_VALUE - * - * DESCRIPTION: Display failure message - * - ******************************************************************************/ - -static void -acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset) -{ - - ACPI_WARNING((AE_INFO, - "Invalid FADT value %s=%X at offset %X FADT=%p", - register_name, value, offset, acpi_gbl_FADT)); -} - -/****************************************************************************** - * - * FUNCTION: acpi_ut_validate_fadt - * - * PARAMETERS: None - * - * RETURN: Status - * - * DESCRIPTION: Validate various ACPI registers in the FADT - * - ******************************************************************************/ - -acpi_status acpi_ut_validate_fadt(void) -{ - - /* - * Verify Fixed ACPI Description Table fields, - * but don't abort on any problems, just display error - */ - if (acpi_gbl_FADT->pm1_evt_len < 4) { - acpi_ut_fadt_register_error("PM1_EVT_LEN", - (u32) acpi_gbl_FADT->pm1_evt_len, - ACPI_FADT_OFFSET(pm1_evt_len)); - } - - if (!acpi_gbl_FADT->pm1_cnt_len) { - acpi_ut_fadt_register_error("PM1_CNT_LEN", 0, - ACPI_FADT_OFFSET(pm1_cnt_len)); - } - - if (!acpi_gbl_FADT->xpm1a_evt_blk.address) { - acpi_ut_fadt_register_error("X_PM1a_EVT_BLK", 0, - ACPI_FADT_OFFSET(xpm1a_evt_blk. - address)); - } - - if (!acpi_gbl_FADT->xpm1a_cnt_blk.address) { - acpi_ut_fadt_register_error("X_PM1a_CNT_BLK", 0, - ACPI_FADT_OFFSET(xpm1a_cnt_blk. - address)); - } - - if (!acpi_gbl_FADT->xpm_tmr_blk.address) { - acpi_ut_fadt_register_error("X_PM_TMR_BLK", 0, - ACPI_FADT_OFFSET(xpm_tmr_blk. - address)); - } - - if ((acpi_gbl_FADT->xpm2_cnt_blk.address && - !acpi_gbl_FADT->pm2_cnt_len)) { - acpi_ut_fadt_register_error("PM2_CNT_LEN", - (u32) acpi_gbl_FADT->pm2_cnt_len, - ACPI_FADT_OFFSET(pm2_cnt_len)); - } - - if (acpi_gbl_FADT->pm_tm_len < 4) { - acpi_ut_fadt_register_error("PM_TM_LEN", - (u32) acpi_gbl_FADT->pm_tm_len, - ACPI_FADT_OFFSET(pm_tm_len)); - } - - /* Length of GPE blocks must be a multiple of 2 */ - - if (acpi_gbl_FADT->xgpe0_blk.address && - (acpi_gbl_FADT->gpe0_blk_len & 1)) { - acpi_ut_fadt_register_error("(x)GPE0_BLK_LEN", - (u32) acpi_gbl_FADT->gpe0_blk_len, - ACPI_FADT_OFFSET(gpe0_blk_len)); - } - - if (acpi_gbl_FADT->xgpe1_blk.address && - (acpi_gbl_FADT->gpe1_blk_len & 1)) { - acpi_ut_fadt_register_error("(x)GPE1_BLK_LEN", - (u32) acpi_gbl_FADT->gpe1_blk_len, - ACPI_FADT_OFFSET(gpe1_blk_len)); - } - - return (AE_OK); -} - /****************************************************************************** * * FUNCTION: acpi_ut_terminate @@ -178,7 +73,6 @@ static void acpi_ut_terminate(void) ACPI_FUNCTION_TRACE(ut_terminate); - /* Free global tables, etc. */ /* Free global GPE blocks and related info structures */ gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; @@ -239,6 +133,10 @@ void acpi_ut_subsystem_shutdown(void) acpi_ns_terminate(); + /* Delete the ACPI tables */ + + acpi_tb_terminate(); + /* Close the globals */ acpi_ut_terminate(); diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c index 19d74bedce27..0c56a0d20b29 100644 --- a/drivers/acpi/utilities/utmath.c +++ b/drivers/acpi/utilities/utmath.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index 6d8a8211be90..50133fffe420 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,6 +49,78 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utmisc") +/******************************************************************************* + * + * FUNCTION: acpi_ut_validate_exception + * + * PARAMETERS: Status - The acpi_status code to be formatted + * + * RETURN: A string containing the exception text. NULL if exception is + * not valid. + * + * DESCRIPTION: This function validates and translates an ACPI exception into + * an ASCII string. + * + ******************************************************************************/ +const char *acpi_ut_validate_exception(acpi_status status) +{ + acpi_status sub_status; + const char *exception = NULL; + + ACPI_FUNCTION_ENTRY(); + + /* + * Status is composed of two parts, a "type" and an actual code + */ + sub_status = (status & ~AE_CODE_MASK); + + switch (status & AE_CODE_MASK) { + case AE_CODE_ENVIRONMENTAL: + + if (sub_status <= AE_CODE_ENV_MAX) { + exception = acpi_gbl_exception_names_env[sub_status]; + } + break; + + case AE_CODE_PROGRAMMER: + + if (sub_status <= AE_CODE_PGM_MAX) { + exception = + acpi_gbl_exception_names_pgm[sub_status - 1]; + } + break; + + case AE_CODE_ACPI_TABLES: + + if (sub_status <= AE_CODE_TBL_MAX) { + exception = + acpi_gbl_exception_names_tbl[sub_status - 1]; + } + break; + + case AE_CODE_AML: + + if (sub_status <= AE_CODE_AML_MAX) { + exception = + acpi_gbl_exception_names_aml[sub_status - 1]; + } + break; + + case AE_CODE_CONTROL: + + if (sub_status <= AE_CODE_CTRL_MAX) { + exception = + acpi_gbl_exception_names_ctrl[sub_status - 1]; + } + break; + + default: + break; + } + + return (ACPI_CAST_PTR(const char, exception)); +} + /******************************************************************************* * * FUNCTION: acpi_ut_is_aml_table @@ -62,14 +134,15 @@ ACPI_MODULE_NAME("utmisc") * data tables that do not contain AML code. * ******************************************************************************/ + u8 acpi_ut_is_aml_table(struct acpi_table_header *table) { /* These are the only tables that contain executable AML */ - if (ACPI_COMPARE_NAME(table->signature, DSDT_SIG) || - ACPI_COMPARE_NAME(table->signature, PSDT_SIG) || - ACPI_COMPARE_NAME(table->signature, SSDT_SIG)) { + if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) || + ACPI_COMPARE_NAME(table->signature, ACPI_SIG_PSDT) || + ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) { return (TRUE); } @@ -418,7 +491,7 @@ u32 acpi_ut_dword_byte_swap(u32 value) void acpi_ut_set_integer_width(u8 revision) { - if (revision <= 1) { + if (revision < 2) { /* 32-bit case */ @@ -582,26 +655,25 @@ u8 acpi_ut_valid_acpi_name(u32 name) * ******************************************************************************/ -acpi_name acpi_ut_repair_name(acpi_name name) +acpi_name acpi_ut_repair_name(char *name) { - char *name_ptr = ACPI_CAST_PTR(char, &name); - char new_name[ACPI_NAME_SIZE]; acpi_native_uint i; + char new_name[ACPI_NAME_SIZE]; for (i = 0; i < ACPI_NAME_SIZE; i++) { - new_name[i] = name_ptr[i]; + new_name[i] = name[i]; /* * Replace a bad character with something printable, yet technically * still invalid. This prevents any collisions with existing "good" * names in the namespace. */ - if (!acpi_ut_valid_acpi_char(name_ptr[i], i)) { + if (!acpi_ut_valid_acpi_char(name[i], i)) { new_name[i] = '*'; } } - return (*ACPI_CAST_PTR(u32, new_name)); + return (*(u32 *) new_name); } /******************************************************************************* @@ -996,9 +1068,13 @@ acpi_ut_info(char *module_name, u32 line_number, char *format, ...) { va_list args; - acpi_os_printf("ACPI (%s-%04d): ", module_name, line_number); + /* + * Removed module_name, line_number, and acpica version, not needed + * for info output + */ + acpi_os_printf("ACPI: "); va_start(args, format); acpi_os_vprintf(format, args); - acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + acpi_os_printf("\n"); } diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c index 180e73ceb6e2..cbad2ef5987d 100644 --- a/drivers/acpi/utilities/utmutex.c +++ b/drivers/acpi/utilities/utmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c index ba7d8ac702df..4696124759e1 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/utilities/utobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c index 5a2de92831d3..e8fe1ba6cc24 100644 --- a/drivers/acpi/utilities/utresrc.c +++ b/drivers/acpi/utilities/utresrc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c index eaa13d05c859..edcaafad0a31 100644 --- a/drivers/acpi/utilities/utstate.c +++ b/drivers/acpi/utilities/utstate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c index 3538f69c82a1..de3276f4f468 100644 --- a/drivers/acpi/utilities/utxface.c +++ b/drivers/acpi/utilities/utxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,6 +67,7 @@ acpi_status acpi_initialize_subsystem(void) ACPI_FUNCTION_TRACE(acpi_initialize_subsystem); + acpi_gbl_startup_flags = ACPI_SUBSYSTEM_INITIALIZE; ACPI_DEBUG_EXEC(acpi_ut_init_stack_ptr_trace()); /* Initialize the OS-Dependent layer */ @@ -127,20 +128,6 @@ acpi_status acpi_enable_subsystem(u32 flags) ACPI_FUNCTION_TRACE(acpi_enable_subsystem); - /* - * We must initialize the hardware before we can enable ACPI. - * The values from the FADT are validated here. - */ - if (!(flags & ACPI_NO_HARDWARE_INIT)) { - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "[Init] Initializing ACPI hardware\n")); - - status = acpi_hw_initialize(); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } - /* Enable ACPI mode */ if (!(flags & ACPI_NO_ACPI_ENABLE)) { @@ -398,7 +385,6 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer) { struct acpi_system_info *info_ptr; acpi_status status; - u32 i; ACPI_FUNCTION_TRACE(acpi_get_system_info); @@ -431,9 +417,7 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer) /* Timer resolution - 24 or 32 bits */ - if (!acpi_gbl_FADT) { - info_ptr->timer_resolution = 0; - } else if (acpi_gbl_FADT->tmr_val_ext == 0) { + if (acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) { info_ptr->timer_resolution = 24; } else { info_ptr->timer_resolution = 32; @@ -449,13 +433,6 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer) info_ptr->debug_layer = acpi_dbg_layer; info_ptr->debug_level = acpi_dbg_level; - /* Current status of the ACPI tables, per table type */ - - info_ptr->num_table_types = ACPI_TABLE_ID_MAX + 1; - for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) { - info_ptr->table_info[i].count = acpi_gbl_table_lists[i].count; - } - return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 3d54680d0333..e0b97add8c63 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -56,6 +57,12 @@ #define ACPI_VIDEO_HEAD_INVALID (~0u - 1) #define ACPI_VIDEO_HEAD_END (~0u) +#define MAX_NAME_LEN 20 + +#define ACPI_VIDEO_DISPLAY_CRT 1 +#define ACPI_VIDEO_DISPLAY_TV 2 +#define ACPI_VIDEO_DISPLAY_DVI 3 +#define ACPI_VIDEO_DISPLAY_LCD 4 #define _COMPONENT ACPI_VIDEO_COMPONENT ACPI_MODULE_NAME("acpi_video") @@ -66,16 +73,14 @@ MODULE_LICENSE("GPL"); static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device, int type); -static int acpi_video_bus_match(struct acpi_device *device, - struct acpi_driver *driver); static struct acpi_driver acpi_video_bus = { .name = ACPI_VIDEO_DRIVER_NAME, .class = ACPI_VIDEO_CLASS, + .ids = ACPI_VIDEO_HID, .ops = { .add = acpi_video_bus_add, .remove = acpi_video_bus_remove, - .match = acpi_video_bus_match, }, }; @@ -133,20 +138,21 @@ struct acpi_video_device_flags { u8 crt:1; u8 lcd:1; u8 tvout:1; + u8 dvi:1; u8 bios:1; u8 unknown:1; - u8 reserved:3; + u8 reserved:2; }; struct acpi_video_device_cap { u8 _ADR:1; /*Return the unique ID */ u8 _BCL:1; /*Query list of brightness control levels supported */ u8 _BCM:1; /*Set the brightness level */ + u8 _BQC:1; /* Get current brightness level */ u8 _DDC:1; /*Return the EDID for this device */ u8 _DCS:1; /*Return status of output device */ u8 _DGS:1; /*Query graphics state */ u8 _DSS:1; /*Device state set */ - u8 _reserved:1; }; struct acpi_video_device_brightness { @@ -163,6 +169,8 @@ struct acpi_video_device { struct acpi_video_bus *video; struct acpi_device *dev; struct acpi_video_device_brightness *brightness; + struct backlight_device *backlight; + struct backlight_properties *data; }; /* bus */ @@ -257,11 +265,35 @@ static void acpi_video_device_bind(struct acpi_video_bus *video, struct acpi_video_device *device); static int acpi_video_device_enumerate(struct acpi_video_bus *video); static int acpi_video_switch_output(struct acpi_video_bus *video, int event); +static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, + int level); +static int acpi_video_device_lcd_get_level_current( + struct acpi_video_device *device, + unsigned long *level); static int acpi_video_get_next_level(struct acpi_video_device *device, u32 level_current, u32 event); static void acpi_video_switch_brightness(struct acpi_video_device *device, int event); +/*backlight device sysfs support*/ +static int acpi_video_get_brightness(struct backlight_device *bd) +{ + unsigned long cur_level; + struct acpi_video_device *vd = + (struct acpi_video_device *)class_get_devdata(&bd->class_dev); + acpi_video_device_lcd_get_level_current(vd, &cur_level); + return (int) cur_level; +} + +static int acpi_video_set_brightness(struct backlight_device *bd) +{ + int request_level = bd->props->brightness; + struct acpi_video_device *vd = + (struct acpi_video_device *)class_get_devdata(&bd->class_dev); + acpi_video_device_lcd_set_level(vd, request_level); + return 0; +} + /* -------------------------------------------------------------------------- Video Management -------------------------------------------------------------------------- */ @@ -499,6 +531,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) acpi_integer status; acpi_handle h_dummy1; int i; + u32 max_level = 0; union acpi_object *obj = NULL; struct acpi_video_device_brightness *br = NULL; @@ -514,6 +547,8 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) { device->cap._BCM = 1; } + if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1))) + device->cap._BQC = 1; if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) { device->cap._DDC = 1; } @@ -550,6 +585,8 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) continue; } br->levels[count] = (u32) o->integer.value; + if (br->levels[count] > max_level) + max_level = br->levels[count]; count++; } out: @@ -568,6 +605,37 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) kfree(obj); + if (device->cap._BCL && device->cap._BCM && device->cap._BQC){ + unsigned long tmp; + static int count = 0; + char *name; + struct backlight_properties *acpi_video_data; + + name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); + if (!name) + return; + + acpi_video_data = kzalloc( + sizeof(struct backlight_properties), + GFP_KERNEL); + if (!acpi_video_data){ + kfree(name); + return; + } + acpi_video_data->owner = THIS_MODULE; + acpi_video_data->get_brightness = + acpi_video_get_brightness; + acpi_video_data->update_status = + acpi_video_set_brightness; + sprintf(name, "acpi_video%d", count++); + device->data = acpi_video_data; + acpi_video_data->max_brightness = max_level; + acpi_video_device_lcd_get_level_current(device, &tmp); + acpi_video_data->brightness = (int)tmp; + device->backlight = backlight_device_register(name, + NULL, device, acpi_video_data); + kfree(name); + } return; } @@ -668,6 +736,8 @@ static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset) seq_printf(seq, "LCD\n"); else if (dev->flags.tvout) seq_printf(seq, "TVOUT\n"); + else if (dev->flags.dvi) + seq_printf(seq, "DVI\n"); else seq_printf(seq, "UNKNOWN\n"); @@ -1242,6 +1312,16 @@ static int acpi_video_bus_remove_fs(struct acpi_device *device) -------------------------------------------------------------------------- */ /* device interface */ +static struct acpi_video_device_attrib* +acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id) +{ + int count; + + for(count = 0; count < video->attached_count; count++) + if((video->attached_array[count].value.int_val & 0xffff) == device_id) + return &(video->attached_array[count].value.attrib); + return NULL; +} static int acpi_video_bus_get_one_device(struct acpi_device *device, @@ -1250,7 +1330,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device, unsigned long device_id; int status; struct acpi_video_device *data; - + struct acpi_video_device_attrib* attribute; if (!device || !video) return -EINVAL; @@ -1271,20 +1351,30 @@ acpi_video_bus_get_one_device(struct acpi_device *device, data->video = video; data->dev = device; - switch (device_id & 0xffff) { - case 0x0100: - data->flags.crt = 1; - break; - case 0x0400: - data->flags.lcd = 1; - break; - case 0x0200: - data->flags.tvout = 1; - break; - default: + attribute = acpi_video_get_device_attr(video, device_id); + + if((attribute != NULL) && attribute->device_id_scheme) { + switch (attribute->display_type) { + case ACPI_VIDEO_DISPLAY_CRT: + data->flags.crt = 1; + break; + case ACPI_VIDEO_DISPLAY_TV: + data->flags.tvout = 1; + break; + case ACPI_VIDEO_DISPLAY_DVI: + data->flags.dvi = 1; + break; + case ACPI_VIDEO_DISPLAY_LCD: + data->flags.lcd = 1; + break; + default: + data->flags.unknown = 1; + break; + } + if(attribute->bios_can_detect) + data->flags.bios = 1; + } else data->flags.unknown = 1; - break; - } acpi_video_device_bind(video, data); acpi_video_device_find_cap(data); @@ -1588,7 +1678,10 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) status = acpi_remove_notify_handler(device->dev->handle, ACPI_DEVICE_NOTIFY, acpi_video_device_notify); - + if (device->backlight){ + backlight_device_unregister(device->backlight); + kfree(device->data); + } return 0; } @@ -1790,39 +1883,6 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) return 0; } -static int -acpi_video_bus_match(struct acpi_device *device, struct acpi_driver *driver) -{ - acpi_handle h_dummy1; - acpi_handle h_dummy2; - acpi_handle h_dummy3; - - - if (!device || !driver) - return -EINVAL; - - /* Since there is no HID, CID for ACPI Video drivers, we have - * to check well known required nodes for each feature we support. - */ - - /* Does this device able to support video switching ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2))) - return 0; - - /* Does this device able to retrieve a video ROM ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1))) - return 0; - - /* Does this device able to configure which video head to be POSTed ? */ - if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) && - ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3))) - return 0; - - return -ENODEV; -} - static int __init acpi_video_init(void) { int result = 0; diff --git a/drivers/base/class.c b/drivers/base/class.c index 8bf2ca2e56b5..96def1ddba19 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -364,7 +364,7 @@ char *make_class_name(const char *name, struct kobject *kobj) class_name = kmalloc(size, GFP_KERNEL); if (!class_name) - return ERR_PTR(-ENOMEM); + return NULL; strcpy(class_name, name); strcat(class_name, ":"); @@ -411,8 +411,11 @@ static int make_deprecated_class_device_links(struct class_device *class_dev) return 0; class_name = make_class_name(class_dev->class->name, &class_dev->kobj); - error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, - class_name); + if (class_name) + error = sysfs_create_link(&class_dev->dev->kobj, + &class_dev->kobj, class_name); + else + error = -ENOMEM; kfree(class_name); return error; } @@ -425,7 +428,8 @@ static void remove_deprecated_class_device_links(struct class_device *class_dev) return; class_name = make_class_name(class_dev->class->name, &class_dev->kobj); - sysfs_remove_link(&class_dev->dev->kobj, class_name); + if (class_name) + sysfs_remove_link(&class_dev->dev->kobj, class_name); kfree(class_name); } #else @@ -863,9 +867,12 @@ int class_device_rename(struct class_device *class_dev, char *new_name) if (class_dev->dev) { new_class_name = make_class_name(class_dev->class->name, &class_dev->kobj); - sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, - new_class_name); - sysfs_remove_link(&class_dev->dev->kobj, old_class_name); + if (new_class_name) + sysfs_create_link(&class_dev->dev->kobj, + &class_dev->kobj, new_class_name); + if (old_class_name) + sysfs_remove_link(&class_dev->dev->kobj, + old_class_name); } #endif class_device_put(class_dev); diff --git a/drivers/base/core.c b/drivers/base/core.c index 67b79a7592a9..e13614241c9e 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 { @@ -154,25 +156,47 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, "MINOR=%u", MINOR(dev->devt)); } -#ifdef CONFIG_SYSFS_DEPRECATED - /* add bus name (same as SUBSYSTEM, deprecated) */ - if (dev->bus) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", dev->bus->name); -#endif - - /* add driver name (PHYSDEV* values are deprecated)*/ - if (dev->driver) { + if (dev->driver) add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, "DRIVER=%s", dev->driver->name); + #ifdef CONFIG_SYSFS_DEPRECATED + if (dev->class) { + struct device *parent = dev->parent; + + /* find first bus device in parent chain */ + while (parent && !parent->bus) + parent = parent->parent; + if (parent && parent->bus) { + const char *path; + + path = kobject_get_path(&parent->kobj, GFP_KERNEL); + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVPATH=%s", path); + kfree(path); + + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVBUS=%s", parent->bus->name); + + if (parent->driver) + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVDRIVER=%s", parent->driver->name); + } + } else if (dev->bus) { add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", dev->driver->name); -#endif + "PHYSDEVBUS=%s", dev->bus->name); + + if (dev->driver) + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVDRIVER=%s", dev->driver->name); } +#endif /* terminate, set to next free slot, shrink available space */ envp[i] = NULL; @@ -184,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; @@ -247,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]); + } } @@ -390,22 +433,23 @@ void device_initialize(struct device *dev) } #ifdef CONFIG_SYSFS_DEPRECATED -static int setup_parent(struct device *dev, struct device *parent) +static struct kobject * get_device_parent(struct device *dev, + struct device *parent) { /* Set the parent to the class, not the parent device */ /* this keeps sysfs from having a symlink to make old udevs happy */ if (dev->class) - dev->kobj.parent = &dev->class->subsys.kset.kobj; + return &dev->class->subsys.kset.kobj; else if (parent) - dev->kobj.parent = &parent->kobj; + return &parent->kobj; - return 0; + return NULL; } #else -static int virtual_device_parent(struct device *dev) +static struct kobject * virtual_device_parent(struct device *dev) { if (!dev->class) - return -ENODEV; + return ERR_PTR(-ENODEV); if (!dev->class->virtual_dir) { static struct kobject *virtual_dir = NULL; @@ -415,25 +459,31 @@ static int virtual_device_parent(struct device *dev) dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); } - dev->kobj.parent = dev->class->virtual_dir; - return 0; + return dev->class->virtual_dir; } -static int setup_parent(struct device *dev, struct device *parent) +static struct kobject * get_device_parent(struct device *dev, + struct device *parent) { - int error; - /* if this is a class device, and has no parent, create one */ if ((dev->class) && (parent == NULL)) { - error = virtual_device_parent(dev); - if (error) - return error; + return virtual_device_parent(dev); } else if (parent) - dev->kobj.parent = &parent->kobj; + return &parent->kobj; + return NULL; +} +#endif +static int setup_parent(struct device *dev, struct device *parent) +{ + struct kobject *kobj; + kobj = get_device_parent(dev, parent); + if (IS_ERR(kobj)) + return PTR_ERR(kobj); + if (kobj) + dev->kobj.parent = kobj; return 0; } -#endif /** * device_add - add device to device hierarchy. @@ -520,9 +570,13 @@ int device_add(struct device *dev) &dev->kobj, dev->bus_id); #ifdef CONFIG_SYSFS_DEPRECATED if (parent) { - sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device"); - class_name = make_class_name(dev->class->name, &dev->kobj); - sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name); + sysfs_create_link(&dev->kobj, &dev->parent->kobj, + "device"); + class_name = make_class_name(dev->class->name, + &dev->kobj); + if (class_name) + sysfs_create_link(&dev->parent->kobj, + &dev->kobj, class_name); } #endif } @@ -535,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) @@ -665,7 +720,9 @@ void device_del(struct device * dev) if (parent) { char *class_name = make_class_name(dev->class->name, &dev->kobj); - sysfs_remove_link(&dev->parent->kobj, class_name); + if (class_name) + sysfs_remove_link(&dev->parent->kobj, + class_name); kfree(class_name); sysfs_remove_link(&dev->kobj, "device"); } @@ -968,20 +1025,25 @@ static int device_move_class_links(struct device *dev, class_name = make_class_name(dev->class->name, &dev->kobj); if (!class_name) { - error = PTR_ERR(class_name); - class_name = NULL; + error = -ENOMEM; goto out; } if (old_parent) { sysfs_remove_link(&dev->kobj, "device"); sysfs_remove_link(&old_parent->kobj, class_name); } - error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device"); - if (error) - goto out; - error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name); - if (error) - sysfs_remove_link(&dev->kobj, "device"); + if (new_parent) { + error = sysfs_create_link(&dev->kobj, &new_parent->kobj, + "device"); + if (error) + goto out; + error = sysfs_create_link(&new_parent->kobj, &dev->kobj, + class_name); + if (error) + sysfs_remove_link(&dev->kobj, "device"); + } + else + error = 0; out: kfree(class_name); return error; @@ -993,29 +1055,28 @@ out: /** * device_move - moves a device to a new parent * @dev: the pointer to the struct device to be moved - * @new_parent: the new parent of the device + * @new_parent: the new parent of the device (can by NULL) */ int device_move(struct device *dev, struct device *new_parent) { int error; struct device *old_parent; + struct kobject *new_parent_kobj; dev = get_device(dev); if (!dev) return -EINVAL; - if (!device_is_registered(dev)) { - error = -EINVAL; - goto out; - } new_parent = get_device(new_parent); - if (!new_parent) { - error = -EINVAL; + new_parent_kobj = get_device_parent (dev, new_parent); + if (IS_ERR(new_parent_kobj)) { + error = PTR_ERR(new_parent_kobj); + put_device(new_parent); goto out; } pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id, - new_parent->bus_id); - error = kobject_move(&dev->kobj, &new_parent->kobj); + new_parent ? new_parent->bus_id : ""); + error = kobject_move(&dev->kobj, new_parent_kobj); if (error) { put_device(new_parent); goto out; @@ -1024,7 +1085,8 @@ int device_move(struct device *dev, struct device *new_parent) dev->parent = new_parent; if (old_parent) klist_remove(&dev->knode_parent); - klist_add_tail(&dev->knode_parent, &new_parent->klist_children); + if (new_parent) + klist_add_tail(&dev->knode_parent, &new_parent->klist_children); if (!dev->class) goto out_put; error = device_move_class_links(dev, old_parent, new_parent); @@ -1032,7 +1094,8 @@ int device_move(struct device *dev, struct device *new_parent) /* We ignore errors on cleanup since we're hosed anyway... */ device_move_class_links(dev, new_parent, old_parent); if (!kobject_move(&dev->kobj, &old_parent->kobj)) { - klist_remove(&dev->knode_parent); + if (new_parent) + klist_remove(&dev->knode_parent); if (old_parent) klist_add_tail(&dev->knode_parent, &old_parent->klist_children); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 510e7884975f..b5bf243d9cd6 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -86,8 +86,12 @@ static void driver_sysfs_remove(struct device *dev) */ int device_bind_driver(struct device *dev) { - driver_bound(dev); - return driver_sysfs_add(dev); + int ret; + + ret = driver_sysfs_add(dev); + if (!ret) + driver_bound(dev); + return ret; } struct stupid_thread_structure { @@ -136,18 +140,17 @@ probe_failed: driver_sysfs_remove(dev); dev->driver = NULL; - if (ret == -ENODEV || ret == -ENXIO) { - /* Driver matched, but didn't support device - * or device not found. - * Not an error; keep going. - */ - ret = 0; - } else { + if (ret != -ENODEV && ret != -ENXIO) { /* driver matched but the probe failed */ printk(KERN_WARNING "%s: probe of %s failed with error %d\n", drv->name, dev->bus_id, ret); } + /* + * Ignore errors returned by ->probe so that the next driver can try + * its luck. + */ + ret = 0; done: kfree(data); atomic_dec(&probe_count); diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 64558f45e6bc..c0a979a5074b 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -35,7 +35,7 @@ enum { FW_STATUS_READY_NOHOTPLUG, }; -static int loading_timeout = 10; /* In seconds */ +static int loading_timeout = 60; /* In seconds */ /* fw_lock could be moved to 'struct firmware_priv' but since it is just * guarding for corner cases a global lock should be OK */ diff --git a/drivers/base/platform.c b/drivers/base/platform.c index f9c903ba9fcd..30480f6f2af2 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -611,8 +611,15 @@ EXPORT_SYMBOL_GPL(platform_bus_type); int __init platform_bus_init(void) { - device_register(&platform_bus); - return bus_register(&platform_bus_type); + int error; + + error = device_register(&platform_bus); + if (error) + return error; + error = bus_register(&platform_bus_type); + if (error) + device_unregister(&platform_bus); + return error; } #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 6dcdceb81203..85d99e21e188 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -532,11 +532,13 @@ typedef struct drm_mm_node { int free; unsigned long start; unsigned long size; + struct drm_mm *mm; void *private; } drm_mm_node_t; typedef struct drm_mm { - drm_mm_node_t root_node; + struct list_head fl_entry; + struct list_head ml_entry; } drm_mm_t; /** @@ -843,9 +845,6 @@ extern void drm_mem_init(void); extern int drm_mem_info(char *buf, char **start, off_t offset, int request, int *eof, void *data); extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area); -extern void *drm_ioremap(unsigned long offset, unsigned long size, - drm_device_t * dev); -extern void drm_ioremapfree(void *pt, unsigned long size, drm_device_t * dev); extern DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type); extern int drm_free_agp(DRM_AGP_MEM * handle, int pages); @@ -1053,33 +1052,18 @@ extern void drm_sysfs_device_remove(struct class_device *class_dev); extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, unsigned long size, unsigned alignment); -extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur); +void drm_mm_put_block(drm_mm_node_t * cur); extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, unsigned alignment, int best_match); extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); extern void drm_mm_takedown(drm_mm_t *mm); +extern int drm_mm_clean(drm_mm_t *mm); +extern unsigned long drm_mm_tail_space(drm_mm_t *mm); +extern int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size); +extern int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size); -/* Inline replacements for DRM_IOREMAP macros */ -static __inline__ void drm_core_ioremap(struct drm_map *map, - struct drm_device *dev) -{ - map->handle = drm_ioremap(map->offset, map->size, dev); -} - -#if 0 -static __inline__ void drm_core_ioremap_nocache(struct drm_map *map, - struct drm_device *dev) -{ - map->handle = drm_ioremap_nocache(map->offset, map->size, dev); -} -#endif /* 0 */ - -static __inline__ void drm_core_ioremapfree(struct drm_map *map, - struct drm_device *dev) -{ - if (map->handle && map->size) - drm_ioremapfree(map->handle, map->size, dev); -} +extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev); +extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev); static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned int token) diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index 9f65f5697ba8..a6828cc14e58 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -79,14 +79,14 @@ static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash, if (!use_hashed_handle) { int ret; - hash->key = user_token; + hash->key = user_token >> PAGE_SHIFT; ret = drm_ht_insert_item(&dev->map_hash, hash); if (ret != -EINVAL) return ret; } return drm_ht_just_insert_please(&dev->map_hash, hash, user_token, 32 - PAGE_SHIFT - 3, - PAGE_SHIFT, DRM_MAP_HASH_OFFSET); + 0, DRM_MAP_HASH_OFFSET >> PAGE_SHIFT); } /** @@ -178,11 +178,11 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, } } if (map->type == _DRM_REGISTERS) - map->handle = drm_ioremap(map->offset, map->size, dev); + map->handle = ioremap(map->offset, map->size); break; case _DRM_SHM: - map->handle = vmalloc_32(map->size); + map->handle = vmalloc_user(map->size); DRM_DEBUG("%lu %d %p\n", map->size, drm_order(map->size), map->handle); if (!map->handle) { @@ -238,7 +238,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, list = drm_alloc(sizeof(*list), DRM_MEM_MAPS); if (!list) { if (map->type == _DRM_REGISTERS) - drm_ioremapfree(map->handle, map->size, dev); + iounmap(map->handle); drm_free(map, sizeof(*map), DRM_MEM_MAPS); return -EINVAL; } @@ -255,14 +255,14 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, ret = drm_map_handle(dev, &list->hash, user_token, 0); if (ret) { if (map->type == _DRM_REGISTERS) - drm_ioremapfree(map->handle, map->size, dev); + iounmap(map->handle); drm_free(map, sizeof(*map), DRM_MEM_MAPS); drm_free(list, sizeof(*list), DRM_MEM_MAPS); mutex_unlock(&dev->struct_mutex); return ret; } - list->user_token = list->hash.key; + list->user_token = list->hash.key << PAGE_SHIFT; mutex_unlock(&dev->struct_mutex); *maplist = list; @@ -347,7 +347,8 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map) if (r_list->map == map) { list_del(list); - drm_ht_remove_key(&dev->map_hash, r_list->user_token); + drm_ht_remove_key(&dev->map_hash, + r_list->user_token >> PAGE_SHIFT); drm_free(list, sizeof(*list), DRM_MEM_MAPS); break; } @@ -362,7 +363,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map) switch (map->type) { case _DRM_REGISTERS: - drm_ioremapfree(map->handle, map->size, dev); + iounmap(map->handle); /* FALLTHROUGH */ case _DRM_FRAME_BUFFER: if (drm_core_has_MTRR(dev) && map->mtrr >= 0) { diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c index 5681cae1d404..92a867082376 100644 --- a/drivers/char/drm/drm_memory.c +++ b/drivers/char/drm/drm_memory.c @@ -79,28 +79,6 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area) } #if __OS_HAS_AGP -/* - * Find the drm_map that covers the range [offset, offset+size). - */ -static drm_map_t *drm_lookup_map(unsigned long offset, - unsigned long size, drm_device_t * dev) -{ - struct list_head *list; - drm_map_list_t *r_list; - drm_map_t *map; - - list_for_each(list, &dev->maplist->head) { - r_list = (drm_map_list_t *) list; - map = r_list->map; - if (!map) - continue; - if (map->offset <= offset - && (offset + size) <= (map->offset + map->size)) - return map; - } - return NULL; -} - static void *agp_remap(unsigned long offset, unsigned long size, drm_device_t * dev) { @@ -169,13 +147,6 @@ int drm_unbind_agp(DRM_AGP_MEM * handle) } #else /* __OS_HAS_AGP */ - -static inline drm_map_t *drm_lookup_map(unsigned long offset, - unsigned long size, drm_device_t * dev) -{ - return NULL; -} - static inline void *agp_remap(unsigned long offset, unsigned long size, drm_device_t * dev) { @@ -184,57 +155,28 @@ static inline void *agp_remap(unsigned long offset, unsigned long size, #endif /* agp */ -void *drm_ioremap(unsigned long offset, unsigned long size, - drm_device_t * dev) -{ - if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { - drm_map_t *map = drm_lookup_map(offset, size, dev); - - if (map && map->type == _DRM_AGP) - return agp_remap(offset, size, dev); - } - return ioremap(offset, size); -} -EXPORT_SYMBOL(drm_ioremap); - -#if 0 -void *drm_ioremap_nocache(unsigned long offset, - unsigned long size, drm_device_t * dev) -{ - if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { - drm_map_t *map = drm_lookup_map(offset, size, dev); - - if (map && map->type == _DRM_AGP) - return agp_remap(offset, size, dev); - } - return ioremap_nocache(offset, size); -} -#endif /* 0 */ - -void drm_ioremapfree(void *pt, unsigned long size, - drm_device_t * dev) -{ - /* - * This is a bit ugly. It would be much cleaner if the DRM API would use separate - * routines for handling mappings in the AGP space. Hopefully this can be done in - * a future revision of the interface... - */ - if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture - && ((unsigned long)pt >= VMALLOC_START - && (unsigned long)pt < VMALLOC_END)) { - unsigned long offset; - drm_map_t *map; - - offset = drm_follow_page(pt) | ((unsigned long)pt & ~PAGE_MASK); - map = drm_lookup_map(offset, size, dev); - if (map && map->type == _DRM_AGP) { - vunmap(pt); - return; - } - } - - iounmap(pt); -} -EXPORT_SYMBOL(drm_ioremapfree); - #endif /* debug_memory */ + +void drm_core_ioremap(struct drm_map *map, struct drm_device *dev) +{ + if (drm_core_has_AGP(dev) && + dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) + map->handle = agp_remap(map->offset, map->size, dev); + else + map->handle = ioremap(map->offset, map->size); +} +EXPORT_SYMBOL(drm_core_ioremap); + +void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev) +{ + if (!map->handle || !map->size) + return; + + if (drm_core_has_AGP(dev) && + dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) + vunmap(map->handle); + else + iounmap(map->handle); +} +EXPORT_SYMBOL(drm_core_ioremapfree); + diff --git a/drivers/char/drm/drm_memory.h b/drivers/char/drm/drm_memory.h index f1b97aff10cf..63e425b5ea82 100644 --- a/drivers/char/drm/drm_memory.h +++ b/drivers/char/drm/drm_memory.h @@ -56,26 +56,6 @@ # endif #endif -static inline unsigned long drm_follow_page(void *vaddr) -{ - pgd_t *pgd = pgd_offset_k((unsigned long)vaddr); - pud_t *pud = pud_offset(pgd, (unsigned long)vaddr); - pmd_t *pmd = pmd_offset(pud, (unsigned long)vaddr); - pte_t *ptep = pte_offset_kernel(pmd, (unsigned long)vaddr); - return pte_pfn(*ptep) << PAGE_SHIFT; -} - #else /* __OS_HAS_AGP */ -static inline unsigned long drm_follow_page(void *vaddr) -{ - return 0; -} - #endif - -void *drm_ioremap(unsigned long offset, unsigned long size, - drm_device_t * dev); - -void drm_ioremapfree(void *pt, unsigned long size, - drm_device_t * dev); diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h index 74581af806e1..6463271deea8 100644 --- a/drivers/char/drm/drm_memory_debug.h +++ b/drivers/char/drm/drm_memory_debug.h @@ -205,76 +205,6 @@ void drm_free (void *pt, size_t size, int area) { } } -void *drm_ioremap (unsigned long offset, unsigned long size, - drm_device_t * dev) { - void *pt; - - if (!size) { - DRM_MEM_ERROR(DRM_MEM_MAPPINGS, - "Mapping 0 bytes at 0x%08lx\n", offset); - return NULL; - } - - if (!(pt = drm_ioremap(offset, size, dev))) { - spin_lock(&drm_mem_lock); - ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count; - spin_unlock(&drm_mem_lock); - return NULL; - } - spin_lock(&drm_mem_lock); - ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; - drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size; - spin_unlock(&drm_mem_lock); - return pt; -} - -#if 0 -void *drm_ioremap_nocache (unsigned long offset, unsigned long size, - drm_device_t * dev) { - void *pt; - - if (!size) { - DRM_MEM_ERROR(DRM_MEM_MAPPINGS, - "Mapping 0 bytes at 0x%08lx\n", offset); - return NULL; - } - - if (!(pt = drm_ioremap_nocache(offset, size, dev))) { - spin_lock(&drm_mem_lock); - ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count; - spin_unlock(&drm_mem_lock); - return NULL; - } - spin_lock(&drm_mem_lock); - ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; - drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size; - spin_unlock(&drm_mem_lock); - return pt; -} -#endif /* 0 */ - -void drm_ioremapfree (void *pt, unsigned long size, drm_device_t * dev) { - int alloc_count; - int free_count; - - if (!pt) - DRM_MEM_ERROR(DRM_MEM_MAPPINGS, - "Attempt to free NULL pointer\n"); - else - drm_ioremapfree(pt, size, dev); - - spin_lock(&drm_mem_lock); - drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size; - free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count; - alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; - spin_unlock(&drm_mem_lock); - if (free_count > alloc_count) { - DRM_MEM_ERROR(DRM_MEM_MAPPINGS, - "Excess frees: %d frees, %d allocs\n", - free_count, alloc_count); - } -} - #if __OS_HAS_AGP DRM_AGP_MEM *drm_alloc_agp (drm_device_t *dev, int pages, u32 type) { diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c index 617526bd5b0c..9b46b85027d0 100644 --- a/drivers/char/drm/drm_mm.c +++ b/drivers/char/drm/drm_mm.c @@ -42,36 +42,131 @@ */ #include "drmP.h" +#include + +unsigned long drm_mm_tail_space(drm_mm_t *mm) +{ + struct list_head *tail_node; + drm_mm_node_t *entry; + + tail_node = mm->ml_entry.prev; + entry = list_entry(tail_node, drm_mm_node_t, ml_entry); + if (!entry->free) + return 0; + + return entry->size; +} + +int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size) +{ + struct list_head *tail_node; + drm_mm_node_t *entry; + + tail_node = mm->ml_entry.prev; + entry = list_entry(tail_node, drm_mm_node_t, ml_entry); + if (!entry->free) + return -ENOMEM; + + if (entry->size <= size) + return -ENOMEM; + + entry->size -= size; + return 0; +} + + +static int drm_mm_create_tail_node(drm_mm_t *mm, + unsigned long start, + unsigned long size) +{ + drm_mm_node_t *child; + + child = (drm_mm_node_t *) + drm_alloc(sizeof(*child), DRM_MEM_MM); + if (!child) + return -ENOMEM; + + child->free = 1; + child->size = size; + child->start = start; + child->mm = mm; + + list_add_tail(&child->ml_entry, &mm->ml_entry); + list_add_tail(&child->fl_entry, &mm->fl_entry); + + return 0; +} + + +int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size) +{ + struct list_head *tail_node; + drm_mm_node_t *entry; + + tail_node = mm->ml_entry.prev; + entry = list_entry(tail_node, drm_mm_node_t, ml_entry); + if (!entry->free) { + return drm_mm_create_tail_node(mm, entry->start + entry->size, size); + } + entry->size += size; + return 0; +} + +static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent, + unsigned long size) +{ + drm_mm_node_t *child; + + child = (drm_mm_node_t *) + drm_alloc(sizeof(*child), DRM_MEM_MM); + if (!child) + return NULL; + + INIT_LIST_HEAD(&child->fl_entry); + + child->free = 0; + child->size = size; + child->start = parent->start; + child->mm = parent->mm; + + list_add_tail(&child->ml_entry, &parent->ml_entry); + INIT_LIST_HEAD(&child->fl_entry); + + parent->size -= size; + parent->start += size; + return child; +} + + drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, unsigned long size, unsigned alignment) { + drm_mm_node_t *align_splitoff = NULL; drm_mm_node_t *child; + unsigned tmp = 0; if (alignment) - size += alignment - 1; + tmp = parent->start % alignment; + + if (tmp) { + align_splitoff = drm_mm_split_at_start(parent, alignment - tmp); + if (!align_splitoff) + return NULL; + } if (parent->size == size) { list_del_init(&parent->fl_entry); parent->free = 0; return parent; } else { - child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM); - if (!child) - return NULL; - - INIT_LIST_HEAD(&child->ml_entry); - INIT_LIST_HEAD(&child->fl_entry); - - child->free = 0; - child->size = size; - child->start = parent->start; - - list_add_tail(&child->ml_entry, &parent->ml_entry); - parent->size -= size; - parent->start += size; + child = drm_mm_split_at_start(parent, size); } + + if (align_splitoff) + drm_mm_put_block(align_splitoff); + return child; } @@ -80,12 +175,12 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, * Otherwise add to the free stack. */ -void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) +void drm_mm_put_block(drm_mm_node_t * cur) { - drm_mm_node_t *list_root = &mm->root_node; + drm_mm_t *mm = cur->mm; struct list_head *cur_head = &cur->ml_entry; - struct list_head *root_head = &list_root->ml_entry; + struct list_head *root_head = &mm->ml_entry; drm_mm_node_t *prev_node = NULL; drm_mm_node_t *next_node; @@ -116,7 +211,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) } if (!merged) { cur->free = 1; - list_add(&cur->fl_entry, &list_root->fl_entry); + list_add(&cur->fl_entry, &mm->fl_entry); } else { list_del(&cur->ml_entry); drm_free(cur, sizeof(*cur), DRM_MEM_MM); @@ -128,20 +223,30 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, unsigned alignment, int best_match) { struct list_head *list; - const struct list_head *free_stack = &mm->root_node.fl_entry; + const struct list_head *free_stack = &mm->fl_entry; drm_mm_node_t *entry; drm_mm_node_t *best; unsigned long best_size; + unsigned wasted; best = NULL; best_size = ~0UL; - if (alignment) - size += alignment - 1; - list_for_each(list, free_stack) { entry = list_entry(list, drm_mm_node_t, fl_entry); - if (entry->size >= size) { + wasted = 0; + + if (entry->size < size) + continue; + + if (alignment) { + register unsigned tmp = entry->start % alignment; + if (tmp) + wasted += alignment - tmp; + } + + + if (entry->size >= size + wasted) { if (!best_match) return entry; if (size < best_size) { @@ -154,40 +259,32 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, return best; } +int drm_mm_clean(drm_mm_t * mm) +{ + struct list_head *head = &mm->ml_entry; + + return (head->next->next == head); +} + int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) { - drm_mm_node_t *child; + INIT_LIST_HEAD(&mm->ml_entry); + INIT_LIST_HEAD(&mm->fl_entry); - INIT_LIST_HEAD(&mm->root_node.ml_entry); - INIT_LIST_HEAD(&mm->root_node.fl_entry); - child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM); - if (!child) - return -ENOMEM; - - INIT_LIST_HEAD(&child->ml_entry); - INIT_LIST_HEAD(&child->fl_entry); - - child->start = start; - child->size = size; - child->free = 1; - - list_add(&child->fl_entry, &mm->root_node.fl_entry); - list_add(&child->ml_entry, &mm->root_node.ml_entry); - - return 0; + return drm_mm_create_tail_node(mm, start, size); } EXPORT_SYMBOL(drm_mm_init); void drm_mm_takedown(drm_mm_t * mm) { - struct list_head *bnode = mm->root_node.fl_entry.next; + struct list_head *bnode = mm->fl_entry.next; drm_mm_node_t *entry; entry = list_entry(bnode, drm_mm_node_t, fl_entry); - if (entry->ml_entry.next != &mm->root_node.ml_entry || - entry->fl_entry.next != &mm->root_node.fl_entry) { + if (entry->ml_entry.next != &mm->ml_entry || + entry->fl_entry.next != &mm->fl_entry) { DRM_ERROR("Memory manager not clean. Delaying takedown\n"); return; } diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index 09398d5fbd3f..ad54b845978b 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -226,12 +226,14 @@ {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \ {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \ {0, 0, 0} #define i810_PCI_IDS \ diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c index 62d5fe15f046..7fd0da712142 100644 --- a/drivers/char/drm/drm_proc.c +++ b/drivers/char/drm/drm_proc.c @@ -500,7 +500,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request, for (pt = dev->vmalist; pt; pt = pt->next) { if (!(vma = pt->vma)) continue; - DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx", + DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000", pt->pid, vma->vm_start, vma->vm_end, @@ -510,7 +510,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request, vma->vm_flags & VM_MAYSHARE ? 's' : 'p', vma->vm_flags & VM_LOCKED ? 'l' : '-', vma->vm_flags & VM_IO ? 'i' : '-', - vma->vm_pgoff << PAGE_SHIFT); + vma->vm_pgoff); #if defined(__i386__) pgprot = pgprot_val(vma->vm_page_prot); diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c index 19c81d2e13d0..e15db6d6bea9 100644 --- a/drivers/char/drm/drm_sman.c +++ b/drivers/char/drm/drm_sman.c @@ -101,10 +101,9 @@ static void *drm_sman_mm_allocate(void *private, unsigned long size, static void drm_sman_mm_free(void *private, void *ref) { - drm_mm_t *mm = (drm_mm_t *) private; drm_mm_node_t *node = (drm_mm_node_t *) ref; - drm_mm_put_block(mm, node); + drm_mm_put_block(node); } static void drm_sman_mm_destroy(void *private) diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index b9cfc077f6bc..54a632848955 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c @@ -70,7 +70,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, if (!dev->agp || !dev->agp->cant_use_aperture) goto vm_nopage_error; - if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) + if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) goto vm_nopage_error; r_list = drm_hash_entry(hash, drm_map_list_t, hash); @@ -227,7 +227,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) map->size); DRM_DEBUG("mtrr_del = %d\n", retcode); } - drm_ioremapfree(map->handle, map->size, dev); + iounmap(map->handle); break; case _DRM_SHM: vfree(map->handle); @@ -463,8 +463,8 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) lock_kernel(); dev = priv->head->dev; dma = dev->dma; - DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", - vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT); + DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", + vma->vm_start, vma->vm_end, vma->vm_pgoff); /* Length must match exact page count */ if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { @@ -537,8 +537,8 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) unsigned long offset = 0; drm_hash_item_t *hash; - DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", - vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT); + DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", + vma->vm_start, vma->vm_end, vma->vm_pgoff); if (!priv->authenticated) return -EACCES; @@ -547,7 +547,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) * the AGP mapped at physical address 0 * --BenH. */ - if (!(vma->vm_pgoff << PAGE_SHIFT) + if (!vma->vm_pgoff #if __OS_HAS_AGP && (!dev->agp || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) @@ -555,7 +555,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) ) return drm_mmap_dma(filp, vma); - if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) { + if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) { DRM_ERROR("Could not find map\n"); return -EINVAL; } diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c index fa2de70f7401..60cb4e45a75e 100644 --- a/drivers/char/drm/i810_dma.c +++ b/drivers/char/drm/i810_dma.c @@ -219,8 +219,7 @@ static int i810_dma_cleanup(drm_device_t * dev) (drm_i810_private_t *) dev->dev_private; if (dev_priv->ring.virtual_start) { - drm_ioremapfree((void *)dev_priv->ring.virtual_start, - dev_priv->ring.Size, dev); + drm_core_ioremapfree(&dev_priv->ring.map, dev); } if (dev_priv->hw_status_page) { pci_free_consistent(dev->pdev, PAGE_SIZE, @@ -236,9 +235,9 @@ static int i810_dma_cleanup(drm_device_t * dev) for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[i]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; + if (buf_priv->kernel_virtual && buf->total) - drm_ioremapfree(buf_priv->kernel_virtual, - buf->total, dev); + drm_core_ioremapfree(&buf_priv->map, dev); } } return 0; @@ -311,8 +310,15 @@ static int i810_freelist_init(drm_device_t * dev, drm_i810_private_t * dev_priv) *buf_priv->in_use = I810_BUF_FREE; - buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, - buf->total, dev); + buf_priv->map.offset = buf->bus_address; + buf_priv->map.size = buf->total; + buf_priv->map.type = _DRM_AGP; + buf_priv->map.flags = 0; + buf_priv->map.mtrr = 0; + + drm_core_ioremap(&buf_priv->map, dev); + buf_priv->kernel_virtual = buf_priv->map.handle; + } return 0; } @@ -363,18 +369,24 @@ static int i810_dma_initialize(drm_device_t * dev, dev_priv->ring.End = init->ring_end; dev_priv->ring.Size = init->ring_size; - dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + - init->ring_start, - init->ring_size, dev); + dev_priv->ring.map.offset = dev->agp->base + init->ring_start; + dev_priv->ring.map.size = init->ring_size; + dev_priv->ring.map.type = _DRM_AGP; + dev_priv->ring.map.flags = 0; + dev_priv->ring.map.mtrr = 0; - if (dev_priv->ring.virtual_start == NULL) { + drm_core_ioremap(&dev_priv->ring.map, dev); + + if (dev_priv->ring.map.handle == NULL) { dev->dev_private = (void *)dev_priv; i810_dma_cleanup(dev); DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); - return -ENOMEM; + return DRM_ERR(ENOMEM); } + dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; dev_priv->w = init->w; diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h index e8cf3ff606f0..e6df49f4928a 100644 --- a/drivers/char/drm/i810_drv.h +++ b/drivers/char/drm/i810_drv.h @@ -61,6 +61,7 @@ typedef struct drm_i810_buf_priv { int currently_mapped; void *virtual; void *kernel_virtual; + drm_local_map_t map; } drm_i810_buf_priv_t; typedef struct _drm_i810_ring_buffer { @@ -72,6 +73,7 @@ typedef struct _drm_i810_ring_buffer { int head; int tail; int space; + drm_local_map_t map; } drm_i810_ring_buffer_t; typedef struct drm_i810_private { diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index 4f0e5746ab33..95224455ec0c 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -223,8 +223,7 @@ static int i830_dma_cleanup(drm_device_t * dev) (drm_i830_private_t *) dev->dev_private; if (dev_priv->ring.virtual_start) { - drm_ioremapfree((void *)dev_priv->ring.virtual_start, - dev_priv->ring.Size, dev); + drm_core_ioremapfree(&dev_priv->ring.map, dev); } if (dev_priv->hw_status_page) { pci_free_consistent(dev->pdev, PAGE_SIZE, @@ -242,8 +241,7 @@ static int i830_dma_cleanup(drm_device_t * dev) drm_buf_t *buf = dma->buflist[i]; drm_i830_buf_priv_t *buf_priv = buf->dev_private; if (buf_priv->kernel_virtual && buf->total) - drm_ioremapfree(buf_priv->kernel_virtual, - buf->total, dev); + drm_core_ioremapfree(&buf_priv->map, dev); } } return 0; @@ -320,8 +318,14 @@ static int i830_freelist_init(drm_device_t * dev, drm_i830_private_t * dev_priv) *buf_priv->in_use = I830_BUF_FREE; - buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, - buf->total, dev); + buf_priv->map.offset = buf->bus_address; + buf_priv->map.size = buf->total; + buf_priv->map.type = _DRM_AGP; + buf_priv->map.flags = 0; + buf_priv->map.mtrr = 0; + + drm_core_ioremap(&buf_priv->map, dev); + buf_priv->kernel_virtual = buf_priv->map.handle; } return 0; } @@ -373,18 +377,24 @@ static int i830_dma_initialize(drm_device_t * dev, dev_priv->ring.End = init->ring_end; dev_priv->ring.Size = init->ring_size; - dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + - init->ring_start, - init->ring_size, dev); + dev_priv->ring.map.offset = dev->agp->base + init->ring_start; + dev_priv->ring.map.size = init->ring_size; + dev_priv->ring.map.type = _DRM_AGP; + dev_priv->ring.map.flags = 0; + dev_priv->ring.map.mtrr = 0; - if (dev_priv->ring.virtual_start == NULL) { + drm_core_ioremap(&dev_priv->ring.map, dev); + + if (dev_priv->ring.map.handle == NULL) { dev->dev_private = (void *)dev_priv; i830_dma_cleanup(dev); DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); - return -ENOMEM; + return DRM_ERR(ENOMEM); } + dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; dev_priv->w = init->w; diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h index 85bc5be6f916..e91f94afb4bb 100644 --- a/drivers/char/drm/i830_drv.h +++ b/drivers/char/drm/i830_drv.h @@ -68,6 +68,7 @@ typedef struct drm_i830_buf_priv { int currently_mapped; void __user *virtual; void *kernel_virtual; + drm_local_map_t map; } drm_i830_buf_priv_t; typedef struct _drm_i830_ring_buffer { @@ -79,6 +80,7 @@ typedef struct _drm_i830_ring_buffer { int head; int tail; int space; + drm_local_map_t map; } drm_i830_ring_buffer_t; typedef struct drm_i830_private { diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index a691ae74129d..c0539c6299cf 100644 --- a/drivers/char/drm/via_dma.c +++ b/drivers/char/drm/via_dma.c @@ -190,6 +190,11 @@ static int via_initialize(drm_device_t * dev, return DRM_ERR(EFAULT); } + if (dev_priv->chipset == VIA_DX9_0) { + DRM_ERROR("AGP DMA is not supported on this chip\n"); + return DRM_ERR(EINVAL); + } + dev_priv->ring.map.offset = dev->agp->base + init->offset; dev_priv->ring.map.size = init->size; dev_priv->ring.map.type = 0; @@ -480,6 +485,7 @@ static int via_hook_segment(drm_via_private_t * dev_priv, VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); + VIA_READ(VIA_REG_TRANSPACE); } } return paused; @@ -557,8 +563,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); - + DRM_WRITEMEMORYBARRIER(); VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK); + VIA_READ(VIA_REG_TRANSPACE); } static void via_pad_cache(drm_via_private_t * dev_priv, int qwords) diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c index 806f9ce5f47b..2054d5773717 100644 --- a/drivers/char/drm/via_dmablit.c +++ b/drivers/char/drm/via_dmablit.c @@ -218,7 +218,9 @@ via_fire_dmablit(drm_device_t *dev, drm_via_sg_info_t *vsg, int engine) VIA_WRITE(VIA_PCI_DMA_MR0 + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE); VIA_WRITE(VIA_PCI_DMA_BCR0 + engine*0x10, 0); VIA_WRITE(VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start); + DRM_WRITEMEMORYBARRIER(); VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS); + VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04); } /* diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h index d21b5b75da0f..8b8778d4a423 100644 --- a/drivers/char/drm/via_drv.h +++ b/drivers/char/drm/via_drv.h @@ -29,10 +29,10 @@ #define DRIVER_NAME "via" #define DRIVER_DESC "VIA Unichrome / Pro" -#define DRIVER_DATE "20060529" +#define DRIVER_DATE "20061227" #define DRIVER_MAJOR 2 -#define DRIVER_MINOR 10 +#define DRIVER_MINOR 11 #define DRIVER_PATCHLEVEL 0 #include "via_verifier.h" @@ -79,7 +79,7 @@ typedef struct drm_via_private { char pci_buf[VIA_PCI_BUF_SIZE]; const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; uint32_t num_fire_offsets; - int pro_group_a; + int chipset; drm_via_irq_t via_irqs[VIA_NUM_IRQS]; unsigned num_irqs; maskarray_t *irq_masks; @@ -96,8 +96,9 @@ typedef struct drm_via_private { } drm_via_private_t; enum via_family { - VIA_OTHER = 0, - VIA_PRO_GROUP_A, + VIA_OTHER = 0, /* Baseline */ + VIA_PRO_GROUP_A, /* Another video engine and DMA commands */ + VIA_DX9_0 /* Same video as pro_group_a, but 3D is unsupported */ }; /* VIA MMIO register access */ diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c index c33d068cde19..1ac5941ad237 100644 --- a/drivers/char/drm/via_irq.c +++ b/drivers/char/drm/via_irq.c @@ -258,12 +258,16 @@ void via_driver_irq_preinstall(drm_device_t * dev) dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE; dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING; - dev_priv->irq_masks = (dev_priv->pro_group_a) ? - via_pro_group_a_irqs : via_unichrome_irqs; - dev_priv->num_irqs = (dev_priv->pro_group_a) ? - via_num_pro_group_a : via_num_unichrome; - dev_priv->irq_map = (dev_priv->pro_group_a) ? - via_irqmap_pro_group_a : via_irqmap_unichrome; + if (dev_priv->chipset == VIA_PRO_GROUP_A || + dev_priv->chipset == VIA_DX9_0) { + dev_priv->irq_masks = via_pro_group_a_irqs; + dev_priv->num_irqs = via_num_pro_group_a; + dev_priv->irq_map = via_irqmap_pro_group_a; + } else { + dev_priv->irq_masks = via_unichrome_irqs; + dev_priv->num_irqs = via_num_unichrome; + dev_priv->irq_map = via_irqmap_unichrome; + } for (i = 0; i < dev_priv->num_irqs; ++i) { atomic_set(&cur_irq->irq_received, 0); diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c index 782011e0a58d..4e3fc072aa3b 100644 --- a/drivers/char/drm/via_map.c +++ b/drivers/char/drm/via_map.c @@ -106,8 +106,7 @@ int via_driver_load(drm_device_t *dev, unsigned long chipset) dev->dev_private = (void *)dev_priv; - if (chipset == VIA_PRO_GROUP_A) - dev_priv->pro_group_a = 1; + dev_priv->chipset = chipset; ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); if (ret) { diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c index 70c897c88766..2e7e08078287 100644 --- a/drivers/char/drm/via_verifier.c +++ b/drivers/char/drm/via_verifier.c @@ -306,6 +306,7 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq) unsigned long lo = ~0, hi = 0, tmp; uint32_t *addr, *pitch, *height, tex; unsigned i; + int npot; if (end > 9) end = 9; @@ -316,12 +317,15 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq) &(cur_seq->t_addr[tex = cur_seq->texture][start]); pitch = &(cur_seq->pitch[tex][start]); height = &(cur_seq->height[tex][start]); - + npot = cur_seq->tex_npot[tex]; for (i = start; i <= end; ++i) { tmp = *addr++; if (tmp < lo) lo = tmp; - tmp += (*height++ << *pitch++); + if (i == 0 && npot) + tmp += (*height++ * *pitch++); + else + tmp += (*height++ << *pitch++); if (tmp > hi) hi = tmp; } @@ -443,13 +447,21 @@ investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t * cur_seq) return 0; case check_texture_addr3: cur_seq->unfinished = tex_address; - tmp = ((cmd >> 24) - 0x2B); - cur_seq->pitch[cur_seq->texture][tmp] = - (cmd & 0x00F00000) >> 20; - if (!tmp && (cmd & 0x000FFFFF)) { - DRM_ERROR - ("Unimplemented texture level 0 pitch mode.\n"); - return 2; + tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit); + if (tmp == 0 && + (cmd & HC_HTXnEnPit_MASK)) { + cur_seq->pitch[cur_seq->texture][tmp] = + (cmd & HC_HTXnLnPit_MASK); + cur_seq->tex_npot[cur_seq->texture] = 1; + } else { + cur_seq->pitch[cur_seq->texture][tmp] = + (cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT; + cur_seq->tex_npot[cur_seq->texture] = 0; + if (cmd & 0x000FFFFF) { + DRM_ERROR + ("Unimplemented texture level 0 pitch mode.\n"); + return 2; + } } return 0; case check_texture_addr4: @@ -961,7 +973,13 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, uint32_t cmd; const uint32_t *buf_end = buf + (size >> 2); verifier_state_t state = state_command; - int pro_group_a = dev_priv->pro_group_a; + int cme_video; + int supported_3d; + + cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A || + dev_priv->chipset == VIA_DX9_0); + + supported_3d = dev_priv->chipset != VIA_DX9_0; hc_state->dev = dev; hc_state->unfinished = no_sequence; @@ -986,17 +1004,21 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, state = via_check_vheader6(&buf, buf_end); break; case state_command: - if (HALCYON_HEADER2 == (cmd = *buf)) + if ((HALCYON_HEADER2 == (cmd = *buf)) && + supported_3d) state = state_header2; else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) state = state_header1; - else if (pro_group_a + else if (cme_video && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) state = state_vheader5; - else if (pro_group_a + else if (cme_video && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) state = state_vheader6; - else { + else if ((cmd == HALCYON_HEADER2) && !supported_3d) { + DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n"); + state = state_error; + } else { DRM_ERROR ("Invalid / Unimplemented DMA HEADER command. 0x%x\n", cmd); diff --git a/drivers/char/drm/via_verifier.h b/drivers/char/drm/via_verifier.h index 256590fcc22a..b77f59df0278 100644 --- a/drivers/char/drm/via_verifier.h +++ b/drivers/char/drm/via_verifier.h @@ -43,6 +43,7 @@ typedef struct { uint32_t tex_level_lo[2]; uint32_t tex_level_hi[2]; uint32_t tex_palette_size[2]; + uint32_t tex_npot[2]; drm_via_sequence_t unfinished; int agp_texture; int multitex; 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/crypto/Kconfig b/drivers/crypto/Kconfig index 879250d3d069..ff8c4beaace4 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -51,6 +51,8 @@ config CRYPTO_DEV_PADLOCK_SHA If unsure say M. The compiled module will be called padlock-sha.ko +source "arch/s390/crypto/Kconfig" + config CRYPTO_DEV_GEODE tristate "Support for the Geode LX AES engine" depends on CRYPTO && X86_32 && PCI 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/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..52e97d8f3c95 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -1,15 +1,8 @@ # # Makefile for the HID driver # - -# Multipart objects. -hid-objs := hid-core.o hid-input.o - -# Optional parts of multipart objects. +hid-objs := hid-core.o hid-input.o obj-$(CONFIG_HID) += hid.o - -ifeq ($(CONFIG_INPUT_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +hid-$(CONFIG_HID_DEBUG) += hid-debug.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 49f18f5b2514..8c7d48eff7b7 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -28,11 +28,9 @@ #include #include -#undef DEBUG -#undef DEBUG_DATA - #include #include +#include /* * Version Information @@ -951,7 +949,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i return -1; } -#ifdef DEBUG_DATA +#ifdef CONFIG_HID_DEBUG printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); #endif @@ -961,7 +959,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i size--; } -#ifdef DEBUG_DATA +#ifdef CONFIG_HID_DEBUG { int i; printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, size); diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c new file mode 100644 index 000000000000..89241be4ec9b --- /dev/null +++ b/drivers/hid/hid-debug.c @@ -0,0 +1,764 @@ +/* + * $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 + +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 c7a6833f6821..25d180a24fc4 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -31,9 +31,8 @@ #include #include -#undef DEBUG - #include +#include static int hid_pb_fnmode = 1; module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644); @@ -252,9 +251,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel field->hidinput = hidinput; -#ifdef DEBUG +#ifdef CONFIG_HID_DEBUG printk(KERN_DEBUG "Mapping: "); - resolv_usage(usage->hid); + hid_resolv_usage(usage->hid); printk(" ---> "); #endif @@ -682,14 +681,14 @@ 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; ignore: -#ifdef DEBUG +#ifdef CONFIG_HID_DEBUG printk("IGNORED\n"); #endif return; @@ -804,6 +803,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 @@ -816,6 +827,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 +840,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) @@ -846,8 +861,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/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/ide/Kconfig b/drivers/ide/Kconfig index 3f828052f8d2..ec03341d2bd8 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -167,6 +167,13 @@ config BLK_DEV_IDECS Support for Compact Flash cards, outboard IDE disks, tape drives, and CD-ROM drives connected through a PCMCIA card. +config BLK_DEV_DELKIN + tristate "Cardbus IDE support (Delkin/ASKA/Workbit)" + depends on CARDBUS && PCI + help + Support for Delkin, ASKA, and Workbit Cardbus CompactFlash + Adapters. This may also work for similar SD and XD adapters. + config BLK_DEV_IDECD tristate "Include IDE/ATAPI CDROM support" ---help--- @@ -264,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 @@ -606,6 +620,11 @@ config BLK_DEV_PIIX the kernel to change PIO, DMA and UDMA speeds and to configure the chip to optimum performance. +config BLK_DEV_IT8213 + tristate "IT8213 IDE support" + help + This driver adds support for the ITE 8213 IDE controller. + config BLK_DEV_IT821X tristate "IT821X IDE support" help @@ -742,6 +761,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/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..17aea65d7dd2 --- /dev/null +++ b/drivers/ide/ide-acpi.c @@ -0,0 +1,697 @@ +/* + * 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%zx] 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/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile index fef08960aa4c..6591ff4753cb 100644 --- a/drivers/ide/pci/Makefile +++ b/drivers/ide/pci/Makefile @@ -9,9 +9,10 @@ obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o +obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o -#obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o +obj-$(CONFIG_BLK_DEV_IT8213) += it8213.o obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o @@ -26,6 +27,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/delkin_cb.c b/drivers/ide/pci/delkin_cb.c new file mode 100644 index 000000000000..e2672fc65d30 --- /dev/null +++ b/drivers/ide/pci/delkin_cb.c @@ -0,0 +1,140 @@ +/* + * linux/drivers/ide/pci/delkin_cb.c + * + * Created 20 Oct 2004 by Mark Lord + * + * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter + * + * Modeled after the 16-bit PCMCIA driver: ide-cs.c + * + * This is slightly peculiar, in that it is a PCI driver, + * but is NOT an IDE PCI driver -- the IDE layer does not directly + * support hot insertion/removal of PCI interfaces, so this driver + * is unable to use the IDE PCI interfaces. Instead, it uses the + * same interfaces as the ide-cs (PCMCIA) driver uses. + * On the plus side, the driver is also smaller/simpler this way. + * + * 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 + +/* + * No chip documentation has yet been found, + * so these configuration values were pulled from + * a running Win98 system using "debug". + * This gives around 3MByte/second read performance, + * which is about 2/3 of what the chip is capable of. + * + * There is also a 4KByte mmio region on the card, + * but its purpose has yet to be reverse-engineered. + */ +static const u8 setup[] = { + 0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00, + 0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13, +}; + +static int __devinit +delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) +{ + unsigned long base; + hw_regs_t hw; + ide_hwif_t *hwif = NULL; + ide_drive_t *drive; + int i, rc; + + rc = pci_enable_device(dev); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc); + return rc; + } + rc = pci_request_regions(dev, "delkin_cb"); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc); + pci_disable_device(dev); + return rc; + } + base = pci_resource_start(dev, 0); + outb(0x02, base + 0x1e); /* set nIEN to block interrupts */ + inb(base + 0x17); /* read status to clear interrupts */ + for (i = 0; i < sizeof(setup); ++i) { + if (setup[i]) + outb(setup[i], base + i); + } + pci_release_regions(dev); /* IDE layer handles regions itself */ + + memset(&hw, 0, sizeof(hw)); + ide_std_init_ports(&hw, base + 0x10, base + 0x1e); + hw.irq = dev->irq; + hw.chipset = ide_pci; /* this enables IRQ sharing */ + + rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave); + if (rc < 0) { + printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc); + pci_disable_device(dev); + return -ENODEV; + } + pci_set_drvdata(dev, hwif); + hwif->pci_dev = dev; + drive = &hwif->drives[0]; + if (drive->present) { + drive->io_32bit = 1; + drive->unmask = 1; + } + return 0; +} + +static void +delkin_cb_remove (struct pci_dev *dev) +{ + ide_hwif_t *hwif = pci_get_drvdata(dev); + + if (hwif) + ide_unregister(hwif->index); + pci_disable_device(dev); +} + +static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = { + { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl); + +static struct pci_driver driver = { + .name = "Delkin-ASKA-Workbit Cardbus IDE", + .id_table = delkin_cb_pci_tbl, + .probe = delkin_cb_probe, + .remove = delkin_cb_remove, +}; + +static int +delkin_cb_init (void) +{ + return pci_module_init(&driver); +} + +static void +delkin_cb_exit (void) +{ + pci_unregister_driver(&driver); +} + +module_init(delkin_cb_init); +module_exit(delkin_cb_exit); + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index b486442dd5d7..05be8fadda7a 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003 + * linux/drivers/ide/pci/hpt366.c Version 1.01 Dec 23, 2006 * * Copyright (C) 1999-2003 Andre Hedrick * Portions Copyright (C) 2001 Sun Microsystems, Inc. @@ -60,13 +60,10 @@ * channel caused the cached register value to get out of sync with the * actual one, the channels weren't serialized, the turnaround shouldn't * be done on 66 MHz PCI bus - * - avoid calibrating PLL twice as the second time results in a wrong PCI - * frequency and thus in the wrong timings for the secondary channel - * - disable UltraATA/133 for HPT372 by default (50 MHz DPLL clock do not - * allow for this speed anyway) - * - add support for HPT302N and HPT371N clocking (the same as for HPT372N) - * - HPT371/N are single channel chips, so avoid touching the primary channel - * which exists only virtually (there's no pins for it) + * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used + * does not allow for this speed anyway + * - avoid touching disabled channels (e.g. HPT371/N are single channel chips, + * their primary channel is kind of virtual, it isn't tied to any pins) * - fix/remove bad/unused timing tables and use one set of tables for the whole * HPT37x chip family; save space by introducing the separate transfer mode * table in which the mode lookup is done @@ -76,11 +73,47 @@ * and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead * - pass to init_chipset() handlers a copy of the IDE PCI device structure as * they tamper with its fields - * - * + * - pass to the init_setup handlers a copy of the ide_pci_device_t structure + * since they may tamper with its fields + * - prefix the driver startup messages with the real chip name + * - claim the extra 240 bytes of I/O space for all chips + * - optimize the rate masking/filtering and the drive list lookup code + * - use pci_get_slot() to get to the function 1 of HPT36x/374 + * - cache offset of the channel's misc. control registers (MCRs) being used + * throughout the driver + * - only touch the relevant MCR when detecting the cable type on HPT374's + * function 1 + * - rename all the register related variables consistently + * - move all the interrupt twiddling code from the speedproc handlers into + * init_hwif_hpt366(), also grouping all the DMA related code together there + * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and + * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings + * when setting an UltraDMA mode + * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select + * the best possible one + * - clean up DMA timeout handling for HPT370 + * - switch to using the enumeration type to differ between the numerous chip + * variants, matching PCI device/revision ID with the chip type early, at the + * init_setup stage + * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies, + * stop duplicating it for each channel by storing the pointer in the pci_dev + * structure: first, at the init_setup stage, point it to a static "template" + * with only the chip type and its specific base DPLL frequency, the highest + * supported DMA mode, and the chip settings table pointer filled, then, at + * the init_chipset stage, allocate per-chip instance and fill it with the + * rest of the necessary information + * - get rid of the constant thresholds in the HPT37x PCI clock detection code, + * switch to calculating PCI clock frequency based on the chip's base DPLL + * frequency + * - switch to using the DPLL clock and enable UltraATA/133 mode by default on + * anything newer than HPT370/A + * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(), + * also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips; + * unify HPT36x/37x timing setup code and the speedproc handlers by joining + * the register setting lists into the table indexed by the clock selected + * Sergei Shtylyov, or */ - #include #include #include @@ -332,93 +365,159 @@ static u32 sixty_six_base_hpt37x[] = { }; #define HPT366_DEBUG_DRIVE_INFO 0 -#define HPT374_ALLOW_ATA133_6 0 -#define HPT371_ALLOW_ATA133_6 0 -#define HPT302_ALLOW_ATA133_6 0 -#define HPT372_ALLOW_ATA133_6 0 -#define HPT370_ALLOW_ATA100_5 1 +#define HPT374_ALLOW_ATA133_6 1 +#define HPT371_ALLOW_ATA133_6 1 +#define HPT302_ALLOW_ATA133_6 1 +#define HPT372_ALLOW_ATA133_6 1 +#define HPT370_ALLOW_ATA100_5 0 #define HPT366_ALLOW_ATA66_4 1 #define HPT366_ALLOW_ATA66_3 1 #define HPT366_MAX_DEVS 8 -#define F_LOW_PCI_33 0x23 -#define F_LOW_PCI_40 0x29 -#define F_LOW_PCI_50 0x2d -#define F_LOW_PCI_66 0x42 - -/* - * Hold all the highpoint quirks and revision information in one - * place. - */ - -struct hpt_info -{ - u8 max_mode; /* Speeds allowed */ - int revision; /* Chipset revision */ - int flags; /* Chipset properties */ -#define PLL_MODE 1 -#define IS_3xxN 2 -#define PCI_66MHZ 4 - /* Speed table */ - u32 *speed; +/* Supported ATA clock frequencies */ +enum ata_clock { + ATA_CLOCK_25MHZ, + ATA_CLOCK_33MHZ, + ATA_CLOCK_40MHZ, + ATA_CLOCK_50MHZ, + ATA_CLOCK_66MHZ, + NUM_ATA_CLOCKS }; /* - * This wants fixing so that we do everything not by classrev - * (which breaks on the newest chips) but by creating an - * enumeration of chip variants and using that + * Hold all the HighPoint chip information in one place. */ -static __devinit u32 hpt_revision (struct pci_dev *dev) -{ - u32 class_rev; - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; +struct hpt_info { + u8 chip_type; /* Chip type */ + u8 max_mode; /* Speeds allowed */ + u8 dpll_clk; /* DPLL clock in MHz */ + u8 pci_clk; /* PCI clock in MHz */ + u32 **settings; /* Chipset settings table */ +}; - switch(dev->device) { - /* Remap new 372N onto 372 */ - case PCI_DEVICE_ID_TTI_HPT372N: - class_rev = PCI_DEVICE_ID_TTI_HPT372; break; - case PCI_DEVICE_ID_TTI_HPT374: - class_rev = PCI_DEVICE_ID_TTI_HPT374; break; - case PCI_DEVICE_ID_TTI_HPT371: - class_rev = PCI_DEVICE_ID_TTI_HPT371; break; - case PCI_DEVICE_ID_TTI_HPT302: - class_rev = PCI_DEVICE_ID_TTI_HPT302; break; - case PCI_DEVICE_ID_TTI_HPT372: - class_rev = PCI_DEVICE_ID_TTI_HPT372; break; - default: - break; - } - return class_rev; +/* Supported HighPoint chips */ +enum { + HPT36x, + HPT370, + HPT370A, + HPT374, + HPT372, + HPT372A, + HPT302, + HPT371, + HPT372N, + HPT302N, + HPT371N +}; + +static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = { + twenty_five_base_hpt36x, + thirty_three_base_hpt36x, + forty_base_hpt36x, + NULL, + NULL +}; + +static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = { + NULL, + thirty_three_base_hpt37x, + NULL, + fifty_base_hpt37x, + sixty_six_base_hpt37x +}; + +static struct hpt_info hpt36x __devinitdata = { + .chip_type = HPT36x, + .max_mode = (HPT366_ALLOW_ATA66_4 || HPT366_ALLOW_ATA66_3) ? 2 : 1, + .dpll_clk = 0, /* no DPLL */ + .settings = hpt36x_settings +}; + +static struct hpt_info hpt370 __devinitdata = { + .chip_type = HPT370, + .max_mode = HPT370_ALLOW_ATA100_5 ? 3 : 2, + .dpll_clk = 48, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt370a __devinitdata = { + .chip_type = HPT370A, + .max_mode = HPT370_ALLOW_ATA100_5 ? 3 : 2, + .dpll_clk = 48, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt374 __devinitdata = { + .chip_type = HPT374, + .max_mode = HPT374_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 48, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt372 __devinitdata = { + .chip_type = HPT372, + .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 55, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt372a __devinitdata = { + .chip_type = HPT372A, + .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 66, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt302 __devinitdata = { + .chip_type = HPT302, + .max_mode = HPT302_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 66, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt371 __devinitdata = { + .chip_type = HPT371, + .max_mode = HPT371_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 66, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt372n __devinitdata = { + .chip_type = HPT372N, + .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 77, + .settings = hpt37x_settings +}; + +static struct hpt_info hpt302n __devinitdata = { + .chip_type = HPT302N, + .max_mode = HPT302_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 77, +}; + +static struct hpt_info hpt371n __devinitdata = { + .chip_type = HPT371N, + .max_mode = HPT371_ALLOW_ATA133_6 ? 4 : 3, + .dpll_clk = 77, + .settings = hpt37x_settings +}; + +static int check_in_drive_list(ide_drive_t *drive, const char **list) +{ + struct hd_driveid *id = drive->id; + + while (*list) + if (!strcmp(*list++,id->model)) + return 1; + return 0; } -static int check_in_drive_lists(ide_drive_t *drive, const char **list); - -static u8 hpt3xx_ratemask (ide_drive_t *drive) +static u8 hpt3xx_ratemask(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 mode = 0; + struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev); + u8 mode = info->max_mode; - /* FIXME: TODO - move this to set info->mode once at boot */ - - if (info->revision >= 8) { /* HPT374 */ - mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3; - } else if (info->revision >= 7) { /* HPT371 */ - mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3; - } else if (info->revision >= 6) { /* HPT302 */ - mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3; - } else if (info->revision >= 5) { /* HPT372 */ - mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3; - } else if (info->revision >= 4) { /* HPT370A */ - mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2; - } else if (info->revision >= 3) { /* HPT370 */ - mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2; - mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode; - } else { /* HPT366 and HPT368 */ - mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2; - } if (!eighty_ninty_three(drive) && mode) mode = min(mode, (u8)1); return mode; @@ -429,75 +528,61 @@ static u8 hpt3xx_ratemask (ide_drive_t *drive) * either PIO or UDMA modes 0,4,5 */ -static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed) +static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed) { - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); + struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev); + u8 chip_type = info->chip_type; u8 mode = hpt3xx_ratemask(drive); if (drive->media != ide_disk) return min(speed, (u8)XFER_PIO_4); - switch(mode) { + switch (mode) { case 0x04: - speed = min(speed, (u8)XFER_UDMA_6); + speed = min_t(u8, speed, XFER_UDMA_6); break; case 0x03: - speed = min(speed, (u8)XFER_UDMA_5); - if (info->revision >= 5) + speed = min_t(u8, speed, XFER_UDMA_5); + if (chip_type >= HPT374) break; - if (check_in_drive_lists(drive, bad_ata100_5)) - speed = min(speed, (u8)XFER_UDMA_4); - break; + if (!check_in_drive_list(drive, bad_ata100_5)) + goto check_bad_ata33; + /* fall thru */ case 0x02: - speed = min(speed, (u8)XFER_UDMA_4); - /* - * CHECK ME, Does this need to be set to 5 ?? - */ - if (info->revision >= 3) - break; - if ((check_in_drive_lists(drive, bad_ata66_4)) || - (!(HPT366_ALLOW_ATA66_4))) - speed = min(speed, (u8)XFER_UDMA_3); - if ((check_in_drive_lists(drive, bad_ata66_3)) || - (!(HPT366_ALLOW_ATA66_3))) - speed = min(speed, (u8)XFER_UDMA_2); - break; + speed = min_t(u8, speed, XFER_UDMA_4); + + /* + * CHECK ME, Does this need to be changed to HPT374 ?? + */ + if (chip_type >= HPT370) + goto check_bad_ata33; + if (HPT366_ALLOW_ATA66_4 && + !check_in_drive_list(drive, bad_ata66_4)) + goto check_bad_ata33; + + speed = min_t(u8, speed, XFER_UDMA_3); + if (HPT366_ALLOW_ATA66_3 && + !check_in_drive_list(drive, bad_ata66_3)) + goto check_bad_ata33; + /* fall thru */ case 0x01: - speed = min(speed, (u8)XFER_UDMA_2); - /* - * CHECK ME, Does this need to be set to 5 ?? - */ - if (info->revision >= 3) + speed = min_t(u8, speed, XFER_UDMA_2); + + check_bad_ata33: + if (chip_type >= HPT370A) break; - if (check_in_drive_lists(drive, bad_ata33)) - speed = min(speed, (u8)XFER_MW_DMA_2); - break; + if (!check_in_drive_list(drive, bad_ata33)) + break; + /* fall thru */ case 0x00: default: - speed = min(speed, (u8)XFER_MW_DMA_2); + speed = min_t(u8, speed, XFER_MW_DMA_2); break; } return speed; } -static int check_in_drive_lists (ide_drive_t *drive, const char **list) -{ - struct hd_driveid *id = drive->id; - - if (quirk_drives == list) { - while (*list) - if (strstr(id->model, *list++)) - return 1; - } else { - while (*list) - if (!strcmp(*list++,id->model)) - return 1; - } - return 0; -} - -static u32 pci_bus_clock_list(u8 speed, u32 *chipset_table) +static u32 get_speed_setting(u8 speed, struct hpt_info *info) { int i; @@ -510,228 +595,161 @@ static u32 pci_bus_clock_list(u8 speed, u32 *chipset_table) for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++) if (xfer_speeds[i] == speed) break; - return chipset_table[i]; + /* + * NOTE: info->settings only points to the pointer + * to the list of the actual register values + */ + return (*info->settings)[i]; } static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed) { - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 speed = hpt3xx_ratefilter(drive, xferspeed); - u8 regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40; - u8 regfast = (hwif->channel) ? 0x55 : 0x51; - u8 drive_fast = 0; - u32 reg1 = 0, reg2 = 0; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = pci_get_drvdata(dev); + u8 speed = hpt3xx_ratefilter(drive, xferspeed); + u8 itr_addr = drive->dn ? 0x44 : 0x40; + u32 itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 : + (speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff); + u32 new_itr = get_speed_setting(speed, info); + u32 old_itr = 0; /* - * Disable the "fast interrupt" prediction. + * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well) + * to avoid problems handling I/O errors later */ - pci_read_config_byte(dev, regfast, &drive_fast); - if (drive_fast & 0x80) - pci_write_config_byte(dev, regfast, drive_fast & ~0x80); + pci_read_config_dword(dev, itr_addr, &old_itr); + new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask); + new_itr &= ~0xc0000000; - reg2 = pci_bus_clock_list(speed, info->speed); - - /* - * Disable on-chip PIO FIFO/buffer - * (to avoid problems handling I/O errors later) - */ - pci_read_config_dword(dev, regtime, ®1); - if (speed >= XFER_MW_DMA_0) { - reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000); - } else { - reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000); - } - reg2 &= ~0x80000000; - - pci_write_config_dword(dev, regtime, reg2); + pci_write_config_dword(dev, itr_addr, new_itr); return ide_config_drive_speed(drive, speed); } -static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed) +static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed) { - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 speed = hpt3xx_ratefilter(drive, xferspeed); - u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51; - u8 drive_pci = 0x40 + (drive->dn * 4); - u8 new_fast = 0, drive_fast = 0; - u32 list_conf = 0, drive_conf = 0; - u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = pci_get_drvdata(dev); + u8 speed = hpt3xx_ratefilter(drive, xferspeed); + u8 itr_addr = 0x40 + (drive->dn * 4); + u32 itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 : + (speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff); + u32 new_itr = get_speed_setting(speed, info); + u32 old_itr = 0; - /* - * Disable the "fast interrupt" prediction. - * don't holdoff on interrupts. (== 0x01 despite what the docs say) - */ - pci_read_config_byte(dev, regfast, &drive_fast); - new_fast = drive_fast; - if (new_fast & 0x02) - new_fast &= ~0x02; - -#ifdef HPT_DELAY_INTERRUPT - if (new_fast & 0x01) - new_fast &= ~0x01; -#else - if ((new_fast & 0x01) == 0) - new_fast |= 0x01; -#endif - if (new_fast != drive_fast) - pci_write_config_byte(dev, regfast, new_fast); - - list_conf = pci_bus_clock_list(speed, info->speed); - - pci_read_config_dword(dev, drive_pci, &drive_conf); - list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); + pci_read_config_dword(dev, itr_addr, &old_itr); + new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask); if (speed < XFER_MW_DMA_0) - list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ - pci_write_config_dword(dev, drive_pci, list_conf); + new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ + pci_write_config_dword(dev, itr_addr, new_itr); return ide_config_drive_speed(drive, speed); } -static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed) +static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed) { - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 speed = hpt3xx_ratefilter(drive, xferspeed); - u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51; - u8 drive_fast = 0, drive_pci = 0x40 + (drive->dn * 4); - u32 list_conf = 0, drive_conf = 0; - u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000; + ide_hwif_t *hwif = HWIF(drive); + struct hpt_info *info = pci_get_drvdata(hwif->pci_dev); - /* - * Disable the "fast interrupt" prediction. - * don't holdoff on interrupts. (== 0x01 despite what the docs say) - */ - pci_read_config_byte(dev, regfast, &drive_fast); - drive_fast &= ~0x07; - pci_write_config_byte(dev, regfast, drive_fast); - - list_conf = pci_bus_clock_list(speed, info->speed); - pci_read_config_dword(dev, drive_pci, &drive_conf); - list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); - if (speed < XFER_MW_DMA_0) - list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ - pci_write_config_dword(dev, drive_pci, list_conf); - - return ide_config_drive_speed(drive, speed); -} - -static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed) -{ - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); - - if (info->revision >= 8) - return hpt372_tune_chipset(drive, speed); /* not a typo */ - else if (info->revision >= 5) - return hpt372_tune_chipset(drive, speed); - else if (info->revision >= 3) - return hpt370_tune_chipset(drive, speed); + if (info->chip_type >= HPT370) + return hpt37x_tune_chipset(drive, speed); else /* hpt368: hpt_minimum_revision(dev, 2) */ return hpt36x_tune_chipset(drive, speed); } -static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio) +static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio) { - pio = ide_get_best_pio_mode(drive, 255, pio, NULL); - (void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio)); + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio); } /* * This allows the configuration of ide_pci chipset registers * for cards that learn about the drive's UDMA, DMA, PIO capabilities - * after the drive is reported by the OS. Initially for designed for + * after the drive is reported by the OS. Initially designed for * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc. * - * check_in_drive_lists(drive, bad_ata66_4) - * check_in_drive_lists(drive, bad_ata66_3) - * check_in_drive_lists(drive, bad_ata33) - * */ -static int config_chipset_for_dma (ide_drive_t *drive) +static int config_chipset_for_dma(ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive)); - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); if (!speed) return 0; - /* If we don't have any timings we can't do a lot */ - if (info->speed == NULL) - return 0; - (void) hpt3xx_tune_chipset(drive, speed); return ide_dma_enable(drive); } -static int hpt3xx_quirkproc (ide_drive_t *drive) +static int hpt3xx_quirkproc(ide_drive_t *drive) { - return ((int) check_in_drive_lists(drive, quirk_drives)); + struct hd_driveid *id = drive->id; + const char **list = quirk_drives; + + while (*list) + if (strstr(id->model, *list++)) + return 1; + return 0; } -static void hpt3xx_intrproc (ide_drive_t *drive) +static void hpt3xx_intrproc(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = HWIF(drive); if (drive->quirk_list) return; /* drives in the quirk_list may not like intr setups/cleanups */ - hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG); + hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG); } -static void hpt3xx_maskproc (ide_drive_t *drive, int mask) +static void hpt3xx_maskproc(ide_drive_t *drive, int mask) { - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); - struct pci_dev *dev = hwif->pci_dev; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = pci_get_drvdata(dev); if (drive->quirk_list) { - if (info->revision >= 3) { - u8 reg5a = 0; - pci_read_config_byte(dev, 0x5a, ®5a); - if (((reg5a & 0x10) >> 4) != mask) - pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10)); - } else { - if (mask) { - disable_irq(hwif->irq); - } else { - enable_irq(hwif->irq); + if (info->chip_type >= HPT370) { + u8 scr1 = 0; + + pci_read_config_byte(dev, 0x5a, &scr1); + if (((scr1 & 0x10) >> 4) != mask) { + if (mask) + scr1 |= 0x10; + else + scr1 &= ~0x10; + pci_write_config_byte(dev, 0x5a, scr1); } + } else { + if (mask) + disable_irq(hwif->irq); + else + enable_irq (hwif->irq); } - } else { - if (IDE_CONTROL_REG) - hwif->OUTB(mask ? (drive->ctl | 2) : - (drive->ctl & ~2), - IDE_CONTROL_REG); - } + } else + hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2), + IDE_CONTROL_REG); } -static int hpt366_config_drive_xfer_rate (ide_drive_t *drive) +static int hpt366_config_drive_xfer_rate(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = HWIF(drive); struct hd_driveid *id = drive->id; drive->init_speed = 0; if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } + 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: - hpt3xx_tune_drive(drive, 5); + hpt3xx_tune_drive(drive, 255); return hwif->ide_dma_off_quietly(drive); } /* IORDY not supported */ @@ -739,31 +757,48 @@ fast_ata_pio: } /* - * This is specific to the HPT366 UDMA bios chipset + * This is specific to the HPT366 UDMA chipset * by HighPoint|Triones Technologies, Inc. */ -static int hpt366_ide_dma_lostirq (ide_drive_t *drive) +static int hpt366_ide_dma_lostirq(ide_drive_t *drive) { - struct pci_dev *dev = HWIF(drive)->pci_dev; - u8 reg50h = 0, reg52h = 0, reg5ah = 0; + struct pci_dev *dev = HWIF(drive)->pci_dev; + u8 mcr1 = 0, mcr3 = 0, scr1 = 0; - pci_read_config_byte(dev, 0x50, ®50h); - pci_read_config_byte(dev, 0x52, ®52h); - pci_read_config_byte(dev, 0x5a, ®5ah); - printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n", - drive->name, __FUNCTION__, reg50h, reg52h, reg5ah); - if (reg5ah & 0x10) - pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10); + pci_read_config_byte(dev, 0x50, &mcr1); + pci_read_config_byte(dev, 0x52, &mcr3); + pci_read_config_byte(dev, 0x5a, &scr1); + printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n", + drive->name, __FUNCTION__, mcr1, mcr3, scr1); + if (scr1 & 0x10) + pci_write_config_byte(dev, 0x5a, scr1 & ~0x10); return __ide_dma_lostirq(drive); } -static void hpt370_clear_engine (ide_drive_t *drive) +static void hpt370_clear_engine(ide_drive_t *drive) { - u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50; - pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37); + ide_hwif_t *hwif = HWIF(drive); + + pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37); udelay(10); } +static void hpt370_irq_timeout(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + u16 bfifo = 0; + u8 dma_cmd; + + pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo); + printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff); + + /* get DMA command mode */ + dma_cmd = hwif->INB(hwif->dma_command); + /* stop DMA */ + hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command); + hpt370_clear_engine(drive); +} + static void hpt370_ide_dma_start(ide_drive_t *drive) { #ifdef HPT_RESET_STATE_ENGINE @@ -772,64 +807,35 @@ static void hpt370_ide_dma_start(ide_drive_t *drive) ide_dma_start(drive); } -static int hpt370_ide_dma_end (ide_drive_t *drive) +static int hpt370_ide_dma_end(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - u8 dma_stat = hwif->INB(hwif->dma_status); + u8 dma_stat = hwif->INB(hwif->dma_status); if (dma_stat & 0x01) { /* wait a little */ udelay(20); dma_stat = hwif->INB(hwif->dma_status); + if (dma_stat & 0x01) + hpt370_irq_timeout(drive); } - if ((dma_stat & 0x01) != 0) - /* fallthrough */ - (void) HWIF(drive)->ide_dma_timeout(drive); - return __ide_dma_end(drive); } -static void hpt370_lostirq_timeout (ide_drive_t *drive) +static int hpt370_ide_dma_timeout(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - u8 bfifo = 0, reginfo = hwif->channel ? 0x56 : 0x52; - u8 dma_stat = 0, dma_cmd = 0; - - pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo); - printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo); - hpt370_clear_engine(drive); - /* get dma command mode */ - dma_cmd = hwif->INB(hwif->dma_command); - /* stop dma */ - hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command); - dma_stat = hwif->INB(hwif->dma_status); - /* clear errors */ - hwif->OUTB(dma_stat | 0x6, hwif->dma_status); -} - -static int hpt370_ide_dma_timeout (ide_drive_t *drive) -{ - hpt370_lostirq_timeout(drive); - hpt370_clear_engine(drive); + hpt370_irq_timeout(drive); return __ide_dma_timeout(drive); } -static int hpt370_ide_dma_lostirq (ide_drive_t *drive) -{ - hpt370_lostirq_timeout(drive); - hpt370_clear_engine(drive); - return __ide_dma_lostirq(drive); -} - /* returns 1 if DMA IRQ issued, 0 otherwise */ static int hpt374_ide_dma_test_irq(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); u16 bfifo = 0; - u8 reginfo = hwif->channel ? 0x56 : 0x52; - u8 dma_stat; + u8 dma_stat; - pci_read_config_word(hwif->pci_dev, reginfo, &bfifo); + pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo); if (bfifo & 0x1FF) { // printk("%s: %d bytes in FIFO\n", drive->name, bfifo); return 0; @@ -837,7 +843,7 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive) dma_stat = hwif->INB(hwif->dma_status); /* return 1 if INTR asserted */ - if ((dma_stat & 4) == 4) + if (dma_stat & 4) return 1; if (!drive->waiting_for_dma) @@ -846,17 +852,17 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive) return 0; } -static int hpt374_ide_dma_end (ide_drive_t *drive) +static int hpt374_ide_dma_end(ide_drive_t *drive) { - struct pci_dev *dev = HWIF(drive)->pci_dev; ide_hwif_t *hwif = HWIF(drive); - u8 msc_stat = 0, mscreg = hwif->channel ? 0x54 : 0x50; - u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01; + struct pci_dev *dev = hwif->pci_dev; + u8 mcr = 0, mcr_addr = hwif->select_data; + u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01; - pci_read_config_byte(dev, 0x6a, &bwsr_stat); - pci_read_config_byte(dev, mscreg, &msc_stat); - if ((bwsr_stat & bwsr_mask) == bwsr_mask) - pci_write_config_byte(dev, mscreg, msc_stat|0x30); + pci_read_config_byte(dev, 0x6a, &bwsr); + pci_read_config_byte(dev, mcr_addr, &mcr); + if (bwsr & mask) + pci_write_config_byte(dev, mcr_addr, mcr | 0x30); return __ide_dma_end(drive); } @@ -866,40 +872,37 @@ static int hpt374_ide_dma_end (ide_drive_t *drive) * @mode: clocking mode (0x21 for write, 0x23 otherwise) * * Switch the DPLL clock on the HPT3xxN devices. This is a right mess. - * NOTE: avoid touching the disabled primary channel on HPT371N -- it - * doesn't physically exist anyway... */ static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode) { - u8 mcr1, scr2 = hwif->INB(hwif->dma_master + 0x7b); + u8 scr2 = hwif->INB(hwif->dma_master + 0x7b); if ((scr2 & 0x7f) == mode) return; - /* MISC. control register 1 has the channel enable bit... */ - mcr1 = hwif->INB(hwif->dma_master + 0x70); - /* Tristate the bus */ - if (mcr1 & 0x04) - hwif->OUTB(0x80, hwif->dma_master + 0x73); + hwif->OUTB(0x80, hwif->dma_master + 0x73); hwif->OUTB(0x80, hwif->dma_master + 0x77); /* Switch clock and reset channels */ hwif->OUTB(mode, hwif->dma_master + 0x7b); hwif->OUTB(0xc0, hwif->dma_master + 0x79); - /* Reset state machines */ - if (mcr1 & 0x04) - hwif->OUTB(0x37, hwif->dma_master + 0x70); - hwif->OUTB(0x37, hwif->dma_master + 0x74); + /* + * Reset the state machines. + * NOTE: avoid accidentally enabling the disabled channels. + */ + hwif->OUTB(hwif->INB(hwif->dma_master + 0x70) | 0x32, + hwif->dma_master + 0x70); + hwif->OUTB(hwif->INB(hwif->dma_master + 0x74) | 0x32, + hwif->dma_master + 0x74); /* Complete reset */ hwif->OUTB(0x00, hwif->dma_master + 0x79); /* Reconnect channels to bus */ - if (mcr1 & 0x04) - hwif->OUTB(0x00, hwif->dma_master + 0x73); + hwif->OUTB(0x00, hwif->dma_master + 0x73); hwif->OUTB(0x00, hwif->dma_master + 0x77); } @@ -914,14 +917,12 @@ static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode) static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq) { - ide_hwif_t *hwif = HWIF(drive); - u8 wantclock = rq_data_dir(rq) ? 0x23 : 0x21; - - hpt3xxn_set_clock(hwif, wantclock); + hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21); } /* * Set/get power state for a drive. + * NOTE: affects both drives on each channel. * * When we turn the power back on, we need to re-initialize things. */ @@ -929,26 +930,18 @@ static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq) static int hpt3xx_busproc(ide_drive_t *drive, int state) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - u8 tristate, resetmask, bus_reg = 0; - u16 tri_reg = 0; + u8 mcr_addr = hwif->select_data + 2; + u8 resetmask = hwif->channel ? 0x80 : 0x40; + u8 bsr2 = 0; + u16 mcr = 0; hwif->bus_state = state; - if (hwif->channel) { - /* secondary channel */ - tristate = 0x56; - resetmask = 0x80; - } else { - /* primary channel */ - tristate = 0x52; - resetmask = 0x40; - } - /* Grab the status. */ - pci_read_config_word(dev, tristate, &tri_reg); - pci_read_config_byte(dev, 0x59, &bus_reg); + pci_read_config_word(dev, mcr_addr, &mcr); + pci_read_config_byte(dev, 0x59, &bsr2); /* * Set the state. We don't set it if we don't need to do so. @@ -956,22 +949,22 @@ static int hpt3xx_busproc(ide_drive_t *drive, int state) */ switch (state) { case BUSSTATE_ON: - if (!(bus_reg & resetmask)) + if (!(bsr2 & resetmask)) return 0; hwif->drives[0].failures = hwif->drives[1].failures = 0; - pci_write_config_byte(dev, 0x59, bus_reg & ~resetmask); - pci_write_config_word(dev, tristate, tri_reg & ~TRISTATE_BIT); + pci_write_config_byte(dev, 0x59, bsr2 & ~resetmask); + pci_write_config_word(dev, mcr_addr, mcr & ~TRISTATE_BIT); return 0; case BUSSTATE_OFF: - if ((bus_reg & resetmask) && !(tri_reg & TRISTATE_BIT)) + if ((bsr2 & resetmask) && !(mcr & TRISTATE_BIT)) return 0; - tri_reg &= ~TRISTATE_BIT; + mcr &= ~TRISTATE_BIT; break; case BUSSTATE_TRISTATE: - if ((bus_reg & resetmask) && (tri_reg & TRISTATE_BIT)) + if ((bsr2 & resetmask) && (mcr & TRISTATE_BIT)) return 0; - tri_reg |= TRISTATE_BIT; + mcr |= TRISTATE_BIT; break; default: return -EINVAL; @@ -980,223 +973,63 @@ static int hpt3xx_busproc(ide_drive_t *drive, int state) hwif->drives[0].failures = hwif->drives[0].max_failures + 1; hwif->drives[1].failures = hwif->drives[1].max_failures + 1; - pci_write_config_word(dev, tristate, tri_reg); - pci_write_config_byte(dev, 0x59, bus_reg | resetmask); + pci_write_config_word(dev, mcr_addr, mcr); + pci_write_config_byte(dev, 0x59, bsr2 | resetmask); return 0; } -static void __devinit hpt366_clocking(ide_hwif_t *hwif) +/** + * hpt37x_calibrate_dpll - calibrate the DPLL + * @dev: PCI device + * + * Perform a calibration cycle on the DPLL. + * Returns 1 if this succeeds + */ +static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high) { - u32 reg1 = 0; - struct hpt_info *info = ide_get_hwifdata(hwif); + u32 dpll = (f_high << 16) | f_low | 0x100; + u8 scr2; + int i; - pci_read_config_dword(hwif->pci_dev, 0x40, ®1); + pci_write_config_dword(dev, 0x5c, dpll); - /* detect bus speed by looking at control reg timing: */ - switch((reg1 >> 8) & 7) { - case 5: - info->speed = forty_base_hpt36x; - break; - case 9: - info->speed = twenty_five_base_hpt36x; - break; - case 7: - default: - info->speed = thirty_three_base_hpt36x; + /* Wait for oscillator ready */ + for(i = 0; i < 0x5000; ++i) { + udelay(50); + pci_read_config_byte(dev, 0x5b, &scr2); + if (scr2 & 0x80) break; } -} - -static void __devinit hpt37x_clocking(ide_hwif_t *hwif) -{ - struct hpt_info *info = ide_get_hwifdata(hwif); - struct pci_dev *dev = hwif->pci_dev; - int adjust, i; - u16 freq = 0; - u32 pll, temp = 0; - u8 reg5bh = 0, mcr1 = 0; - - /* - * default to pci clock. make sure MA15/16 are set to output - * to prevent drives having problems with 40-pin cables. Needed - * for some drives such as IBM-DTLA which will not enter ready - * state on reset when PDIAG is a input. - * - * ToDo: should we set 0x21 when using PLL mode ? - */ - pci_write_config_byte(dev, 0x5b, 0x23); - - /* - * We'll have to read f_CNT value in order to determine - * the PCI clock frequency according to the following ratio: - * - * f_CNT = Fpci * 192 / Fdpll - * - * First try reading the register in which the HighPoint BIOS - * saves f_CNT value before reprogramming the DPLL from its - * default setting (which differs for the various chips). - * NOTE: This register is only accessible via I/O space. - * - * In case the signature check fails, we'll have to resort to - * reading the f_CNT register itself in hopes that nobody has - * touched the DPLL yet... - */ - temp = inl(pci_resource_start(dev, 4) + 0x90); - if ((temp & 0xFFFFF000) != 0xABCDE000) { - printk(KERN_WARNING "HPT37X: no clock data saved by BIOS\n"); - - /* Calculate the average value of f_CNT */ - for (temp = i = 0; i < 128; i++) { - pci_read_config_word(dev, 0x78, &freq); - temp += freq & 0x1ff; - mdelay(1); - } - freq = temp / 128; - } else - freq = temp & 0x1ff; - - /* - * HPT3xxN chips use different PCI clock information. - * Currently we always set up the PLL for them. - */ - - if (info->flags & IS_3xxN) { - if(freq < 0x55) - pll = F_LOW_PCI_33; - else if(freq < 0x70) - pll = F_LOW_PCI_40; - else if(freq < 0x7F) - pll = F_LOW_PCI_50; - else - pll = F_LOW_PCI_66; - - printk(KERN_INFO "HPT3xxN detected, FREQ: %d, PLL: %d\n", freq, pll); + /* See if it stays ready (we'll just bail out if it's not yet) */ + for(i = 0; i < 0x1000; ++i) { + pci_read_config_byte(dev, 0x5b, &scr2); + /* DPLL destabilized? */ + if(!(scr2 & 0x80)) + return 0; } - else - { - if(freq < 0x9C) - pll = F_LOW_PCI_33; - else if(freq < 0xb0) - pll = F_LOW_PCI_40; - else if(freq <0xc8) - pll = F_LOW_PCI_50; - else - pll = F_LOW_PCI_66; - - if (pll == F_LOW_PCI_33) { - info->speed = thirty_three_base_hpt37x; - printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n"); - } else if (pll == F_LOW_PCI_40) { - /* Unsupported */ - } else if (pll == F_LOW_PCI_50) { - info->speed = fifty_base_hpt37x; - printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n"); - } else { - info->speed = sixty_six_base_hpt37x; - printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n"); - } - } - - if (pll == F_LOW_PCI_66) - info->flags |= PCI_66MHZ; - - /* - * only try the pll if we don't have a table for the clock - * speed that we're running at. NOTE: the internal PLL will - * result in slow reads when using a 33MHz PCI clock. we also - * don't like to use the PLL because it will cause glitches - * on PRST/SRST when the HPT state engine gets reset. - * - * ToDo: Use 66MHz PLL when ATA133 devices are present on a - * 372 device so we can get ATA133 support - */ - if (info->speed) - goto init_hpt37X_done; - - info->flags |= PLL_MODE; - - /* - * Adjust the PLL based upon the PCI clock, enable it, and - * wait for stabilization... - */ - adjust = 0; - freq = (pll < F_LOW_PCI_50) ? 2 : 4; - while (adjust++ < 6) { - pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 | - pll | 0x100); - - /* wait for clock stabilization */ - for (i = 0; i < 0x50000; i++) { - pci_read_config_byte(dev, 0x5b, ®5bh); - if (reg5bh & 0x80) { - /* spin looking for the clock to destabilize */ - for (i = 0; i < 0x1000; ++i) { - pci_read_config_byte(dev, 0x5b, - ®5bh); - if ((reg5bh & 0x80) == 0) - goto pll_recal; - } - pci_read_config_dword(dev, 0x5c, &pll); - pci_write_config_dword(dev, 0x5c, - pll & ~0x100); - pci_write_config_byte(dev, 0x5b, 0x21); - - info->speed = fifty_base_hpt37x; - printk("HPT37X: using 50MHz internal PLL\n"); - goto init_hpt37X_done; - } - } -pll_recal: - if (adjust & 1) - pll -= (adjust >> 1); - else - pll += (adjust >> 1); - } - -init_hpt37X_done: - if (!info->speed) - printk(KERN_ERR "HPT37x%s: unknown bus timing [%d %d].\n", - (info->flags & IS_3xxN) ? "N" : "", pll, freq); - /* - * Reset the state engines. - * NOTE: avoid accidentally enabling the primary channel on HPT371N. - */ - pci_read_config_byte(dev, 0x50, &mcr1); - if (mcr1 & 0x04) - pci_write_config_byte(dev, 0x50, 0x37); - pci_write_config_byte(dev, 0x54, 0x37); - udelay(100); -} - -static int __devinit init_hpt37x(struct pci_dev *dev) -{ - u8 reg5ah; - - pci_read_config_byte(dev, 0x5a, ®5ah); - /* interrupt force enable */ - pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10)); - return 0; -} - -static int __devinit init_hpt366(struct pci_dev *dev) -{ - u32 reg1 = 0; - u8 drive_fast = 0; - - /* - * Disable the "fast interrupt" prediction. - */ - pci_read_config_byte(dev, 0x51, &drive_fast); - if (drive_fast & 0x80) - pci_write_config_byte(dev, 0x51, drive_fast & ~0x80); - pci_read_config_dword(dev, 0x40, ®1); - - return 0; + /* Turn off tuning, we have the DPLL set */ + pci_read_config_dword (dev, 0x5c, &dpll); + pci_write_config_dword(dev, 0x5c, (dpll & ~0x100)); + return 1; } static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name) { - int ret = 0; + struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL); + unsigned long io_base = pci_resource_start(dev, 4); + u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */ + enum ata_clock clock; + + if (info == NULL) { + printk(KERN_ERR "%s: out of memory!\n", name); + return -ENOMEM; + } + + /* + * Copy everything from a static "template" structure + * to just allocated per-chip hpt_info structure. + */ + *info = *(struct hpt_info *)pci_get_drvdata(dev); /* * FIXME: Not portable. Also, why do we enable the ROM in the first place? @@ -1211,37 +1044,249 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); - if (hpt_revision(dev) >= 3) - ret = init_hpt37x(dev); - else - ret = init_hpt366(dev); + /* + * First, try to estimate the PCI clock frequency... + */ + if (info->chip_type >= HPT370) { + u8 scr1 = 0; + u16 f_cnt = 0; + u32 temp = 0; - if (ret) - return ret; + /* Interrupt force enable. */ + pci_read_config_byte(dev, 0x5a, &scr1); + if (scr1 & 0x10) + pci_write_config_byte(dev, 0x5a, scr1 & ~0x10); + + /* + * HighPoint does this for HPT372A. + * NOTE: This register is only writeable via I/O space. + */ + if (info->chip_type == HPT372A) + outb(0x0e, io_base + 0x9c); + + /* + * Default to PCI clock. Make sure MA15/16 are set to output + * to prevent drives having problems with 40-pin cables. + */ + pci_write_config_byte(dev, 0x5b, 0x23); + + /* + * We'll have to read f_CNT value in order to determine + * the PCI clock frequency according to the following ratio: + * + * f_CNT = Fpci * 192 / Fdpll + * + * First try reading the register in which the HighPoint BIOS + * saves f_CNT value before reprogramming the DPLL from its + * default setting (which differs for the various chips). + * NOTE: This register is only accessible via I/O space. + * + * In case the signature check fails, we'll have to resort to + * reading the f_CNT register itself in hopes that nobody has + * touched the DPLL yet... + */ + temp = inl(io_base + 0x90); + if ((temp & 0xFFFFF000) != 0xABCDE000) { + int i; + + printk(KERN_WARNING "%s: no clock data saved by BIOS\n", + name); + + /* Calculate the average value of f_CNT. */ + for (temp = i = 0; i < 128; i++) { + pci_read_config_word(dev, 0x78, &f_cnt); + temp += f_cnt & 0x1ff; + mdelay(1); + } + f_cnt = temp / 128; + } else + f_cnt = temp & 0x1ff; + + dpll_clk = info->dpll_clk; + pci_clk = (f_cnt * dpll_clk) / 192; + + /* Clamp PCI clock to bands. */ + if (pci_clk < 40) + pci_clk = 33; + else if(pci_clk < 45) + pci_clk = 40; + else if(pci_clk < 55) + pci_clk = 50; + else + pci_clk = 66; + + printk(KERN_INFO "%s: DPLL base: %d MHz, f_CNT: %d, " + "assuming %d MHz PCI\n", name, dpll_clk, f_cnt, pci_clk); + } else { + u32 itr1 = 0; + + pci_read_config_dword(dev, 0x40, &itr1); + + /* Detect PCI clock by looking at cmd_high_time. */ + switch((itr1 >> 8) & 0x07) { + case 0x09: + pci_clk = 40; + break; + case 0x05: + pci_clk = 25; + break; + case 0x07: + default: + pci_clk = 33; + break; + } + } + + /* Let's assume we'll use PCI clock for the ATA clock... */ + switch (pci_clk) { + case 25: + clock = ATA_CLOCK_25MHZ; + break; + case 33: + default: + clock = ATA_CLOCK_33MHZ; + break; + case 40: + clock = ATA_CLOCK_40MHZ; + break; + case 50: + clock = ATA_CLOCK_50MHZ; + break; + case 66: + clock = ATA_CLOCK_66MHZ; + break; + } + + /* + * Only try the DPLL if we don't have a table for the PCI clock that + * we are running at for HPT370/A, always use it for anything newer... + * + * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI. + * We also don't like using the DPLL because this causes glitches + * on PRST-/SRST- when the state engine gets reset... + */ + if (info->chip_type >= HPT374 || info->settings[clock] == NULL) { + u16 f_low, delta = pci_clk < 50 ? 2 : 4; + int adjust; + + /* + * Select 66 MHz DPLL clock only if UltraATA/133 mode is + * supported/enabled, use 50 MHz DPLL clock otherwise... + */ + if (info->max_mode == 0x04) { + dpll_clk = 66; + clock = ATA_CLOCK_66MHZ; + } else if (dpll_clk) { /* HPT36x chips don't have DPLL */ + dpll_clk = 50; + clock = ATA_CLOCK_50MHZ; + } + + if (info->settings[clock] == NULL) { + printk(KERN_ERR "%s: unknown bus timing!\n", name); + kfree(info); + return -EIO; + } + + /* Select the DPLL clock. */ + pci_write_config_byte(dev, 0x5b, 0x21); + + /* + * Adjust the DPLL based upon PCI clock, enable it, + * and wait for stabilization... + */ + f_low = (pci_clk * 48) / dpll_clk; + + for (adjust = 0; adjust < 8; adjust++) { + if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta)) + break; + + /* + * See if it'll settle at a fractionally different clock + */ + if (adjust & 1) + f_low -= adjust >> 1; + else + f_low += adjust >> 1; + } + if (adjust == 8) { + printk(KERN_ERR "%s: DPLL did not stabilize!\n", name); + kfree(info); + return -EIO; + } + + printk("%s: using %d MHz DPLL clock\n", name, dpll_clk); + } else { + /* Mark the fact that we're not using the DPLL. */ + dpll_clk = 0; + + printk("%s: using %d MHz PCI clock\n", name, pci_clk); + } + + /* + * Advance the table pointer to a slot which points to the list + * of the register values settings matching the clock being used. + */ + info->settings += clock; + + /* Store the clock frequencies. */ + info->dpll_clk = dpll_clk; + info->pci_clk = pci_clk; + + /* Point to this chip's own instance of the hpt_info structure. */ + pci_set_drvdata(dev, info); + + if (info->chip_type >= HPT370) { + u8 mcr1, mcr4; + + /* + * Reset the state engines. + * NOTE: Avoid accidentally enabling the disabled channels. + */ + pci_read_config_byte (dev, 0x50, &mcr1); + pci_read_config_byte (dev, 0x54, &mcr4); + pci_write_config_byte(dev, 0x50, (mcr1 | 0x32)); + pci_write_config_byte(dev, 0x54, (mcr4 | 0x32)); + udelay(100); + } + + /* + * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in + * the MISC. register to stretch the UltraDMA Tss timing. + * NOTE: This register is only writeable via I/O space. + */ + if (info->chip_type == HPT371N && clock == ATA_CLOCK_66MHZ) + + outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c); return dev->irq; } static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) { - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 ata66 = 0, regmask = (hwif->channel) ? 0x01 : 0x02; + struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = pci_get_drvdata(dev); int serialize = HPT_SERIALIZE_IO; - + u8 scr1 = 0, ata66 = (hwif->channel) ? 0x01 : 0x02; + u8 chip_type = info->chip_type; + u8 new_mcr, old_mcr = 0; + + /* Cache the channel's MISC. control registers' offset */ + hwif->select_data = hwif->channel ? 0x54 : 0x50; + hwif->tuneproc = &hpt3xx_tune_drive; hwif->speedproc = &hpt3xx_tune_chipset; hwif->quirkproc = &hpt3xx_quirkproc; hwif->intrproc = &hpt3xx_intrproc; hwif->maskproc = &hpt3xx_maskproc; - + hwif->busproc = &hpt3xx_busproc; + /* * HPT3xxN chips have some complications: * * - on 33 MHz PCI we must clock switch * - on 66 MHz PCI we must NOT use the PCI clock */ - if ((info->flags & (IS_3xxN | PCI_66MHZ)) == IS_3xxN) { + if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) { /* * Clock is shared between the channels, * so we'll have to serialize them... :-( @@ -1250,200 +1295,171 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) hwif->rw_disk = &hpt3xxn_rw_disk; } - /* - * The HPT37x uses the CBLID pins as outputs for MA15/MA16 - * address lines to access an external eeprom. To read valid - * cable detect state the pins must be enabled as inputs. - */ - if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) { - /* - * HPT374 PCI function 1 - * - set bit 15 of reg 0x52 to enable TCBLID as input - * - set bit 15 of reg 0x56 to enable FCBLID as input - */ - u16 mcr3, mcr6; - pci_read_config_word(dev, 0x52, &mcr3); - pci_read_config_word(dev, 0x56, &mcr6); - pci_write_config_word(dev, 0x52, mcr3 | 0x8000); - pci_write_config_word(dev, 0x56, mcr6 | 0x8000); - /* now read cable id register */ - pci_read_config_byte(dev, 0x5a, &ata66); - pci_write_config_word(dev, 0x52, mcr3); - pci_write_config_word(dev, 0x56, mcr6); - } else if (info->revision >= 3) { - /* - * HPT370/372 and 374 pcifn 0 - * - clear bit 0 of 0x5b to enable P/SCBLID as inputs - */ - u8 scr2; - pci_read_config_byte(dev, 0x5b, &scr2); - pci_write_config_byte(dev, 0x5b, scr2 & ~1); - /* now read cable id register */ - pci_read_config_byte(dev, 0x5a, &ata66); - pci_write_config_byte(dev, 0x5b, scr2); - } else { - pci_read_config_byte(dev, 0x5a, &ata66); - } - -#ifdef DEBUG - printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n", - ata66, (ata66 & regmask) ? "33" : "66", - PCI_FUNC(hwif->pci_dev->devfn)); -#endif /* DEBUG */ - - /* Serialize access to this device */ + /* Serialize access to this device if needed */ if (serialize && hwif->mate) hwif->serialized = hwif->mate->serialized = 1; /* - * Set up ioctl for power status. - * NOTE: power affects both drives on each channel. + * Disable the "fast interrupt" prediction. Don't hold off + * on interrupts. (== 0x01 despite what the docs say) */ - hwif->busproc = &hpt3xx_busproc; + pci_read_config_byte(dev, hwif->select_data + 1, &old_mcr); + + if (info->chip_type >= HPT374) + new_mcr = old_mcr & ~0x07; + else if (info->chip_type >= HPT370) { + new_mcr = old_mcr; + new_mcr &= ~0x02; + +#ifdef HPT_DELAY_INTERRUPT + new_mcr &= ~0x01; +#else + new_mcr |= 0x01; +#endif + } else /* HPT366 and HPT368 */ + new_mcr = old_mcr & ~0x80; + + if (new_mcr != old_mcr) + pci_write_config_byte(dev, hwif->select_data + 1, new_mcr); if (!hwif->dma_base) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; + hwif->drives[0].autotune = hwif->drives[1].autotune = 1; return; } hwif->ultra_mask = 0x7f; hwif->mwdma_mask = 0x07; - if (!(hwif->udma_four)) - hwif->udma_four = ((ata66 & regmask) ? 0 : 1); - hwif->ide_dma_check = &hpt366_config_drive_xfer_rate; + /* + * The HPT37x uses the CBLID pins as outputs for MA15/MA16 + * address lines to access an external EEPROM. To read valid + * cable detect state the pins must be enabled as inputs. + */ + if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) { + /* + * HPT374 PCI function 1 + * - set bit 15 of reg 0x52 to enable TCBLID as input + * - set bit 15 of reg 0x56 to enable FCBLID as input + */ + u8 mcr_addr = hwif->select_data + 2; + u16 mcr; - if (info->revision >= 8) { - hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq; - hwif->ide_dma_end = &hpt374_ide_dma_end; - } else if (info->revision >= 5) { - hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq; - hwif->ide_dma_end = &hpt374_ide_dma_end; - } else if (info->revision >= 3) { - hwif->dma_start = &hpt370_ide_dma_start; - hwif->ide_dma_end = &hpt370_ide_dma_end; - hwif->ide_dma_timeout = &hpt370_ide_dma_timeout; - hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq; - } else if (info->revision >= 2) - hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq; - else - hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq; + pci_read_config_word (dev, mcr_addr, &mcr); + pci_write_config_word(dev, mcr_addr, (mcr | 0x8000)); + /* now read cable id register */ + pci_read_config_byte (dev, 0x5a, &scr1); + pci_write_config_word(dev, mcr_addr, mcr); + } else if (chip_type >= HPT370) { + /* + * HPT370/372 and 374 pcifn 0 + * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs + */ + u8 scr2 = 0; + + pci_read_config_byte (dev, 0x5b, &scr2); + pci_write_config_byte(dev, 0x5b, (scr2 & ~1)); + /* now read cable id register */ + pci_read_config_byte (dev, 0x5a, &scr1); + pci_write_config_byte(dev, 0x5b, scr2); + } else + pci_read_config_byte (dev, 0x5a, &scr1); + + if (!hwif->udma_four) + hwif->udma_four = (scr1 & ata66) ? 0 : 1; + + hwif->ide_dma_check = &hpt366_config_drive_xfer_rate; + + if (chip_type >= HPT374) { + hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq; + hwif->ide_dma_end = &hpt374_ide_dma_end; + } else if (chip_type >= HPT370) { + hwif->dma_start = &hpt370_ide_dma_start; + hwif->ide_dma_end = &hpt370_ide_dma_end; + hwif->ide_dma_timeout = &hpt370_ide_dma_timeout; + } else + hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq; if (!noautodma) hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; + hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma; } static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase) { - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 masterdma = 0, slavedma = 0; - u8 dma_new = 0, dma_old = 0; - u8 primary = hwif->channel ? 0x4b : 0x43; - u8 secondary = hwif->channel ? 0x4f : 0x47; + struct pci_dev *dev = hwif->pci_dev; + u8 masterdma = 0, slavedma = 0; + u8 dma_new = 0, dma_old = 0; unsigned long flags; if (!dmabase) return; - if(info->speed == NULL) { - printk(KERN_WARNING "hpt366: no known IDE timings, disabling DMA.\n"); - return; - } - - dma_old = hwif->INB(dmabase+2); + dma_old = hwif->INB(dmabase + 2); local_irq_save(flags); dma_new = dma_old; - pci_read_config_byte(hwif->pci_dev, primary, &masterdma); - pci_read_config_byte(hwif->pci_dev, secondary, &slavedma); + pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma); + pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47, &slavedma); if (masterdma & 0x30) dma_new |= 0x20; - if (slavedma & 0x30) dma_new |= 0x40; + if ( slavedma & 0x30) dma_new |= 0x40; if (dma_new != dma_old) - hwif->OUTB(dma_new, dmabase+2); + hwif->OUTB(dma_new, dmabase + 2); local_irq_restore(flags); ide_setup_dma(hwif, dmabase, 8); } -/* - * We "borrow" this hook in order to set the data structures - * up early enough before dma or init_hwif calls are made. - */ - -static void __devinit init_iops_hpt366(ide_hwif_t *hwif) -{ - struct hpt_info *info = kzalloc(sizeof(struct hpt_info), GFP_KERNEL); - struct pci_dev *dev = hwif->pci_dev; - u16 did = dev->device; - u8 rid = 0; - - if(info == NULL) { - printk(KERN_WARNING "hpt366: out of memory.\n"); - return; - } - ide_set_hwifdata(hwif, info); - - /* Avoid doing the same thing twice. */ - if (hwif->channel && hwif->mate) { - memcpy(info, ide_get_hwifdata(hwif->mate), sizeof(struct hpt_info)); - return; - } - - pci_read_config_byte(dev, PCI_CLASS_REVISION, &rid); - - if (( did == PCI_DEVICE_ID_TTI_HPT366 && rid == 6) || - ((did == PCI_DEVICE_ID_TTI_HPT372 || - did == PCI_DEVICE_ID_TTI_HPT302 || - did == PCI_DEVICE_ID_TTI_HPT371) && rid > 1) || - did == PCI_DEVICE_ID_TTI_HPT372N) - info->flags |= IS_3xxN; - - info->revision = hpt_revision(dev); - - if (info->revision >= 3) - hpt37x_clocking(hwif); - else - hpt366_clocking(hwif); -} - static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d) { - struct pci_dev *findev = NULL; + struct pci_dev *dev2; if (PCI_FUNC(dev->devfn) & 1) return -ENODEV; - while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { - if ((findev->vendor == dev->vendor) && - (findev->device == dev->device) && - ((findev->devfn - dev->devfn) == 1) && - (PCI_FUNC(findev->devfn) & 1)) { - if (findev->irq != dev->irq) { - /* FIXME: we need a core pci_set_interrupt() */ - findev->irq = dev->irq; - printk(KERN_WARNING "%s: pci-config space interrupt " - "fixed.\n", d->name); - } - return ide_setup_pci_devices(dev, findev, d); + pci_set_drvdata(dev, &hpt374); + + if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) { + int ret; + + pci_set_drvdata(dev2, &hpt374); + + if (dev2->irq != dev->irq) { + /* FIXME: we need a core pci_set_interrupt() */ + dev2->irq = dev->irq; + printk(KERN_WARNING "%s: PCI config space interrupt " + "fixed.\n", d->name); } + ret = ide_setup_pci_devices(dev, dev2, d); + if (ret < 0) + pci_dev_put(dev2); + return ret; } return ide_setup_pci_device(dev, d); } -static int __devinit init_setup_hpt37x(struct pci_dev *dev, ide_pci_device_t *d) +static int __devinit init_setup_hpt372n(struct pci_dev *dev, ide_pci_device_t *d) { + pci_set_drvdata(dev, &hpt372n); + return ide_setup_pci_device(dev, d); } static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d) { - u8 mcr1 = 0; + struct hpt_info *info; + u8 rev = 0, mcr1 = 0; + + pci_read_config_byte(dev, PCI_REVISION_ID, &rev); + + if (rev > 1) { + d->name = "HPT371N"; + + info = &hpt371n; + } else + info = &hpt371; /* * HPT371 chips physically have only one channel, the secondary one, @@ -1453,59 +1469,94 @@ static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d) */ pci_read_config_byte(dev, 0x50, &mcr1); if (mcr1 & 0x04) - pci_write_config_byte(dev, 0x50, (mcr1 & ~0x04)); + pci_write_config_byte(dev, 0x50, mcr1 & ~0x04); + + pci_set_drvdata(dev, info); + + return ide_setup_pci_device(dev, d); +} + +static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d) +{ + struct hpt_info *info; + u8 rev = 0; + + pci_read_config_byte(dev, PCI_REVISION_ID, &rev); + + if (rev > 1) { + d->name = "HPT372N"; + + info = &hpt372n; + } else + info = &hpt372a; + pci_set_drvdata(dev, info); + + return ide_setup_pci_device(dev, d); +} + +static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d) +{ + struct hpt_info *info; + u8 rev = 0; + + pci_read_config_byte(dev, PCI_REVISION_ID, &rev); + + if (rev > 1) { + d->name = "HPT302N"; + + info = &hpt302n; + } else + info = &hpt302; + pci_set_drvdata(dev, info); return ide_setup_pci_device(dev, d); } static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d) { - struct pci_dev *findev = NULL; - u8 pin1 = 0, pin2 = 0; - unsigned int class_rev; - char *chipset_names[] = {"HPT366", "HPT366", "HPT368", - "HPT370", "HPT370A", "HPT372", - "HPT372N" }; + struct pci_dev *dev2; + u8 rev = 0; + static char *chipset_names[] = { "HPT366", "HPT366", "HPT368", + "HPT370", "HPT370A", "HPT372", + "HPT372N" }; + static struct hpt_info *info[] = { &hpt36x, &hpt36x, &hpt36x, + &hpt370, &hpt370a, &hpt372, + &hpt372n }; if (PCI_FUNC(dev->devfn) & 1) return -ENODEV; - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; + pci_read_config_byte(dev, PCI_REVISION_ID, &rev); - if(dev->device == PCI_DEVICE_ID_TTI_HPT372N) - class_rev = 6; + if (rev > 6) + rev = 6; - if(class_rev <= 6) - d->name = chipset_names[class_rev]; + d->name = chipset_names[rev]; - switch(class_rev) { - case 6: - case 5: - case 4: - case 3: - goto init_single; - default: - break; - } + pci_set_drvdata(dev, info[rev]); + + if (rev > 2) + goto init_single; d->channels = 1; - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); - while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { - if ((findev->vendor == dev->vendor) && - (findev->device == dev->device) && - ((findev->devfn - dev->devfn) == 1) && - (PCI_FUNC(findev->devfn) & 1)) { - pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2); - if ((pin1 != pin2) && (dev->irq == findev->irq)) { - d->bootable = ON_BOARD; - printk("%s: onboard version of chipset, " - "pin1=%d pin2=%d\n", d->name, - pin1, pin2); - } - return ide_setup_pci_devices(dev, findev, d); + if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) { + u8 pin1 = 0, pin2 = 0; + int ret; + + pci_set_drvdata(dev2, info[rev]); + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); + pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); + if (pin1 != pin2 && dev->irq == dev2->irq) { + d->bootable = ON_BOARD; + printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", + d->name, pin1, pin2); } + ret = ide_setup_pci_devices(dev, dev2, d); + if (ret < 0) + pci_dev_put(dev2); + return ret; } init_single: return ide_setup_pci_device(dev, d); @@ -1516,64 +1567,68 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = { .name = "HPT366", .init_setup = init_setup_hpt366, .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, - .init_hwif = init_hwif_hpt366, - .init_dma = init_dma_hpt366, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - .extra = 240 - },{ /* 1 */ - .name = "HPT372A", - .init_setup = init_setup_hpt37x, - .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, - .init_hwif = init_hwif_hpt366, - .init_dma = init_dma_hpt366, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 2 */ - .name = "HPT302", - .init_setup = init_setup_hpt37x, - .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, - .init_hwif = init_hwif_hpt366, - .init_dma = init_dma_hpt366, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 3 */ - .name = "HPT371", - .init_setup = init_setup_hpt371, - .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, .autodma = AUTODMA, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .bootable = OFF_BOARD, + .extra = 240 + },{ /* 1 */ + .name = "HPT372A", + .init_setup = init_setup_hpt372a, + .init_chipset = init_chipset_hpt366, + .init_hwif = init_hwif_hpt366, + .init_dma = init_dma_hpt366, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, + .bootable = OFF_BOARD, + .extra = 240 + },{ /* 2 */ + .name = "HPT302", + .init_setup = init_setup_hpt302, + .init_chipset = init_chipset_hpt366, + .init_hwif = init_hwif_hpt366, + .init_dma = init_dma_hpt366, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, + .bootable = OFF_BOARD, + .extra = 240 + },{ /* 3 */ + .name = "HPT371", + .init_setup = init_setup_hpt371, + .init_chipset = init_chipset_hpt366, + .init_hwif = init_hwif_hpt366, + .init_dma = init_dma_hpt366, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, + .bootable = OFF_BOARD, + .extra = 240 },{ /* 4 */ .name = "HPT374", .init_setup = init_setup_hpt374, .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, /* 4 */ .autodma = AUTODMA, + .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .bootable = OFF_BOARD, + .extra = 240 },{ /* 5 */ .name = "HPT372N", - .init_setup = init_setup_hpt37x, + .init_setup = init_setup_hpt372n, .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, /* 4 */ .autodma = AUTODMA, + .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .bootable = OFF_BOARD, + .extra = 240 } }; diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c new file mode 100644 index 000000000000..63248b6909fa --- /dev/null +++ b/drivers/ide/pci/it8213.c @@ -0,0 +1,362 @@ +/* + * ITE 8213 IDE driver + * + * Copyright (C) 2006 Jack Lee + * Copyright (C) 2006 Alan Cox + * Copyright (C) 2007 Bartlomiej Zolnierkiewicz + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * it8213_ratemask - Compute available modes + * @drive: IDE drive + * + * Compute the available speeds for the devices on the interface. This + * is all modes to ATA133 clipped by drive cable setup. + */ + +static u8 it8213_ratemask (ide_drive_t *drive) +{ + u8 mode = 4; + if (!eighty_ninty_three(drive)) + mode = min_t(u8, mode, 1); + return mode; +} + +/** + * it8213_dma_2_pio - return the PIO mode matching DMA + * @xfer_rate: transfer speed + * + * Returns the nearest equivalent PIO timing for the PIO or DMA + * mode requested by the controller. + */ + +static u8 it8213_dma_2_pio (u8 xfer_rate) { + switch(xfer_rate) { + case XFER_UDMA_6: + case XFER_UDMA_5: + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + case XFER_MW_DMA_2: + case XFER_PIO_4: + return 4; + case XFER_MW_DMA_1: + case XFER_PIO_3: + return 3; + case XFER_SW_DMA_2: + case XFER_PIO_2: + return 2; + case XFER_MW_DMA_0: + case XFER_SW_DMA_1: + case XFER_SW_DMA_0: + case XFER_PIO_1: + case XFER_PIO_0: + case XFER_PIO_SLOW: + default: + return 0; + } +} + +/* + * it8213_tuneproc - tune a drive + * @drive: drive to tune + * @pio: desired PIO mode + * + * Set the interface PIO mode. + */ + +static void it8213_tuneproc (ide_drive_t *drive, u8 pio) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + int is_slave = drive->dn & 1; + int master_port = 0x40; + int slave_port = 0x44; + unsigned long flags; + u16 master_data; + u8 slave_data; + static DEFINE_SPINLOCK(tune_lock); + int control = 0; + + static const u8 timings[][2]= { + { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + + spin_lock_irqsave(&tune_lock, flags); + pci_read_config_word(dev, master_port, &master_data); + + if (pio > 1) + control |= 1; /* Programmable timing on */ + if (drive->media != ide_disk) + control |= 4; /* ATAPI */ + if (pio > 2) + control |= 2; /* IORDY */ + if (is_slave) { + master_data |= 0x4000; + master_data &= ~0x0070; + if (pio > 1) + master_data = master_data | (control << 4); + pci_read_config_byte(dev, slave_port, &slave_data); + slave_data = slave_data & 0xf0; + slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1]; + } else { + master_data &= ~0x3307; + if (pio > 1) + master_data = master_data | control; + master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); + } + pci_write_config_word(dev, master_port, master_data); + if (is_slave) + pci_write_config_byte(dev, slave_port, slave_data); + spin_unlock_irqrestore(&tune_lock, flags); +} + +/** + * it8213_tune_chipset - set controller timings + * @drive: Drive to set up + * @xferspeed: speed we want to achieve + * + * Tune the ITE chipset for the desired mode. If we can't achieve + * the desired mode then tune for a lower one, but ultimately + * make the thing work. + */ + +static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed) +{ + + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + u8 maslave = 0x40; + u8 speed = ide_rate_filter(it8213_ratemask(drive), xferspeed); + int a_speed = 3 << (drive->dn * 4); + int u_flag = 1 << drive->dn; + int v_flag = 0x01 << drive->dn; + int w_flag = 0x10 << drive->dn; + int u_speed = 0; + u16 reg4042, reg4a; + u8 reg48, reg54, reg55; + + pci_read_config_word(dev, maslave, ®4042); + pci_read_config_byte(dev, 0x48, ®48); + pci_read_config_word(dev, 0x4a, ®4a); + pci_read_config_byte(dev, 0x54, ®54); + pci_read_config_byte(dev, 0x55, ®55); + + switch(speed) { + case XFER_UDMA_6: + case XFER_UDMA_4: + case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; + case XFER_UDMA_5: + case XFER_UDMA_3: + case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; + case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; + break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_SW_DMA_2: + break; + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_1: + case XFER_PIO_0: + break; + default: + return -1; + } + + if (speed >= XFER_UDMA_0) { + if (!(reg48 & u_flag)) + pci_write_config_byte(dev, 0x48, reg48 | u_flag); + if (speed >= XFER_UDMA_5) { + pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); + } else { + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + } + + if ((reg4a & a_speed) != u_speed) + pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); + if (speed > XFER_UDMA_2) { + if (!(reg54 & v_flag)) + pci_write_config_byte(dev, 0x54, reg54 | v_flag); + } else + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + } else { + if (reg48 & u_flag) + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + if (reg4a & a_speed) + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + if (reg54 & v_flag) + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + if (reg55 & w_flag) + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + } + it8213_tuneproc(drive, it8213_dma_2_pio(speed)); + return ide_config_drive_speed(drive, speed); +} + +/* + * config_chipset_for_dma - configure for DMA + * @drive: drive to configure + * + * Called by the IDE layer when it wants the timings set up. + */ + +static int config_chipset_for_dma (ide_drive_t *drive) +{ + u8 speed = ide_dma_speed(drive, it8213_ratemask(drive)); + + if (!speed) + return 0; + + it8213_tune_chipset(drive, speed); + + return ide_dma_enable(drive); +} + +/** + * it8213_configure_drive_for_dma - set up for DMA transfers + * @drive: drive we are going to set up + * + * Set up the drive for DMA, tune the controller and drive as + * required. If the drive isn't suitable for DMA or we hit + * other problems then we will drop down to PIO and set up + * PIO appropriately + */ + +static int it8213_config_drive_for_dma (ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + + if (ide_use_dma(drive)) { + if (config_chipset_for_dma(drive)) + return hwif->ide_dma_on(drive); + } + + hwif->speedproc(drive, XFER_PIO_0 + + ide_get_best_pio_mode(drive, 255, 4, NULL)); + + return hwif->ide_dma_off_quietly(drive); +} + +/** + * init_hwif_it8213 - set up hwif structs + * @hwif: interface to set up + * + * We do the basic set up of the interface structure. The IT8212 + * requires several custom handlers so we override the default + * ide DMA handlers appropriately + */ + +static void __devinit init_hwif_it8213(ide_hwif_t *hwif) +{ + u8 reg42h = 0, ata66 = 0; + + hwif->speedproc = &it8213_tune_chipset; + hwif->tuneproc = &it8213_tuneproc; + + hwif->autodma = 0; + + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + + if (!hwif->dma_base) + return; + + hwif->atapi_dma = 1; + hwif->ultra_mask = 0x7f; + hwif->mwdma_mask = 0x06; + hwif->swdma_mask = 0x04; + + pci_read_config_byte(hwif->pci_dev, 0x42, ®42h); + ata66 = (reg42h & 0x02) ? 0 : 1; + + hwif->ide_dma_check = &it8213_config_drive_for_dma; + if (!(hwif->udma_four)) + hwif->udma_four = ata66; + + /* + * The BIOS often doesn't set up DMA on this controller + * so we always do it. + */ + if (!noautodma) + hwif->autodma = 1; + + hwif->drives[0].autodma = hwif->autodma; + hwif->drives[1].autodma = hwif->autodma; +} + + +#define DECLARE_ITE_DEV(name_str) \ + { \ + .name = name_str, \ + .init_hwif = init_hwif_it8213, \ + .channels = 1, \ + .autodma = AUTODMA, \ + .enablebits = {{0x41,0x80,0x80}}, \ + .bootable = ON_BOARD, \ + } + +static ide_pci_device_t it8213_chipsets[] __devinitdata = { + /* 0 */ DECLARE_ITE_DEV("IT8213"), +}; + + +/** + * it8213_init_one - pci layer discovery entry + * @dev: PCI device + * @id: ident table entry + * + * Called by the PCI code when it finds an ITE8213 controller. As + * this device follows the standard interfaces we can use the + * standard helper functions to do almost all the work for us. + */ + +static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + ide_setup_pci_device(dev, &it8213_chipsets[id->driver_data]); + return 0; +} + + +static struct pci_device_id it8213_pci_tbl[] = { + { PCI_VENDOR_ID_ITE, 0x8213, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, it8213_pci_tbl); + +static struct pci_driver driver = { + .name = "ITE8213_IDE", + .id_table = it8213_pci_tbl, + .probe = it8213_init_one, +}; + +static int __init it8213_ide_init(void) +{ + return ide_pci_register_driver(&driver); +} + +module_init(it8213_ide_init); + +MODULE_AUTHOR("Jack Lee, Alan Cox"); +MODULE_DESCRIPTION("PCI driver module for the ITE 8213"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 77a9aaa7dab9..236a03144a27 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -92,26 +92,6 @@ static u8 pdcnew_ratemask(ide_drive_t *drive) return mode; } -static int check_in_drive_lists(ide_drive_t *drive, const char **list) -{ - struct hd_driveid *id = drive->id; - - if (pdc_quirk_drives == list) { - while (*list) { - if (strstr(id->model, *list++)) { - return 2; - } - } - } else { - while (*list) { - if (!strcmp(*list++,id->model)) { - return 1; - } - } - } - return 0; -} - /** * get_indexed_reg - Get indexed register * @hwif: for the port address @@ -249,13 +229,6 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed) return err; } -/* 0 1 2 3 4 5 6 7 8 - * 960, 480, 390, 300, 240, 180, 120, 90, 60 - * 180, 150, 120, 90, 60 - * DMA_Speed - * 180, 120, 90, 90, 90, 60, 30 - * 11, 5, 4, 3, 2, 1, 0 - */ static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio) { pio = ide_get_best_pio_mode(drive, pio, 4, NULL); @@ -313,12 +286,10 @@ static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive) drive->init_speed = 0; - if (id && (id->capability & 1) && drive->autodma) { + if ((id->capability & 1) && drive->autodma) { - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } + if (ide_use_dma(drive) && config_chipset_for_dma(drive)) + return hwif->ide_dma_on(drive); goto fast_ata_pio; @@ -333,21 +304,12 @@ fast_ata_pio: static int pdcnew_quirkproc(ide_drive_t *drive) { - return check_in_drive_lists(drive, pdc_quirk_drives); -} + const char **list, *model = drive->id->model; -static int pdcnew_ide_dma_lostirq(ide_drive_t *drive) -{ - if (HWIF(drive)->resetproc != NULL) - HWIF(drive)->resetproc(drive); - return __ide_dma_lostirq(drive); -} - -static int pdcnew_ide_dma_timeout(ide_drive_t *drive) -{ - if (HWIF(drive)->resetproc != NULL) - HWIF(drive)->resetproc(drive); - return __ide_dma_timeout(drive); + for (list = pdc_quirk_drives; *list != NULL; list++) + if (strstr(model, *list) != NULL) + return 2; + return 0; } static void pdcnew_reset(ide_drive_t *drive) @@ -599,8 +561,6 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif) hwif->err_stops_fifo = 1; hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate; - hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq; - hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout; if (!hwif->udma_four) hwif->udma_four = pdcnew_cable_detect(hwif) ? 0 : 1; diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index 143239c093d5..730e8d1ec2f5 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -123,26 +123,6 @@ static u8 pdc202xx_ratemask (ide_drive_t *drive) return mode; } -static int check_in_drive_lists (ide_drive_t *drive, const char **list) -{ - struct hd_driveid *id = drive->id; - - if (pdc_quirk_drives == list) { - while (*list) { - if (strstr(id->model, *list++)) { - return 2; - } - } - } else { - while (*list) { - if (!strcmp(*list++,id->model)) { - return 1; - } - } - } - return 0; -} - static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed) { ide_hwif_t *hwif = HWIF(drive); @@ -377,7 +357,12 @@ fast_ata_pio: static int pdc202xx_quirkproc (ide_drive_t *drive) { - return ((int) check_in_drive_lists(drive, pdc_quirk_drives)); + const char **list, *model = drive->id->model; + + for (list = pdc_quirk_drives; *list != NULL; list++) + if (strstr(model, *list) != NULL) + return 2; + return 0; } static void pdc202xx_old_ide_dma_start(ide_drive_t *drive) diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index edb37f3d558d..52cfc2ac22c1 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/piix.c Version 0.45 May 12, 2006 + * linux/drivers/ide/pci/piix.c Version 0.46 December 3, 2006 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-2000 Andre Hedrick @@ -163,7 +163,7 @@ static u8 piix_ratemask (ide_drive_t *drive) * if the drive cannot see an 80pin cable. */ if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); + mode = min_t(u8, mode, 1); return mode; } @@ -216,7 +216,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - int is_slave = (&hwif->drives[1] == drive); + int is_slave = drive->dn & 1; int master_port = hwif->channel ? 0x42 : 0x40; int slave_port = 0x44; unsigned long flags; @@ -225,7 +225,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) static DEFINE_SPINLOCK(tune_lock); int control = 0; - /* ISP RTC */ + /* ISP RTC */ static const u8 timings[][2]= { { 0, 0 }, { 0, 0 }, @@ -233,7 +233,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) { 2, 1 }, { 2, 3 }, }; - pio = ide_get_best_pio_mode(drive, pio, 5, NULL); + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); /* * Master vs slave is synchronized above us but the slave register is @@ -243,25 +243,24 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) spin_lock_irqsave(&tune_lock, flags); pci_read_config_word(dev, master_port, &master_data); - if (pio >= 2) + if (pio > 1) control |= 1; /* Programmable timing on */ if (drive->media == ide_disk) control |= 4; /* Prefetch, post write */ - if (pio >= 3) + if (pio > 2) control |= 2; /* IORDY */ if (is_slave) { - master_data = master_data | 0x4000; + master_data |= 0x4000; + master_data &= ~0x0070; if (pio > 1) { /* enable PPE, IE and TIME */ master_data = master_data | (control << 4); - } else { - master_data &= ~0x0070; } pci_read_config_byte(dev, slave_port, &slave_data); slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0); slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0)); } else { - master_data = master_data & 0xccf8; + master_data &= ~0x3307; if (pio > 1) { /* enable PPE, IE and TIME */ master_data = master_data | control; @@ -539,13 +538,19 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = { /* 0 */ DECLARE_PIIX_DEV("PIIXa"), /* 1 */ DECLARE_PIIX_DEV("PIIXb"), - { /* 2 */ + /* 2 */ + { /* + * MPIIX actually has only a single IDE channel mapped to + * the primary or secondary ports depending on the value + * of the bit 14 of the IDETIM register at offset 0x6c + */ .name = "MPIIX", .init_hwif = init_hwif_piix, .channels = 2, .autodma = NODMA, - .enablebits = {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}}, + .enablebits = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}}, .bootable = ON_BOARD, + .flags = IDEPCI_FLAG_ISA_PORTS }, /* 3 */ DECLARE_PIIX_DEV("PIIX3"), diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index 90e79c0844d2..2663ddbd9b67 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/slc90e66.c Version 0.12 May 12, 2006 + * linux/drivers/ide/pci/slc90e66.c Version 0.13 December 30, 2006 * * Copyright (C) 2000-2002 Andre Hedrick * Copyright (C) 2006 MontaVista Software, Inc. @@ -26,7 +26,7 @@ static u8 slc90e66_ratemask (ide_drive_t *drive) u8 mode = 2; if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); + mode = min_t(u8, mode, 1); return mode; } @@ -65,36 +65,47 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - int is_slave = (&hwif->drives[1] == drive); + int is_slave = drive->dn & 1; int master_port = hwif->channel ? 0x42 : 0x40; int slave_port = 0x44; unsigned long flags; u16 master_data; u8 slave_data; - /* ISP RTC */ + int control = 0; + /* ISP RTC */ static const u8 timings[][2]= { - { 0, 0 }, - { 0, 0 }, - { 1, 0 }, - { 2, 1 }, - { 2, 3 }, }; + { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; - pio = ide_get_best_pio_mode(drive, pio, 5, NULL); + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); spin_lock_irqsave(&ide_lock, flags); pci_read_config_word(dev, master_port, &master_data); + + if (pio > 1) + control |= 1; /* Programmable timing on */ + if (drive->media == ide_disk) + control |= 4; /* Prefetch, post write */ + if (pio > 2) + control |= 2; /* IORDY */ if (is_slave) { - master_data = master_data | 0x4000; - if (pio > 1) + master_data |= 0x4000; + master_data &= ~0x0070; + if (pio > 1) { /* enable PPE, IE and TIME */ - master_data = master_data | 0x0070; + master_data = master_data | (control << 4); + } pci_read_config_byte(dev, slave_port, &slave_data); slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0); slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0)); } else { - master_data = master_data & 0xccf8; - if (pio > 1) + master_data &= ~0x3307; + if (pio > 1) { /* enable PPE, IE and TIME */ - master_data = master_data | 0x0007; + master_data = master_data | control; + } master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); } pci_write_config_word(dev, master_port, master_data); @@ -173,7 +184,7 @@ static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive) drive->init_speed = 0; - if (id && (id->capability & 1) && drive->autodma) { + if ((id->capability & 1) && drive->autodma) { if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive)) return hwif->ide_dma_on(drive); @@ -201,7 +212,7 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif) hwif->irq = hwif->channel ? 15 : 14; hwif->speedproc = &slc90e66_tune_chipset; - hwif->tuneproc = &slc90e66_tune_drive; + hwif->tuneproc = &slc90e66_tune_drive; pci_read_config_byte(hwif->pci_dev, 0x47, ®47); @@ -213,14 +224,16 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif) hwif->atapi_dma = 1; hwif->ultra_mask = 0x1f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; + hwif->mwdma_mask = 0x06; + hwif->swdma_mask = 0x04; - if (!(hwif->udma_four)) + if (!hwif->udma_four) { /* bit[0(1)]: 0:80, 1:40 */ hwif->udma_four = (reg47 & mask) ? 0 : 1; + } hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate; + if (!noautodma) hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c new file mode 100644 index 000000000000..2ad72bbda342 --- /dev/null +++ b/drivers/ide/pci/tc86c001.c @@ -0,0 +1,309 @@ +/* + * 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; +} + +static 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 __devinit 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 __init 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/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/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index af939796750d..d2bb5a9a303f 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -360,8 +360,7 @@ static int netevent_callback(struct notifier_block *self, unsigned long event, if (event == NETEVENT_NEIGH_UPDATE) { struct neighbour *neigh = ctx; - if (neigh->dev->type == ARPHRD_INFINIBAND && - (neigh->nud_state & NUD_VALID)) { + if (neigh->nud_state & NUD_VALID) { set_timeout(jiffies); } } diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 5ed141ebd1c8..13efd4170349 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -642,7 +642,8 @@ static void snoop_recv(struct ib_mad_qp_info *qp_info, spin_unlock_irqrestore(&qp_info->snoop_lock, flags); } -static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num, +static void build_smp_wc(struct ib_qp *qp, + u64 wr_id, u16 slid, u16 pkey_index, u8 port_num, struct ib_wc *wc) { memset(wc, 0, sizeof *wc); @@ -652,7 +653,7 @@ static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num, wc->pkey_index = pkey_index; wc->byte_len = sizeof(struct ib_mad) + sizeof(struct ib_grh); wc->src_qp = IB_QP0; - wc->qp_num = IB_QP0; + wc->qp = qp; wc->slid = slid; wc->sl = 0; wc->dlid_path_bits = 0; @@ -713,7 +714,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, goto out; } - build_smp_wc(send_wr->wr_id, be16_to_cpu(smp->dr_slid), + build_smp_wc(mad_agent_priv->agent.qp, + send_wr->wr_id, be16_to_cpu(smp->dr_slid), send_wr->wr.ud.pkey_index, send_wr->wr.ud.port_num, &mad_wc); @@ -2355,7 +2357,8 @@ static void local_completions(struct work_struct *work) * Defined behavior is to complete response * before request */ - build_smp_wc((unsigned long) local->mad_send_wr, + build_smp_wc(recv_mad_agent->agent.qp, + (unsigned long) local->mad_send_wr, be16_to_cpu(IB_LID_PERMISSIVE), 0, recv_mad_agent->agent.port_num, &wc); diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 743247ec065e..df1efbc10882 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -933,7 +933,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, resp->wc[i].vendor_err = wc[i].vendor_err; resp->wc[i].byte_len = wc[i].byte_len; resp->wc[i].imm_data = (__u32 __force) wc[i].imm_data; - resp->wc[i].qp_num = wc[i].qp_num; + resp->wc[i].qp_num = wc[i].qp->qp_num; resp->wc[i].src_qp = wc[i].src_qp; resp->wc[i].wc_flags = wc[i].wc_flags; resp->wc[i].pkey_index = wc[i].pkey_index; diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c index 05c9154d46f4..5175c99ee586 100644 --- a/drivers/infiniband/hw/amso1100/c2_cq.c +++ b/drivers/infiniband/hw/amso1100/c2_cq.c @@ -153,7 +153,7 @@ static inline int c2_poll_one(struct c2_dev *c2dev, entry->status = c2_cqe_status_to_openib(c2_wr_get_result(ce)); entry->wr_id = ce->hdr.context; - entry->qp_num = ce->handle; + entry->qp = &qp->ibqp; entry->wc_flags = 0; entry->slid = 0; entry->sl = 0; diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 1c722032319c..cf95ee474b0f 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -119,13 +119,14 @@ struct ehca_qp { struct ipz_qp_handle ipz_qp_handle; struct ehca_pfqp pf; struct ib_qp_init_attr init_attr; - u64 uspace_squeue; - u64 uspace_rqueue; - u64 uspace_fwh; struct ehca_cq *send_cq; struct ehca_cq *recv_cq; unsigned int sqerr_purgeflag; struct hlist_node list_entries; + /* mmap counter for resources mapped into user space */ + u32 mm_count_squeue; + u32 mm_count_rqueue; + u32 mm_count_galpa; }; /* must be power of 2 */ @@ -142,13 +143,14 @@ struct ehca_cq { struct ipz_cq_handle ipz_cq_handle; struct ehca_pfcq pf; spinlock_t cb_lock; - u64 uspace_queue; - u64 uspace_fwh; struct hlist_head qp_hashtab[QP_HASHTAB_LEN]; struct list_head entry; u32 nr_callbacks; spinlock_t task_lock; u32 ownpid; + /* mmap counter for resources mapped into user space */ + u32 mm_count_queue; + u32 mm_count_galpa; }; enum ehca_mr_flag { @@ -248,20 +250,6 @@ struct ehca_ucontext { struct ib_ucontext ib_ucontext; }; -struct ehca_module *ehca_module_new(void); - -int ehca_module_delete(struct ehca_module *me); - -int ehca_eq_ctor(struct ehca_eq *eq); - -int ehca_eq_dtor(struct ehca_eq *eq); - -struct ehca_shca *ehca_shca_new(void); - -int ehca_shca_delete(struct ehca_shca *me); - -struct ehca_sport *ehca_sport_new(struct ehca_shca *anchor); - int ehca_init_pd_cache(void); void ehca_cleanup_pd_cache(void); int ehca_init_cq_cache(void); @@ -283,7 +271,6 @@ extern int ehca_port_act_time; extern int ehca_use_hp_mr; struct ipzu_queue_resp { - u64 queue; /* points to first queue entry */ u32 qe_size; /* queue entry size */ u32 act_nr_of_sg; u32 queue_length; /* queue length allocated in bytes */ @@ -296,7 +283,6 @@ struct ehca_create_cq_resp { u32 cq_number; u32 token; struct ipzu_queue_resp ipz_queue; - struct h_galpas galpas; }; struct ehca_create_qp_resp { @@ -309,7 +295,6 @@ struct ehca_create_qp_resp { u32 dummy; /* padding for 8 byte alignment */ struct ipzu_queue_resp ipz_squeue; struct ipzu_queue_resp ipz_rqueue; - struct h_galpas galpas; }; struct ehca_alloc_cq_parms { diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index 6074c897f51c..9291a86ca053 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -267,7 +267,6 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, if (context) { struct ipz_queue *ipz_queue = &my_cq->ipz_queue; struct ehca_create_cq_resp resp; - struct vm_area_struct *vma; memset(&resp, 0, sizeof(resp)); resp.cq_number = my_cq->cq_number; resp.token = my_cq->token; @@ -276,40 +275,14 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, resp.ipz_queue.queue_length = ipz_queue->queue_length; resp.ipz_queue.pagesize = ipz_queue->pagesize; resp.ipz_queue.toggle_state = ipz_queue->toggle_state; - ret = ehca_mmap_nopage(((u64)(my_cq->token) << 32) | 0x12000000, - ipz_queue->queue_length, - (void**)&resp.ipz_queue.queue, - &vma); - if (ret) { - ehca_err(device, "Could not mmap queue pages"); - cq = ERR_PTR(ret); - goto create_cq_exit4; - } - my_cq->uspace_queue = resp.ipz_queue.queue; - resp.galpas = my_cq->galpas; - ret = ehca_mmap_register(my_cq->galpas.user.fw_handle, - (void**)&resp.galpas.kernel.fw_handle, - &vma); - if (ret) { - ehca_err(device, "Could not mmap fw_handle"); - cq = ERR_PTR(ret); - goto create_cq_exit5; - } - my_cq->uspace_fwh = (u64)resp.galpas.kernel.fw_handle; if (ib_copy_to_udata(udata, &resp, sizeof(resp))) { ehca_err(device, "Copy to udata failed."); - goto create_cq_exit6; + goto create_cq_exit4; } } return cq; -create_cq_exit6: - ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE); - -create_cq_exit5: - ehca_munmap(my_cq->uspace_queue, my_cq->ipz_queue.queue_length); - create_cq_exit4: ipz_queue_dtor(&my_cq->ipz_queue); @@ -333,7 +306,6 @@ create_cq_exit1: int ehca_destroy_cq(struct ib_cq *cq) { u64 h_ret; - int ret; struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); int cq_num = my_cq->cq_number; struct ib_device *device = cq->device; @@ -343,6 +315,20 @@ int ehca_destroy_cq(struct ib_cq *cq) u32 cur_pid = current->tgid; unsigned long flags; + if (cq->uobject) { + if (my_cq->mm_count_galpa || my_cq->mm_count_queue) { + ehca_err(device, "Resources still referenced in " + "user space cq_num=%x", my_cq->cq_number); + return -EINVAL; + } + if (my_cq->ownpid != cur_pid) { + ehca_err(device, "Invalid caller pid=%x ownpid=%x " + "cq_num=%x", + cur_pid, my_cq->ownpid, my_cq->cq_number); + return -EINVAL; + } + } + spin_lock_irqsave(&ehca_cq_idr_lock, flags); while (my_cq->nr_callbacks) { spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); @@ -353,25 +339,6 @@ int ehca_destroy_cq(struct ib_cq *cq) idr_remove(&ehca_cq_idr, my_cq->token); spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); - if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) { - ehca_err(device, "Invalid caller pid=%x ownpid=%x", - cur_pid, my_cq->ownpid); - return -EINVAL; - } - - /* un-mmap if vma alloc */ - if (my_cq->uspace_queue ) { - ret = ehca_munmap(my_cq->uspace_queue, - my_cq->ipz_queue.queue_length); - if (ret) - ehca_err(device, "Could not munmap queue ehca_cq=%p " - "cq_num=%x", my_cq, cq_num); - ret = ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE); - if (ret) - ehca_err(device, "Could not munmap fwh ehca_cq=%p " - "cq_num=%x", my_cq, cq_num); - } - h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0); if (h_ret == H_R_STATE) { /* cq in err: read err data and destroy it forcibly */ @@ -400,7 +367,7 @@ int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata) struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq); u32 cur_pid = current->tgid; - if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) { + if (cq->uobject && my_cq->ownpid != cur_pid) { ehca_err(cq->device, "Invalid caller pid=%x ownpid=%x", cur_pid, my_cq->ownpid); return -EINVAL; diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h index cd7789f0d08e..95fd59fb4528 100644 --- a/drivers/infiniband/hw/ehca/ehca_iverbs.h +++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h @@ -171,14 +171,6 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); void ehca_poll_eqs(unsigned long data); -int ehca_mmap_nopage(u64 foffset,u64 length,void **mapped, - struct vm_area_struct **vma); - -int ehca_mmap_register(u64 physical,void **mapped, - struct vm_area_struct **vma); - -int ehca_munmap(unsigned long addr, size_t len); - #ifdef CONFIG_PPC_64K_PAGES void *ehca_alloc_fw_ctrlblock(gfp_t flags); void ehca_free_fw_ctrlblock(void *ptr); diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 6574fbbaead5..1155bcf48212 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -52,7 +52,7 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Christoph Raisch "); MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver"); -MODULE_VERSION("SVNEHCA_0019"); +MODULE_VERSION("SVNEHCA_0020"); int ehca_open_aqp1 = 0; int ehca_debug_level = 0; @@ -288,7 +288,7 @@ int ehca_init_device(struct ehca_shca *shca) strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX); shca->ib_device.owner = THIS_MODULE; - shca->ib_device.uverbs_abi_ver = 5; + shca->ib_device.uverbs_abi_ver = 6; shca->ib_device.uverbs_cmd_mask = (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | @@ -790,7 +790,7 @@ int __init ehca_module_init(void) int ret; printk(KERN_INFO "eHCA Infiniband Device Driver " - "(Rel.: SVNEHCA_0019)\n"); + "(Rel.: SVNEHCA_0020)\n"); idr_init(&ehca_qp_idr); idr_init(&ehca_cq_idr); spin_lock_init(&ehca_qp_idr_lock); diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 34b85556d01e..95efef921f1d 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -637,7 +637,6 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd, struct ipz_queue *ipz_rqueue = &my_qp->ipz_rqueue; struct ipz_queue *ipz_squeue = &my_qp->ipz_squeue; struct ehca_create_qp_resp resp; - struct vm_area_struct * vma; memset(&resp, 0, sizeof(resp)); resp.qp_num = my_qp->real_qp_num; @@ -651,59 +650,21 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd, resp.ipz_rqueue.queue_length = ipz_rqueue->queue_length; resp.ipz_rqueue.pagesize = ipz_rqueue->pagesize; resp.ipz_rqueue.toggle_state = ipz_rqueue->toggle_state; - ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x22000000, - ipz_rqueue->queue_length, - (void**)&resp.ipz_rqueue.queue, - &vma); - if (ret) { - ehca_err(pd->device, "Could not mmap rqueue pages"); - goto create_qp_exit3; - } - my_qp->uspace_rqueue = resp.ipz_rqueue.queue; /* squeue properties */ resp.ipz_squeue.qe_size = ipz_squeue->qe_size; resp.ipz_squeue.act_nr_of_sg = ipz_squeue->act_nr_of_sg; resp.ipz_squeue.queue_length = ipz_squeue->queue_length; resp.ipz_squeue.pagesize = ipz_squeue->pagesize; resp.ipz_squeue.toggle_state = ipz_squeue->toggle_state; - ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x23000000, - ipz_squeue->queue_length, - (void**)&resp.ipz_squeue.queue, - &vma); - if (ret) { - ehca_err(pd->device, "Could not mmap squeue pages"); - goto create_qp_exit4; - } - my_qp->uspace_squeue = resp.ipz_squeue.queue; - /* fw_handle */ - resp.galpas = my_qp->galpas; - ret = ehca_mmap_register(my_qp->galpas.user.fw_handle, - (void**)&resp.galpas.kernel.fw_handle, - &vma); - if (ret) { - ehca_err(pd->device, "Could not mmap fw_handle"); - goto create_qp_exit5; - } - my_qp->uspace_fwh = (u64)resp.galpas.kernel.fw_handle; - if (ib_copy_to_udata(udata, &resp, sizeof resp)) { ehca_err(pd->device, "Copy to udata failed"); ret = -EINVAL; - goto create_qp_exit6; + goto create_qp_exit3; } } return &my_qp->ib_qp; -create_qp_exit6: - ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE); - -create_qp_exit5: - ehca_munmap(my_qp->uspace_squeue, my_qp->ipz_squeue.queue_length); - -create_qp_exit4: - ehca_munmap(my_qp->uspace_rqueue, my_qp->ipz_rqueue.queue_length); - create_qp_exit3: ipz_queue_dtor(&my_qp->ipz_rqueue); ipz_queue_dtor(&my_qp->ipz_squeue); @@ -931,7 +892,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, my_qp->qp_type == IB_QPT_SMI) && statetrans == IB_QPST_SQE2RTS) { /* mark next free wqe if kernel */ - if (my_qp->uspace_squeue == 0) { + if (!ibqp->uobject) { struct ehca_wqe *wqe; /* lock send queue */ spin_lock_irqsave(&my_qp->spinlock_s, spl_flags); @@ -1417,11 +1378,18 @@ int ehca_destroy_qp(struct ib_qp *ibqp) enum ib_qp_type qp_type; unsigned long flags; - if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context && - my_pd->ownpid != cur_pid) { - ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x", - cur_pid, my_pd->ownpid); - return -EINVAL; + if (ibqp->uobject) { + if (my_qp->mm_count_galpa || + my_qp->mm_count_rqueue || my_qp->mm_count_squeue) { + ehca_err(ibqp->device, "Resources still referenced in " + "user space qp_num=%x", ibqp->qp_num); + return -EINVAL; + } + if (my_pd->ownpid != cur_pid) { + ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x", + cur_pid, my_pd->ownpid); + return -EINVAL; + } } if (my_qp->send_cq) { @@ -1439,24 +1407,6 @@ int ehca_destroy_qp(struct ib_qp *ibqp) idr_remove(&ehca_qp_idr, my_qp->token); spin_unlock_irqrestore(&ehca_qp_idr_lock, flags); - /* un-mmap if vma alloc */ - if (my_qp->uspace_rqueue) { - ret = ehca_munmap(my_qp->uspace_rqueue, - my_qp->ipz_rqueue.queue_length); - if (ret) - ehca_err(ibqp->device, "Could not munmap rqueue " - "qp_num=%x", qp_num); - ret = ehca_munmap(my_qp->uspace_squeue, - my_qp->ipz_squeue.queue_length); - if (ret) - ehca_err(ibqp->device, "Could not munmap squeue " - "qp_num=%x", qp_num); - ret = ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE); - if (ret) - ehca_err(ibqp->device, "Could not munmap fwh qp_num=%x", - qp_num); - } - h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp); if (h_ret != H_SUCCESS) { ehca_err(ibqp->device, "hipz_h_destroy_qp() failed rc=%lx " diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index b46bda1bf85d..08d3f892d9f3 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -579,7 +579,7 @@ poll_cq_one_read_cqe: } else wc->status = IB_WC_SUCCESS; - wc->qp_num = cqe->local_qp_number; + wc->qp = NULL; wc->byte_len = cqe->nr_bytes_transferred; wc->pkey_index = cqe->pkey_index; wc->slid = cqe->rlid; diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c index e08764e4aef2..73db920b6945 100644 --- a/drivers/infiniband/hw/ehca/ehca_uverbs.c +++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c @@ -68,104 +68,182 @@ int ehca_dealloc_ucontext(struct ib_ucontext *context) return 0; } -struct page *ehca_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static void ehca_mm_open(struct vm_area_struct *vma) { - struct page *mypage = NULL; - u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT; - u32 idr_handle = fileoffset >> 32; - u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */ - u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */ - u32 cur_pid = current->tgid; - unsigned long flags; - struct ehca_cq *cq; - struct ehca_qp *qp; - struct ehca_pd *pd; - u64 offset; - void *vaddr; + u32 *count = (u32*)vma->vm_private_data; + if (!count) { + ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx", + vma->vm_start, vma->vm_end); + return; + } + (*count)++; + if (!(*count)) + ehca_gen_err("Use count overflow vm_start=%lx vm_end=%lx", + vma->vm_start, vma->vm_end); + ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x", + vma->vm_start, vma->vm_end, *count); +} - switch (q_type) { - case 1: /* CQ */ - spin_lock_irqsave(&ehca_cq_idr_lock, flags); - cq = idr_find(&ehca_cq_idr, idr_handle); - spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); +static void ehca_mm_close(struct vm_area_struct *vma) +{ + u32 *count = (u32*)vma->vm_private_data; + if (!count) { + ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx", + vma->vm_start, vma->vm_end); + return; + } + (*count)--; + ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x", + vma->vm_start, vma->vm_end, *count); +} - /* make sure this mmap really belongs to the authorized user */ - if (!cq) { - ehca_gen_err("cq is NULL ret=NOPAGE_SIGBUS"); - return NOPAGE_SIGBUS; +static struct vm_operations_struct vm_ops = { + .open = ehca_mm_open, + .close = ehca_mm_close, +}; + +static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas, + u32 *mm_count) +{ + int ret; + u64 vsize, physical; + + vsize = vma->vm_end - vma->vm_start; + if (vsize != EHCA_PAGESIZE) { + ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start); + return -EINVAL; + } + + physical = galpas->user.fw_handle; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical); + /* VM_IO | VM_RESERVED are set by remap_pfn_range() */ + ret = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT, + vsize, vma->vm_page_prot); + if (unlikely(ret)) { + ehca_gen_err("remap_pfn_range() failed ret=%x", ret); + return -ENOMEM; + } + + vma->vm_private_data = mm_count; + (*mm_count)++; + vma->vm_ops = &vm_ops; + + return 0; +} + +static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue, + u32 *mm_count) +{ + int ret; + u64 start, ofs; + struct page *page; + + vma->vm_flags |= VM_RESERVED; + start = vma->vm_start; + for (ofs = 0; ofs < queue->queue_length; ofs += PAGE_SIZE) { + u64 virt_addr = (u64)ipz_qeit_calc(queue, ofs); + page = virt_to_page(virt_addr); + ret = vm_insert_page(vma, start, page); + if (unlikely(ret)) { + ehca_gen_err("vm_insert_page() failed rc=%x", ret); + return ret; } + start += PAGE_SIZE; + } + vma->vm_private_data = mm_count; + (*mm_count)++; + vma->vm_ops = &vm_ops; - if (cq->ownpid != cur_pid) { + return 0; +} + +static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq, + u32 rsrc_type) +{ + int ret; + + switch (rsrc_type) { + case 1: /* galpa fw handle */ + ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number); + ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa); + if (unlikely(ret)) { ehca_err(cq->ib_cq.device, - "Invalid caller pid=%x ownpid=%x", - cur_pid, cq->ownpid); - return NOPAGE_SIGBUS; - } - - if (rsrc_type == 2) { - ehca_dbg(cq->ib_cq.device, "cq=%p cq queuearea", cq); - offset = address - vma->vm_start; - vaddr = ipz_qeit_calc(&cq->ipz_queue, offset); - ehca_dbg(cq->ib_cq.device, "offset=%lx vaddr=%p", - offset, vaddr); - mypage = virt_to_page(vaddr); + "ehca_mmap_fw() failed rc=%x cq_num=%x", + ret, cq->cq_number); + return ret; } break; - case 2: /* QP */ - spin_lock_irqsave(&ehca_qp_idr_lock, flags); - qp = idr_find(&ehca_qp_idr, idr_handle); - spin_unlock_irqrestore(&ehca_qp_idr_lock, flags); - - /* make sure this mmap really belongs to the authorized user */ - if (!qp) { - ehca_gen_err("qp is NULL ret=NOPAGE_SIGBUS"); - return NOPAGE_SIGBUS; - } - - pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd); - if (pd->ownpid != cur_pid) { - ehca_err(qp->ib_qp.device, - "Invalid caller pid=%x ownpid=%x", - cur_pid, pd->ownpid); - return NOPAGE_SIGBUS; - } - - if (rsrc_type == 2) { /* rqueue */ - ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueuearea", qp); - offset = address - vma->vm_start; - vaddr = ipz_qeit_calc(&qp->ipz_rqueue, offset); - ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p", - offset, vaddr); - mypage = virt_to_page(vaddr); - } else if (rsrc_type == 3) { /* squeue */ - ehca_dbg(qp->ib_qp.device, "qp=%p qp squeuearea", qp); - offset = address - vma->vm_start; - vaddr = ipz_qeit_calc(&qp->ipz_squeue, offset); - ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p", - offset, vaddr); - mypage = virt_to_page(vaddr); + case 2: /* cq queue_addr */ + ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number); + ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue); + if (unlikely(ret)) { + ehca_err(cq->ib_cq.device, + "ehca_mmap_queue() failed rc=%x cq_num=%x", + ret, cq->cq_number); + return ret; } break; default: - ehca_gen_err("bad queue type %x", q_type); - return NOPAGE_SIGBUS; + ehca_err(cq->ib_cq.device, "bad resource type=%x cq_num=%x", + rsrc_type, cq->cq_number); + return -EINVAL; } - if (!mypage) { - ehca_gen_err("Invalid page adr==NULL ret=NOPAGE_SIGBUS"); - return NOPAGE_SIGBUS; - } - get_page(mypage); - - return mypage; + return 0; } -static struct vm_operations_struct ehcau_vm_ops = { - .nopage = ehca_nopage, -}; +static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp, + u32 rsrc_type) +{ + int ret; + + switch (rsrc_type) { + case 1: /* galpa fw handle */ + ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num); + ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa); + if (unlikely(ret)) { + ehca_err(qp->ib_qp.device, + "remap_pfn_range() failed ret=%x qp_num=%x", + ret, qp->ib_qp.qp_num); + return -ENOMEM; + } + break; + + case 2: /* qp rqueue_addr */ + ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue", + qp->ib_qp.qp_num); + ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, &qp->mm_count_rqueue); + if (unlikely(ret)) { + ehca_err(qp->ib_qp.device, + "ehca_mmap_queue(rq) failed rc=%x qp_num=%x", + ret, qp->ib_qp.qp_num); + return ret; + } + break; + + case 3: /* qp squeue_addr */ + ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue", + qp->ib_qp.qp_num); + ret = ehca_mmap_queue(vma, &qp->ipz_squeue, &qp->mm_count_squeue); + if (unlikely(ret)) { + ehca_err(qp->ib_qp.device, + "ehca_mmap_queue(sq) failed rc=%x qp_num=%x", + ret, qp->ib_qp.qp_num); + return ret; + } + break; + + default: + ehca_err(qp->ib_qp.device, "bad resource type=%x qp=num=%x", + rsrc_type, qp->ib_qp.qp_num); + return -EINVAL; + } + + return 0; +} int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) { @@ -175,7 +253,6 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */ u32 cur_pid = current->tgid; u32 ret; - u64 vsize, physical; unsigned long flags; struct ehca_cq *cq; struct ehca_qp *qp; @@ -201,44 +278,12 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context) return -EINVAL; - switch (rsrc_type) { - case 1: /* galpa fw handle */ - ehca_dbg(cq->ib_cq.device, "cq=%p cq triggerarea", cq); - vma->vm_flags |= VM_RESERVED; - vsize = vma->vm_end - vma->vm_start; - if (vsize != EHCA_PAGESIZE) { - ehca_err(cq->ib_cq.device, "invalid vsize=%lx", - vma->vm_end - vma->vm_start); - return -EINVAL; - } - - physical = cq->galpas.user.fw_handle; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - vma->vm_flags |= VM_IO | VM_RESERVED; - - ehca_dbg(cq->ib_cq.device, - "vsize=%lx physical=%lx", vsize, physical); - ret = remap_pfn_range(vma, vma->vm_start, - physical >> PAGE_SHIFT, vsize, - vma->vm_page_prot); - if (ret) { - ehca_err(cq->ib_cq.device, - "remap_pfn_range() failed ret=%x", - ret); - return -ENOMEM; - } - break; - - case 2: /* cq queue_addr */ - ehca_dbg(cq->ib_cq.device, "cq=%p cq q_addr", cq); - vma->vm_flags |= VM_RESERVED; - vma->vm_ops = &ehcau_vm_ops; - break; - - default: - ehca_err(cq->ib_cq.device, "bad resource type %x", - rsrc_type); - return -EINVAL; + ret = ehca_mmap_cq(vma, cq, rsrc_type); + if (unlikely(ret)) { + ehca_err(cq->ib_cq.device, + "ehca_mmap_cq() failed rc=%x cq_num=%x", + ret, cq->cq_number); + return ret; } break; @@ -262,50 +307,12 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) if (!qp->ib_qp.uobject || qp->ib_qp.uobject->context != context) return -EINVAL; - switch (rsrc_type) { - case 1: /* galpa fw handle */ - ehca_dbg(qp->ib_qp.device, "qp=%p qp triggerarea", qp); - vma->vm_flags |= VM_RESERVED; - vsize = vma->vm_end - vma->vm_start; - if (vsize != EHCA_PAGESIZE) { - ehca_err(qp->ib_qp.device, "invalid vsize=%lx", - vma->vm_end - vma->vm_start); - return -EINVAL; - } - - physical = qp->galpas.user.fw_handle; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - vma->vm_flags |= VM_IO | VM_RESERVED; - - ehca_dbg(qp->ib_qp.device, "vsize=%lx physical=%lx", - vsize, physical); - ret = remap_pfn_range(vma, vma->vm_start, - physical >> PAGE_SHIFT, vsize, - vma->vm_page_prot); - if (ret) { - ehca_err(qp->ib_qp.device, - "remap_pfn_range() failed ret=%x", - ret); - return -ENOMEM; - } - break; - - case 2: /* qp rqueue_addr */ - ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueue_addr", qp); - vma->vm_flags |= VM_RESERVED; - vma->vm_ops = &ehcau_vm_ops; - break; - - case 3: /* qp squeue_addr */ - ehca_dbg(qp->ib_qp.device, "qp=%p qp squeue_addr", qp); - vma->vm_flags |= VM_RESERVED; - vma->vm_ops = &ehcau_vm_ops; - break; - - default: - ehca_err(qp->ib_qp.device, "bad resource type %x", - rsrc_type); - return -EINVAL; + ret = ehca_mmap_qp(vma, qp, rsrc_type); + if (unlikely(ret)) { + ehca_err(qp->ib_qp.device, + "ehca_mmap_qp() failed rc=%x qp_num=%x", + ret, qp->ib_qp.qp_num); + return ret; } break; @@ -316,77 +323,3 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) return 0; } - -int ehca_mmap_nopage(u64 foffset, u64 length, void **mapped, - struct vm_area_struct **vma) -{ - down_write(¤t->mm->mmap_sem); - *mapped = (void*)do_mmap(NULL,0, length, PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS, - foffset); - up_write(¤t->mm->mmap_sem); - if (!(*mapped)) { - ehca_gen_err("couldn't mmap foffset=%lx length=%lx", - foffset, length); - return -EINVAL; - } - - *vma = find_vma(current->mm, (u64)*mapped); - if (!(*vma)) { - down_write(¤t->mm->mmap_sem); - do_munmap(current->mm, 0, length); - up_write(¤t->mm->mmap_sem); - ehca_gen_err("couldn't find vma queue=%p", *mapped); - return -EINVAL; - } - (*vma)->vm_flags |= VM_RESERVED; - (*vma)->vm_ops = &ehcau_vm_ops; - - return 0; -} - -int ehca_mmap_register(u64 physical, void **mapped, - struct vm_area_struct **vma) -{ - int ret; - unsigned long vsize; - /* ehca hw supports only 4k page */ - ret = ehca_mmap_nopage(0, EHCA_PAGESIZE, mapped, vma); - if (ret) { - ehca_gen_err("could'nt mmap physical=%lx", physical); - return ret; - } - - (*vma)->vm_flags |= VM_RESERVED; - vsize = (*vma)->vm_end - (*vma)->vm_start; - if (vsize != EHCA_PAGESIZE) { - ehca_gen_err("invalid vsize=%lx", - (*vma)->vm_end - (*vma)->vm_start); - return -EINVAL; - } - - (*vma)->vm_page_prot = pgprot_noncached((*vma)->vm_page_prot); - (*vma)->vm_flags |= VM_IO | VM_RESERVED; - - ret = remap_pfn_range((*vma), (*vma)->vm_start, - physical >> PAGE_SHIFT, vsize, - (*vma)->vm_page_prot); - if (ret) { - ehca_gen_err("remap_pfn_range() failed ret=%x", ret); - return -ENOMEM; - } - - return 0; - -} - -int ehca_munmap(unsigned long addr, size_t len) { - int ret = 0; - struct mm_struct *mm = current->mm; - if (mm) { - down_write(&mm->mmap_sem); - ret = do_munmap(mm, addr, len); - up_write(&mm->mmap_sem); - } - return ret; -} diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c index 46c1c89bf6ae..64f07b19349f 100644 --- a/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/drivers/infiniband/hw/ipath/ipath_qp.c @@ -379,7 +379,7 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err) wc.vendor_err = 0; wc.byte_len = 0; wc.imm_data = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = 0; wc.wc_flags = 0; wc.pkey_index = 0; diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c index ce6038743c5c..5ff20cb04494 100644 --- a/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/drivers/infiniband/hw/ipath/ipath_rc.c @@ -702,7 +702,7 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc) wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; wc->vendor_err = 0; wc->byte_len = 0; - wc->qp_num = qp->ibqp.qp_num; + wc->qp = &qp->ibqp; wc->src_qp = qp->remote_qpn; wc->pkey_index = 0; wc->slid = qp->remote_ah_attr.dlid; @@ -836,7 +836,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; wc.vendor_err = 0; wc.byte_len = wqe->length; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; wc.pkey_index = 0; wc.slid = qp->remote_ah_attr.dlid; @@ -951,7 +951,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; wc.vendor_err = 0; wc.byte_len = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; wc.pkey_index = 0; wc.slid = qp->remote_ah_attr.dlid; @@ -1511,7 +1511,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, wc.status = IB_WC_SUCCESS; wc.opcode = IB_WC_RECV; wc.vendor_err = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; wc.pkey_index = 0; wc.slid = qp->remote_ah_attr.dlid; diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c index f7530512045d..e86cb171872e 100644 --- a/drivers/infiniband/hw/ipath/ipath_ruc.c +++ b/drivers/infiniband/hw/ipath/ipath_ruc.c @@ -137,7 +137,7 @@ bad_lkey: wc.vendor_err = 0; wc.byte_len = 0; wc.imm_data = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = 0; wc.wc_flags = 0; wc.pkey_index = 0; @@ -336,7 +336,7 @@ again: wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; wc.vendor_err = 0; wc.byte_len = 0; - wc.qp_num = sqp->ibqp.qp_num; + wc.qp = &sqp->ibqp; wc.src_qp = sqp->remote_qpn; wc.pkey_index = 0; wc.slid = sqp->remote_ah_attr.dlid; @@ -426,7 +426,7 @@ again: wc.status = IB_WC_SUCCESS; wc.vendor_err = 0; wc.byte_len = wqe->length; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; /* XXX do we know which pkey matched? Only needed for GSI. */ wc.pkey_index = 0; @@ -447,7 +447,7 @@ send_comp: wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; wc.vendor_err = 0; wc.byte_len = wqe->length; - wc.qp_num = sqp->ibqp.qp_num; + wc.qp = &sqp->ibqp; wc.src_qp = 0; wc.pkey_index = 0; wc.slid = 0; diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c index e636cfd67a82..325d6634ff53 100644 --- a/drivers/infiniband/hw/ipath/ipath_uc.c +++ b/drivers/infiniband/hw/ipath/ipath_uc.c @@ -49,7 +49,7 @@ static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe, wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; wc->vendor_err = 0; wc->byte_len = wqe->length; - wc->qp_num = qp->ibqp.qp_num; + wc->qp = &qp->ibqp; wc->src_qp = qp->remote_qpn; wc->pkey_index = 0; wc->slid = qp->remote_ah_attr.dlid; @@ -411,7 +411,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, wc.status = IB_WC_SUCCESS; wc.opcode = IB_WC_RECV; wc.vendor_err = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = qp->remote_qpn; wc.pkey_index = 0; wc.slid = qp->remote_ah_attr.dlid; diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c index 49f1102af8b3..9a3e54664ee4 100644 --- a/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/drivers/infiniband/hw/ipath/ipath_ud.c @@ -66,7 +66,7 @@ bad_lkey: wc.vendor_err = 0; wc.byte_len = 0; wc.imm_data = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = 0; wc.wc_flags = 0; wc.pkey_index = 0; @@ -255,7 +255,7 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, wc->status = IB_WC_SUCCESS; wc->opcode = IB_WC_RECV; wc->vendor_err = 0; - wc->qp_num = qp->ibqp.qp_num; + wc->qp = &qp->ibqp; wc->src_qp = sqp->ibqp.qp_num; /* XXX do we know which pkey matched? Only needed for GSI. */ wc->pkey_index = 0; @@ -474,7 +474,7 @@ done: wc.vendor_err = 0; wc.opcode = IB_WC_SEND; wc.byte_len = len; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = 0; wc.wc_flags = 0; /* XXX initialize other fields? */ @@ -651,7 +651,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, wc.status = IB_WC_SUCCESS; wc.opcode = IB_WC_RECV; wc.vendor_err = 0; - wc.qp_num = qp->ibqp.qp_num; + wc.qp = &qp->ibqp; wc.src_qp = src_qp; /* XXX do we know which pkey matched? Only needed for GSI. */ wc.pkey_index = 0; diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index 768df7265b81..968d1519761c 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -1854,7 +1854,7 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey, memset(inbox + 256, 0, 256); - MTHCA_PUT(inbox, in_wc->qp_num, MAD_IFC_MY_QPN_OFFSET); + MTHCA_PUT(inbox, in_wc->qp->qp_num, MAD_IFC_MY_QPN_OFFSET); MTHCA_PUT(inbox, in_wc->src_qp, MAD_IFC_RQPN_OFFSET); val = in_wc->sl << 4; diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index 1159c8a0f2c5..efd79ef109a6 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -534,7 +534,7 @@ static inline int mthca_poll_one(struct mthca_dev *dev, } } - entry->qp_num = (*cur_qp)->qpn; + entry->qp = &(*cur_qp)->ibqp; if (is_send) { wq = &(*cur_qp)->sq; 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/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 72611fd15103..5e8ac577f0ad 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -548,6 +548,7 @@ static int srp_reconnect_target(struct srp_target_port *target) target->tx_head = 0; target->tx_tail = 0; + target->qp_in_error = 0; ret = srp_connect_target(target); if (ret) goto err; @@ -878,6 +879,7 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr) printk(KERN_ERR PFX "failed %s status %d\n", wc.wr_id & SRP_OP_RECV ? "receive" : "send", wc.status); + target->qp_in_error = 1; break; } @@ -1337,6 +1339,8 @@ static int srp_abort(struct scsi_cmnd *scmnd) printk(KERN_ERR "SRP abort called\n"); + if (target->qp_in_error) + return FAILED; if (srp_find_req(target, scmnd, &req)) return FAILED; if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK)) @@ -1365,6 +1369,8 @@ static int srp_reset_device(struct scsi_cmnd *scmnd) printk(KERN_ERR "SRP reset_device called\n"); + if (target->qp_in_error) + return FAILED; if (srp_find_req(target, scmnd, &req)) return FAILED; if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET)) @@ -1801,6 +1807,7 @@ static ssize_t srp_create_target(struct class_device *class_dev, goto err_free; } + target->qp_in_error = 0; ret = srp_connect_target(target); if (ret) { printk(KERN_ERR PFX "Connection failed\n"); diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index c21772317b86..2f3319c719a5 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -158,6 +158,7 @@ struct srp_target_port { struct completion done; int status; enum srp_target_state state; + int qp_in_error; }; struct srp_iu { 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/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h index 4363a915b1f4..3daf049a288a 100644 --- a/drivers/media/video/zc0301/zc0301_sensor.h +++ b/drivers/media/video/zc0301/zc0301_sensor.h @@ -75,7 +75,6 @@ static const struct usb_device_id zc0301_id_table[] = { \ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \ { ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */ \ { ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \ { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \ { ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */ \ { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \ diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 00db31c314e0..89bba277da5f 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -69,6 +69,25 @@ config TIFM_7XX1 To compile this driver as a module, choose M here: the module will be called tifm_7xx1. +config ASUS_LAPTOP + tristate "Asus Laptop Extras (EXPERIMENTAL)" + depends on X86 + depends on ACPI + depends on EXPERIMENTAL && !ACPI_ASUS + depends on LEDS_CLASS + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is the new Linux driver for Asus laptops. It may also support some + MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate + standard ACPI events that go through /proc/acpi/events. It also adds + support for video output switching, LCD backlight control, Bluetooth and + Wlan control, and most importantly, allows you to blink those fancy LEDs. + + For more information and a userspace daemon for handling the extra + buttons see . + + If you have an ACPI-compatible ASUS laptop, say Y or M here. + config MSI_LAPTOP tristate "MSI Laptop Extras" depends on X86 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index c9e98ab021c5..35da53c409c0 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -6,6 +6,7 @@ obj- := misc.o # Dummy rule to force built-in.o to be made obj-$(CONFIG_IBM_ASM) += ibmasm/ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o +obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c new file mode 100644 index 000000000000..861c39935f99 --- /dev/null +++ b/drivers/misc/asus-laptop.c @@ -0,0 +1,1165 @@ +/* + * asus-laptop.c - Asus Laptop Support + * + * + * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor + * Copyright (C) 2006 Corentin Chary + * + * This 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 development page for this driver is located at + * http://sourceforge.net/projects/acpi4asus/ + * + * Credits: + * Pontus Fuchs - Helper functions, cleanup + * Johann Wiesner - Small compile fixes + * John Belmonte - ACPI code for Toshiba laptop was a good starting point. + * Eric Burghard - LED display support for W1N + * Josh Green - Light Sens support + * Thomas Tuttle - His first patch for led support was very helpfull + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ASUS_LAPTOP_VERSION "0.40" + +#define ASUS_HOTK_NAME "Asus Laptop Support" +#define ASUS_HOTK_CLASS "hotkey" +#define ASUS_HOTK_DEVICE_NAME "Hotkey" +#define ASUS_HOTK_HID "ATK0100" +#define ASUS_HOTK_FILE "asus-laptop" +#define ASUS_HOTK_PREFIX "\\_SB.ATKD." + +/* + * Some events we use, same for all Asus + */ +#define ATKD_BR_UP 0x10 +#define ATKD_BR_DOWN 0x20 +#define ATKD_LCD_ON 0x33 +#define ATKD_LCD_OFF 0x34 + +/* + * Known bits returned by \_SB.ATKD.HWRS + */ +#define WL_HWRS 0x80 +#define BT_HWRS 0x100 + +/* + * Flags for hotk status + * WL_ON and BT_ON are also used for wireless_status() + */ +#define WL_ON 0x01 //internal Wifi +#define BT_ON 0x02 //internal Bluetooth +#define MLED_ON 0x04 //mail LED +#define TLED_ON 0x08 //touchpad LED +#define RLED_ON 0x10 //Record LED +#define PLED_ON 0x20 //Phone LED +#define LCD_ON 0x40 //LCD backlight + +#define ASUS_LOG ASUS_HOTK_FILE ": " +#define ASUS_ERR KERN_ERR ASUS_LOG +#define ASUS_WARNING KERN_WARNING ASUS_LOG +#define ASUS_NOTICE KERN_NOTICE ASUS_LOG +#define ASUS_INFO KERN_INFO ASUS_LOG +#define ASUS_DEBUG KERN_DEBUG ASUS_LOG + +MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary"); +MODULE_DESCRIPTION(ASUS_HOTK_NAME); +MODULE_LICENSE("GPL"); + +#define ASUS_HANDLE(object, paths...) \ + static acpi_handle object##_handle = NULL; \ + static char *object##_paths[] = { paths } + +/* LED */ +ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED"); +ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED"); +ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */ +ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */ + +/* LEDD */ +ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM"); + +/* Bluetooth and WLAN + * WLED and BLED are not handled like other XLED, because in some dsdt + * they also control the WLAN/Bluetooth device. + */ +ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED"); +ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED"); +ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS"); /* All new models */ + +/* Brightness */ +ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV"); +ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "GPLV"); + +/* Backlight */ +ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ + "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */ + "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */ + "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */ + "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */ + "\\_SB.PCI0.PX40.Q10", /* S1x */ + "\\Q10"); /* A2x, L2D, L3D, M2E */ + +/* Display */ +ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP"); +ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G + M6A M6V VX-1 V6J V6V W3Z */ + "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V + S5A M5A z33A W1Jc W2V */ + "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */ + "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */ + "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */ + "\\_SB.PCI0.VGA.GETD", /* Z96F */ + "\\ACTD", /* A2D */ + "\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ + "\\DNXT", /* P30 */ + "\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ + "\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */ + +ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ +ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ + +/* + * This is the main structure, we can use it to store anything interesting + * about the hotk device + */ +struct asus_hotk { + char *name; //laptop name + struct acpi_device *device; //the device we are in + acpi_handle handle; //the handle of the hotk device + char status; //status of the hotk, for LEDs, ... + u32 ledd_status; //status of the LED display + u8 light_level; //light sensor level + u8 light_switch; //light sensor switch value + u16 event_count[128]; //count for each event TODO make this better +}; + +/* + * This header is made available to allow proper configuration given model, + * revision number , ... this info cannot go in struct asus_hotk because it is + * available before the hotk + */ +static struct acpi_table_header *asus_info; + +/* The actual device the driver binds to */ +static struct asus_hotk *hotk; + +/* + * The hotkey driver declaration + */ +static int asus_hotk_add(struct acpi_device *device); +static int asus_hotk_remove(struct acpi_device *device, int type); +static struct acpi_driver asus_hotk_driver = { + .name = ASUS_HOTK_NAME, + .class = ASUS_HOTK_CLASS, + .ids = ASUS_HOTK_HID, + .ops = { + .add = asus_hotk_add, + .remove = asus_hotk_remove, + }, +}; + +/* The backlight device /sys/class/backlight */ +static struct backlight_device *asus_backlight_device; + +/* + * The backlight class declaration + */ +static int read_brightness(struct backlight_device *bd); +static int update_bl_status(struct backlight_device *bd); +static struct backlight_properties asusbl_data = { + .owner = THIS_MODULE, + .get_brightness = read_brightness, + .update_status = update_bl_status, + .max_brightness = 15, +}; + +/* These functions actually update the LED's, and are called from a + * workqueue. By doing this as separate work rather than when the LED + * subsystem asks, we avoid messing with the Asus ACPI stuff during a + * potentially bad time, such as a timer interrupt. */ +static struct workqueue_struct *led_workqueue; + +#define ASUS_LED(object, ledname) \ + static void object##_led_set(struct led_classdev *led_cdev, \ + enum led_brightness value); \ + static void object##_led_update(struct work_struct *ignored); \ + static int object##_led_wk; \ + DECLARE_WORK(object##_led_work, object##_led_update); \ + static struct led_classdev object##_led = { \ + .name = "asus:" ledname, \ + .brightness_set = object##_led_set, \ + } + +ASUS_LED(mled, "mail"); +ASUS_LED(tled, "touchpad"); +ASUS_LED(rled, "record"); +ASUS_LED(pled, "phone"); + +/* + * This function evaluates an ACPI method, given an int as parameter, the + * method is searched within the scope of the handle, can be NULL. The output + * of the method is written is output, which can also be NULL + * + * returns 1 if write is successful, 0 else. + */ +static int write_acpi_int(acpi_handle handle, const char *method, int val, + struct acpi_buffer *output) +{ + struct acpi_object_list params; //list of input parameters (an int here) + union acpi_object in_obj; //the only param we use + acpi_status status; + + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = val; + + status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); + return (status == AE_OK); +} + +static int read_acpi_int(acpi_handle handle, const char *method, int *val, + struct acpi_object_list *params) +{ + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, (char *)method, params, &output); + *val = out_obj.integer.value; + return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER); +} + +static int read_wireless_status(int mask) +{ + int status; + + if (!wireless_status_handle) + return (hotk->status & mask) ? 1 : 0; + + if (read_acpi_int(wireless_status_handle, NULL, &status, NULL)) { + return (status & mask) ? 1 : 0; + } else + printk(ASUS_WARNING "Error reading Wireless status\n"); + + return (hotk->status & mask) ? 1 : 0; +} + +/* Generic LED functions */ +static int read_status(int mask) +{ + /* There is a special method for both wireless devices */ + if (mask == BT_ON || mask == WL_ON) + return read_wireless_status(mask); + + return (hotk->status & mask) ? 1 : 0; +} + +static void write_status(acpi_handle handle, int out, int mask, int invert) +{ + hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask); + + if (invert) /* invert target value */ + out = !out & 0x1; + + if (handle && !write_acpi_int(handle, NULL, out, NULL)) + printk(ASUS_WARNING " write failed\n"); +} + +/* /sys/class/led handlers */ +#define ASUS_LED_HANDLER(object, mask, invert) \ + static void object##_led_set(struct led_classdev *led_cdev, \ + enum led_brightness value) \ + { \ + object##_led_wk = value; \ + queue_work(led_workqueue, &object##_led_work); \ + } \ + static void object##_led_update(struct work_struct *ignored) \ + { \ + int value = object##_led_wk; \ + write_status(object##_set_handle, value, (mask), (invert)); \ + } + +ASUS_LED_HANDLER(mled, MLED_ON, 1); +ASUS_LED_HANDLER(pled, PLED_ON, 0); +ASUS_LED_HANDLER(rled, RLED_ON, 0); +ASUS_LED_HANDLER(tled, TLED_ON, 0); + +static int get_lcd_state(void) +{ + return read_status(LCD_ON); +} + +static int set_lcd_state(int value) +{ + int lcd = 0; + acpi_status status = 0; + + lcd = value ? 1 : 0; + + if (lcd == get_lcd_state()) + return 0; + + if (lcd_switch_handle) { + status = acpi_evaluate_object(lcd_switch_handle, + NULL, NULL, NULL); + + if (ACPI_FAILURE(status)) + printk(ASUS_WARNING "Error switching LCD\n"); + } + + write_status(NULL, lcd, LCD_ON, 0); + return 0; +} + +static void lcd_blank(int blank) +{ + struct backlight_device *bd = asus_backlight_device; + + if (bd) { + down(&bd->sem); + if (likely(bd->props)) { + bd->props->power = blank; + if (likely(bd->props->update_status)) + bd->props->update_status(bd); + } + up(&bd->sem); + } +} + +static int read_brightness(struct backlight_device *bd) +{ + int value; + + if (!read_acpi_int(brightness_get_handle, NULL, &value, NULL)) + printk(ASUS_WARNING "Error reading brightness\n"); + + return value; +} + +static int set_brightness(struct backlight_device *bd, int value) +{ + int ret = 0; + + value = (0 < value) ? ((15 < value) ? 15 : value) : 0; + /* 0 <= value <= 15 */ + + if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) { + printk(ASUS_WARNING "Error changing brightness\n"); + ret = -EIO; + } + + return ret; +} + +static int update_bl_status(struct backlight_device *bd) +{ + int rv; + int value = bd->props->brightness; + + rv = set_brightness(bd, value); + if (rv) + return rv; + + value = (bd->props->power == FB_BLANK_UNBLANK) ? 1 : 0; + return set_lcd_state(value); +} + +/* + * Platform device handlers + */ + +/* + * We write our info in page, we begin at offset off and cannot write more + * than count bytes. We set eof to 1 if we handle those 2 values. We return the + * number of bytes written in page + */ +static ssize_t show_infos(struct device *dev, + struct device_attribute *attr, char *page) +{ + int len = 0; + int temp; + char buf[16]; //enough for all info + /* + * We use the easy way, we don't care of off and count, so we don't set eof + * to 1 + */ + + len += sprintf(page, ASUS_HOTK_NAME " " ASUS_LAPTOP_VERSION "\n"); + len += sprintf(page + len, "Model reference : %s\n", hotk->name); + /* + * The SFUN method probably allows the original driver to get the list + * of features supported by a given model. For now, 0x0100 or 0x0800 + * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. + * The significance of others is yet to be found. + */ + if (read_acpi_int(hotk->handle, "SFUN", &temp, NULL)) + len += + sprintf(page + len, "SFUN value : 0x%04x\n", temp); + /* + * Another value for userspace: the ASYM method returns 0x02 for + * battery low and 0x04 for battery critical, its readings tend to be + * more accurate than those provided by _BST. + * Note: since not all the laptops provide this method, errors are + * silently ignored. + */ + if (read_acpi_int(hotk->handle, "ASYM", &temp, NULL)) + len += + sprintf(page + len, "ASYM value : 0x%04x\n", temp); + if (asus_info) { + snprintf(buf, 16, "%d", asus_info->length); + len += sprintf(page + len, "DSDT length : %s\n", buf); + snprintf(buf, 16, "%d", asus_info->checksum); + len += sprintf(page + len, "DSDT checksum : %s\n", buf); + snprintf(buf, 16, "%d", asus_info->revision); + len += sprintf(page + len, "DSDT revision : %s\n", buf); + snprintf(buf, 7, "%s", asus_info->oem_id); + len += sprintf(page + len, "OEM id : %s\n", buf); + snprintf(buf, 9, "%s", asus_info->oem_table_id); + len += sprintf(page + len, "OEM table id : %s\n", buf); + snprintf(buf, 16, "%x", asus_info->oem_revision); + len += sprintf(page + len, "OEM revision : 0x%s\n", buf); + snprintf(buf, 5, "%s", asus_info->asl_compiler_id); + len += sprintf(page + len, "ASL comp vendor id : %s\n", buf); + snprintf(buf, 16, "%x", asus_info->asl_compiler_revision); + len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf); + } + + return len; +} + +static int parse_arg(const char *buf, unsigned long count, int *val) +{ + if (!count) + return 0; + if (count > 31) + return -EINVAL; + if (sscanf(buf, "%i", val) != 1) + return -EINVAL; + return count; +} + +static ssize_t store_status(const char *buf, size_t count, + acpi_handle handle, int mask, int invert) +{ + int rv, value; + int out = 0; + + rv = parse_arg(buf, count, &value); + if (rv > 0) + out = value ? 1 : 0; + + write_status(handle, out, mask, invert); + + return rv; +} + +/* + * LEDD display + */ +static ssize_t show_ledd(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "0x%08x\n", hotk->ledd_status); +} + +static ssize_t store_ledd(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int rv, value; + + rv = parse_arg(buf, count, &value); + if (rv > 0) { + if (!write_acpi_int(ledd_set_handle, NULL, value, NULL)) + printk(ASUS_WARNING "LED display write failed\n"); + else + hotk->ledd_status = (u32) value; + } + return rv; +} + +/* + * WLAN + */ +static ssize_t show_wlan(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", read_status(WL_ON)); +} + +static ssize_t store_wlan(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return store_status(buf, count, wl_switch_handle, WL_ON, 0); +} + +/* + * Bluetooth + */ +static ssize_t show_bluetooth(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", read_status(BT_ON)); +} + +static ssize_t store_bluetooth(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + return store_status(buf, count, bt_switch_handle, BT_ON, 0); +} + +/* + * Display + */ +static void set_display(int value) +{ + /* no sanity check needed for now */ + if (!write_acpi_int(display_set_handle, NULL, value, NULL)) + printk(ASUS_WARNING "Error setting display\n"); + return; +} + +static int read_display(void) +{ + int value = 0; + + /* In most of the case, we know how to set the display, but sometime + we can't read it */ + if (display_get_handle) { + if (!read_acpi_int(display_get_handle, NULL, &value, NULL)) + printk(ASUS_WARNING "Error reading display status\n"); + } + + value &= 0x0F; /* needed for some models, shouldn't hurt others */ + + return value; +} + +/* + * Now, *this* one could be more user-friendly, but so far, no-one has + * complained. The significance of bits is the same as in store_disp() + */ +static ssize_t show_disp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", read_display()); +} + +/* + * Experimental support for display switching. As of now: 1 should activate + * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. + * Any combination (bitwise) of these will suffice. I never actually tested 4 + * displays hooked up simultaneously, so be warned. See the acpi4asus README + * for more info. + */ +static ssize_t store_disp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int rv, value; + + rv = parse_arg(buf, count, &value); + if (rv > 0) + set_display(value); + return rv; +} + +/* + * Light Sens + */ +static void set_light_sens_switch(int value) +{ + if (!write_acpi_int(ls_switch_handle, NULL, value, NULL)) + printk(ASUS_WARNING "Error setting light sensor switch\n"); + hotk->light_switch = value; +} + +static ssize_t show_lssw(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", hotk->light_switch); +} + +static ssize_t store_lssw(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int rv, value; + + rv = parse_arg(buf, count, &value); + if (rv > 0) + set_light_sens_switch(value ? 1 : 0); + + return rv; +} + +static void set_light_sens_level(int value) +{ + if (!write_acpi_int(ls_level_handle, NULL, value, NULL)) + printk(ASUS_WARNING "Error setting light sensor level\n"); + hotk->light_level = value; +} + +static ssize_t show_lslvl(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", hotk->light_level); +} + +static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int rv, value; + + rv = parse_arg(buf, count, &value); + if (rv > 0) { + value = (0 < value) ? ((15 < value) ? 15 : value) : 0; + /* 0 <= value <= 15 */ + set_light_sens_level(value); + } + + return rv; +} + +static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) +{ + /* TODO Find a better way to handle events count. */ + if (!hotk) + return; + + /* + * We need to tell the backlight device when the backlight power is + * switched + */ + if (event == ATKD_LCD_ON) { + write_status(NULL, 1, LCD_ON, 0); + lcd_blank(FB_BLANK_UNBLANK); + } else if (event == ATKD_LCD_OFF) { + write_status(NULL, 0, LCD_ON, 0); + lcd_blank(FB_BLANK_POWERDOWN); + } + + acpi_bus_generate_event(hotk->device, event, + hotk->event_count[event % 128]++); + + return; +} + +#define ASUS_CREATE_DEVICE_ATTR(_name) \ + struct device_attribute dev_attr_##_name = { \ + .attr = { \ + .name = __stringify(_name), \ + .mode = 0, \ + .owner = THIS_MODULE }, \ + .show = NULL, \ + .store = NULL, \ + } + +#define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store) \ + do { \ + dev_attr_##_name.attr.mode = _mode; \ + dev_attr_##_name.show = _show; \ + dev_attr_##_name.store = _store; \ + } while(0) + +static ASUS_CREATE_DEVICE_ATTR(infos); +static ASUS_CREATE_DEVICE_ATTR(wlan); +static ASUS_CREATE_DEVICE_ATTR(bluetooth); +static ASUS_CREATE_DEVICE_ATTR(display); +static ASUS_CREATE_DEVICE_ATTR(ledd); +static ASUS_CREATE_DEVICE_ATTR(ls_switch); +static ASUS_CREATE_DEVICE_ATTR(ls_level); + +static struct attribute *asuspf_attributes[] = { + &dev_attr_infos.attr, + &dev_attr_wlan.attr, + &dev_attr_bluetooth.attr, + &dev_attr_display.attr, + &dev_attr_ledd.attr, + &dev_attr_ls_switch.attr, + &dev_attr_ls_level.attr, + NULL +}; + +static struct attribute_group asuspf_attribute_group = { + .attrs = asuspf_attributes +}; + +static struct platform_driver asuspf_driver = { + .driver = { + .name = ASUS_HOTK_FILE, + .owner = THIS_MODULE, + } +}; + +static struct platform_device *asuspf_device; + +static void asus_hotk_add_fs(void) +{ + ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL); + + if (wl_switch_handle) + ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan); + + if (bt_switch_handle) + ASUS_SET_DEVICE_ATTR(bluetooth, 0644, + show_bluetooth, store_bluetooth); + + if (display_set_handle && display_get_handle) + ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, store_disp); + else if (display_set_handle) + ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp); + + if (ledd_set_handle) + ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd); + + if (ls_switch_handle && ls_level_handle) { + ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl); + ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw); + } +} + +static int asus_handle_init(char *name, acpi_handle * handle, + char **paths, int num_paths) +{ + int i; + acpi_status status; + + for (i = 0; i < num_paths; i++) { + status = acpi_get_handle(NULL, paths[i], handle); + if (ACPI_SUCCESS(status)) + return 0; + } + + *handle = NULL; + return -ENODEV; +} + +#define ASUS_HANDLE_INIT(object) \ + asus_handle_init(#object, &object##_handle, object##_paths, \ + ARRAY_SIZE(object##_paths)) + +/* + * This function is used to initialize the hotk with right values. In this + * method, we can make all the detection we want, and modify the hotk struct + */ +static int asus_hotk_get_info(void) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *model = NULL; + int bsts_result, hwrs_result; + char *string = NULL; + acpi_status status; + + /* + * Get DSDT headers early enough to allow for differentiating between + * models, but late enough to allow acpi_bus_register_driver() to fail + * before doing anything ACPI-specific. Should we encounter a machine, + * which needs special handling (i.e. its hotkey device has a different + * HID), this bit will be moved. A global variable asus_info contains + * the DSDT header. + */ + status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info); + if (ACPI_FAILURE(status)) + printk(ASUS_WARNING "Couldn't get the DSDT table header\n"); + + /* We have to write 0 on init this far for all ASUS models */ + if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { + printk(ASUS_ERR "Hotkey initialization failed\n"); + return -ENODEV; + } + + /* This needs to be called for some laptops to init properly */ + if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result, NULL)) + printk(ASUS_WARNING "Error calling BSTS\n"); + else if (bsts_result) + printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n", + bsts_result); + + /* + * Try to match the object returned by INIT to the specific model. + * Handle every possible object (or the lack of thereof) the DSDT + * writers might throw at us. When in trouble, we pass NULL to + * asus_model_match() and try something completely different. + */ + if (buffer.pointer) { + model = buffer.pointer; + switch (model->type) { + case ACPI_TYPE_STRING: + string = model->string.pointer; + break; + case ACPI_TYPE_BUFFER: + string = model->buffer.pointer; + break; + default: + string = ""; + break; + } + } + hotk->name = kstrdup(string, GFP_KERNEL); + if (!hotk->name) + return -ENOMEM; + + if (*string) + printk(ASUS_NOTICE " %s model detected\n", string); + + ASUS_HANDLE_INIT(mled_set); + ASUS_HANDLE_INIT(tled_set); + ASUS_HANDLE_INIT(rled_set); + ASUS_HANDLE_INIT(pled_set); + + ASUS_HANDLE_INIT(ledd_set); + + /* + * The HWRS method return informations about the hardware. + * 0x80 bit is for WLAN, 0x100 for Bluetooth. + * The significance of others is yet to be found. + * If we don't find the method, we assume the device are present. + */ + if (!read_acpi_int(hotk->handle, "HRWS", &hwrs_result, NULL)) + hwrs_result = WL_HWRS | BT_HWRS; + + if (hwrs_result & WL_HWRS) + ASUS_HANDLE_INIT(wl_switch); + if (hwrs_result & BT_HWRS) + ASUS_HANDLE_INIT(bt_switch); + + ASUS_HANDLE_INIT(wireless_status); + + ASUS_HANDLE_INIT(brightness_set); + ASUS_HANDLE_INIT(brightness_get); + + ASUS_HANDLE_INIT(lcd_switch); + + ASUS_HANDLE_INIT(display_set); + ASUS_HANDLE_INIT(display_get); + + /* There is a lot of models with "ALSL", but a few get + a real light sens, so we need to check it. */ + if (ASUS_HANDLE_INIT(ls_switch)) + ASUS_HANDLE_INIT(ls_level); + + kfree(model); + + return AE_OK; +} + +static int asus_hotk_check(void) +{ + int result = 0; + + result = acpi_bus_get_status(hotk->device); + if (result) + return result; + + if (hotk->device->status.present) { + result = asus_hotk_get_info(); + } else { + printk(ASUS_ERR "Hotkey device not present, aborting\n"); + return -EINVAL; + } + + return result; +} + +static int asus_hotk_found; + +static int asus_hotk_add(struct acpi_device *device) +{ + acpi_status status = AE_OK; + int result; + + if (!device) + return -EINVAL; + + printk(ASUS_NOTICE "Asus Laptop Support version %s\n", + ASUS_LAPTOP_VERSION); + + hotk = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL); + if (!hotk) + return -ENOMEM; + memset(hotk, 0, sizeof(struct asus_hotk)); + + hotk->handle = device->handle; + strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME); + strcpy(acpi_device_class(device), ASUS_HOTK_CLASS); + acpi_driver_data(device) = hotk; + hotk->device = device; + + result = asus_hotk_check(); + if (result) + goto end; + + asus_hotk_add_fs(); + + /* + * We install the handler, it will receive the hotk in parameter, so, we + * could add other data to the hotk struct + */ + status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, + asus_hotk_notify, hotk); + if (ACPI_FAILURE(status)) + printk(ASUS_ERR "Error installing notify handler\n"); + + asus_hotk_found = 1; + + /* WLED and BLED are on by default */ + write_status(bt_switch_handle, 1, BT_ON, 0); + write_status(wl_switch_handle, 1, WL_ON, 0); + + /* LCD Backlight is on by default */ + write_status(NULL, 1, LCD_ON, 0); + + /* LED display is off by default */ + hotk->ledd_status = 0xFFF; + + /* Set initial values of light sensor and level */ + hotk->light_switch = 1; /* Default to light sensor disabled */ + hotk->light_level = 0; /* level 5 for sensor sensitivity */ + + if (ls_switch_handle) + set_light_sens_switch(hotk->light_switch); + + if (ls_level_handle) + set_light_sens_level(hotk->light_level); + + end: + if (result) { + kfree(hotk->name); + kfree(hotk); + } + + return result; +} + +static int asus_hotk_remove(struct acpi_device *device, int type) +{ + acpi_status status = 0; + + if (!device || !acpi_driver_data(device)) + return -EINVAL; + + status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, + asus_hotk_notify); + if (ACPI_FAILURE(status)) + printk(ASUS_ERR "Error removing notify handler\n"); + + kfree(hotk->name); + kfree(hotk); + + return 0; +} + +static void asus_backlight_exit(void) +{ + if (asus_backlight_device) + backlight_device_unregister(asus_backlight_device); +} + +#define ASUS_LED_UNREGISTER(object) \ + if(object##_led.class_dev \ + && !IS_ERR(object##_led.class_dev)) \ + led_classdev_unregister(&object##_led) + +static void asus_led_exit(void) +{ + ASUS_LED_UNREGISTER(mled); + ASUS_LED_UNREGISTER(tled); + ASUS_LED_UNREGISTER(pled); + ASUS_LED_UNREGISTER(rled); + + destroy_workqueue(led_workqueue); +} + +static void __exit asus_laptop_exit(void) +{ + asus_backlight_exit(); + asus_led_exit(); + + acpi_bus_unregister_driver(&asus_hotk_driver); + sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group); + platform_device_unregister(asuspf_device); + platform_driver_unregister(&asuspf_driver); +} + +static int asus_backlight_init(struct device *dev) +{ + struct backlight_device *bd; + + if (brightness_set_handle && lcd_switch_handle) { + bd = backlight_device_register(ASUS_HOTK_FILE, dev, + NULL, &asusbl_data); + if (IS_ERR(bd)) { + printk(ASUS_ERR + "Could not register asus backlight device\n"); + asus_backlight_device = NULL; + return PTR_ERR(bd); + } + + asus_backlight_device = bd; + + down(&bd->sem); + if (likely(bd->props)) { + bd->props->brightness = read_brightness(NULL); + bd->props->power = FB_BLANK_UNBLANK; + if (likely(bd->props->update_status)) + bd->props->update_status(bd); + } + up(&bd->sem); + } + return 0; +} + +static int asus_led_register(acpi_handle handle, + struct led_classdev *ldev, struct device *dev) +{ + if (!handle) + return 0; + + return led_classdev_register(dev, ldev); +} + +#define ASUS_LED_REGISTER(object, device) \ + asus_led_register(object##_set_handle, &object##_led, device) + +static int asus_led_init(struct device *dev) +{ + int rv; + + rv = ASUS_LED_REGISTER(mled, dev); + if (rv) + return rv; + + rv = ASUS_LED_REGISTER(tled, dev); + if (rv) + return rv; + + rv = ASUS_LED_REGISTER(rled, dev); + if (rv) + return rv; + + rv = ASUS_LED_REGISTER(pled, dev); + if (rv) + return rv; + + led_workqueue = create_singlethread_workqueue("led_workqueue"); + if (!led_workqueue) + return -ENOMEM; + + return 0; +} + +static int __init asus_laptop_init(void) +{ + struct device *dev; + int result; + + if (acpi_disabled) + return -ENODEV; + + if (!acpi_specific_hotkey_enabled) { + printk(ASUS_ERR "Using generic hotkey driver\n"); + return -ENODEV; + } + + result = acpi_bus_register_driver(&asus_hotk_driver); + if (result < 0) + return result; + + /* + * This is a bit of a kludge. We only want this module loaded + * for ASUS systems, but there's currently no way to probe the + * ACPI namespace for ASUS HIDs. So we just return failure if + * we didn't find one, which will cause the module to be + * unloaded. + */ + if (!asus_hotk_found) { + acpi_bus_unregister_driver(&asus_hotk_driver); + return -ENODEV; + } + + dev = acpi_get_physical_device(hotk->device->handle); + + result = asus_backlight_init(dev); + if (result) + goto fail_backlight; + + result = asus_led_init(dev); + if (result) + goto fail_led; + + /* Register platform stuff */ + result = platform_driver_register(&asuspf_driver); + if (result) + goto fail_platform_driver; + + asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1); + if (!asuspf_device) { + result = -ENOMEM; + goto fail_platform_device1; + } + + result = platform_device_add(asuspf_device); + if (result) + goto fail_platform_device2; + + result = sysfs_create_group(&asuspf_device->dev.kobj, + &asuspf_attribute_group); + if (result) + goto fail_sysfs; + + return 0; + + fail_sysfs: + platform_device_del(asuspf_device); + + fail_platform_device2: + platform_device_put(asuspf_device); + + fail_platform_device1: + platform_driver_unregister(&asuspf_driver); + + fail_platform_driver: + asus_led_exit(); + + fail_led: + asus_backlight_exit(); + + fail_backlight: + + return result; +} + +module_init(asus_laptop_init); +module_exit(asus_laptop_exit); diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 2ab7add78f94..e21e490fedb0 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -11,66 +11,25 @@ #include #include +#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) { - int cnt; unsigned long flags; spin_lock_irqsave(&fm->lock, flags); - if (!fm->inhibit_new_cards) { - for (cnt = 0; cnt < fm->max_sockets; cnt++) { - if (fm->sockets[cnt] == sock) { - fm->remove_mask |= (1 << cnt); - queue_work(fm->wq, &fm->media_remover); - break; - } - } - } + fm->socket_change_set |= 1 << sock->socket_id; + wake_up_all(&fm->change_set_notify); 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; + struct tifm_dev *sock; unsigned int irq_status; unsigned int sock_irq_status, cnt; @@ -84,42 +43,32 @@ 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++) { - sock_irq_status = (irq_status >> cnt) & - (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK); + for (cnt = 0; cnt < fm->num_sockets; cnt++) { + sock = fm->sockets[cnt]; + sock_irq_status = (irq_status >> cnt) + & (TIFM_IRQ_FIFOMASK(1) + | TIFM_IRQ_CARDMASK(1)); - if (fm->sockets[cnt]) { - if (sock_irq_status && - fm->sockets[cnt]->signal_irq) - sock_irq_status = fm->sockets[cnt]-> - signal_irq(fm->sockets[cnt], - sock_irq_status); - - 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) { - 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); - } - } + 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; } -static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2) +static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, + int is_x2) { unsigned int s_state; int cnt; @@ -127,8 +76,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is writel(0x0e00, sock_addr + SOCK_CONTROL); for (cnt = 0; cnt < 100; cnt++) { - if (!(TIFM_SOCK_STATE_POWERED & - readl(sock_addr + SOCK_PRESENT_STATE))) + if (!(TIFM_SOCK_STATE_POWERED + & readl(sock_addr + SOCK_PRESENT_STATE))) break; msleep(10); } @@ -151,8 +100,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is } for (cnt = 0; cnt < 100; cnt++) { - if ((TIFM_SOCK_STATE_POWERED & - readl(sock_addr + SOCK_PRESENT_STATE))) + if ((TIFM_SOCK_STATE_POWERED + & readl(sock_addr + SOCK_PRESENT_STATE))) break; msleep(10); } @@ -170,130 +119,209 @@ 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 int tifm_7xx1_switch_media(void *data) { - struct tifm_adapter *fm = - container_of(work, struct tifm_adapter, media_inserter); + struct tifm_adapter *fm = data; 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, rc; + 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) { + 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; + + dev_dbg(fm->dev, "checking media set %x\n", + socket_change_set); + + if (kthread_should_stop()) + 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))) + if (!socket_change_set) 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, cnt); - if (new_sock) { - new_sock->addr = tifm_7xx1_sock_addr(fm->addr, - cnt); - new_sock->media_id = media_id; - 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); + 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); - spin_lock_irqsave(&fm->lock, flags); - if (!fm->sockets[cnt]) { - fm->sockets[cnt] = new_sock; - ok_to_register = 1; - } + ": demand removing card from socket %d\n", + cnt); + fm->sockets[cnt] = NULL; 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); + device_unregister(&sock->dev); + spin_lock_irqsave(&fm->lock, flags); + writel(0x0e00, + tifm_7xx1_sock_addr(fm->addr, cnt) + + SOCK_CONTROL); + } + if (kthread_should_stop()) + 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); } } - 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); + if (!kthread_should_stop()) { + 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); + } 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); + return 0; + } else { + spin_unlock_irqrestore(&fm->lock, flags); + } + } + } + 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->remove_mask = 0xf; - fm->insert_mask = 0; - 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); - - 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->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); + 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); - 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, - fm->addr + FM_SET_INTERRUPT_ENABLE); - fm->insert_mask = 0xf; + 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) + const struct pci_device_id *dev_id) { struct tifm_adapter *fm; int pci_dev_busy = 0; @@ -324,19 +352,18 @@ 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, - GFP_KERNEL); + 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) goto err_out_free; - INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media); - INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media); fm->eject = tifm_7xx1_eject; pci_set_drvdata(dev, fm); fm->addr = ioremap(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); + pci_resource_len(dev, 0)); if (!fm->addr) goto err_out_free; @@ -344,16 +371,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_SETALLSOCK, - fm->addr + FM_SET_INTERRUPT_ENABLE); - - fm->insert_mask = 0xf; - + writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), + fm->addr + FM_SET_INTERRUPT_ENABLE); + wake_up_process(fm->media_switcher); return 0; err_out_irq: @@ -377,19 +403,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->remove_mask = 0xf; - fm->insert_mask = 0; - 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_remove_media(&fm->media_remover); - - writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); - free_irq(dev->irq, fm); + kthread_stop(fm->media_switcher); tifm_remove_adapter(fm); @@ -404,10 +426,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/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index d61df5c3ac36..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) @@ -71,8 +102,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 +130,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 +143,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); @@ -141,27 +171,27 @@ 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) +static void tifm_dummy_signal_irq(struct tifm_dev *sock, + unsigned int sock_irq_status) +{ + return; +} + +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; + dev->signal_irq = tifm_dummy_signal_irq; } return dev; } @@ -219,6 +249,7 @@ static int tifm_device_remove(struct device *dev) struct tifm_driver *drv = fm_dev->drv; if (drv) { + fm_dev->signal_irq = tifm_dummy_signal_irq; if (drv->remove) drv->remove(fm_dev); fm_dev->drv = NULL; @@ -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/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c index aa152f31851e..2ce50f38e3c7 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/at91_mci.c @@ -823,6 +823,9 @@ 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; + mmc->max_blk_count = mmc->max_req_size; + host = mmc_priv(mmc); host->mmc = mmc; host->buffer = NULL; diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c index 800527cf40d5..b834be261ab7 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/au1xmmc.c @@ -152,8 +152,9 @@ static inline int au1xmmc_card_inserted(struct au1xmmc_host *host) ? 1 : 0; } -static inline int au1xmmc_card_readonly(struct au1xmmc_host *host) +static int au1xmmc_card_readonly(struct mmc_host *mmc) { + struct au1xmmc_host *host = mmc_priv(mmc); return (bcsr->status & au1xmmc_card_table[host->id].wpstatus) ? 1 : 0; } @@ -193,6 +194,8 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT); switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + break; case MMC_RSP_R1: mmccmd |= SD_CMD_RT_1; break; @@ -205,6 +208,10 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, case MMC_RSP_R3: mmccmd |= SD_CMD_RT_3; break; + default: + printk(KERN_INFO "au1xmmc: unhandled response type %02x\n", + mmc_resp_type(cmd)); + return MMC_ERR_INVALID; } switch(cmd->opcode) { @@ -878,6 +885,7 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host) static const struct mmc_host_ops au1xmmc_ops = { .request = au1xmmc_request, .set_ios = au1xmmc_set_ios, + .get_ro = au1xmmc_card_readonly, }; static int __devinit au1xmmc_probe(struct platform_device *pdev) @@ -914,6 +922,9 @@ 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->max_blk_count = 512; + mmc->ocr_avail = AU1XMMC_OCR; host = mmc_priv(mmc); diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index bfb9ff693208..b060d4bfba29 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -958,8 +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 6f2a282e2b97..5046a1661342 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -103,11 +103,16 @@ 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; 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; mrq->data->mrq = mrq; @@ -157,7 +162,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 +200,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; @@ -289,7 +294,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; } @@ -320,14 +328,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 +361,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); @@ -372,7 +380,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); } @@ -381,7 +389,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; @@ -588,34 +596,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 +887,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 @@ -1018,7 +1092,8 @@ static void mmc_process_ext_csds(struct mmc_host *host) mmc_wait_for_req(host, &mrq); if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { - mmc_card_set_dead(card); + printk("%s: unable to read EXT_CSD, performance " + "might suffer.\n", mmc_hostname(card->host)); continue; } @@ -1034,7 +1109,6 @@ static void mmc_process_ext_csds(struct mmc_host *host) printk("%s: card is mmc v4 but doesn't support " "any high-speed modes.\n", mmc_hostname(card->host)); - mmc_card_set_bad(card); continue; } @@ -1215,7 +1289,9 @@ static void mmc_read_switch_caps(struct mmc_host *host) mmc_wait_for_req(host, &mrq); if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { - mmc_card_set_dead(card); + printk("%s: unable to read switch capabilities, " + "performance might suffer.\n", + mmc_hostname(card->host)); continue; } @@ -1247,12 +1323,8 @@ static void mmc_read_switch_caps(struct mmc_host *host) mmc_wait_for_req(host, &mrq); - if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { - mmc_card_set_dead(card); - continue; - } - - if ((status[16] & 0xF) != 1) { + if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE || + (status[16] & 0xF) != 1) { printk(KERN_WARNING "%s: Problem switching card " "into high-speed mode!\n", mmc_hostname(host)); @@ -1334,6 +1406,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 +1462,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); @@ -1519,8 +1606,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 87713572293f..05ba8ace70e7 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -237,13 +237,17 @@ 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); 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); @@ -375,9 +379,10 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) spin_unlock_irq(&md->lock); } +flush_queue: + mmc_card_release_host(card); -flush_queue: spin_lock_irq(&md->lock); while (ret) { ret = end_that_request_chunk(req, 0, @@ -494,6 +499,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/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/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/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index ccfe6561be24..5941dd951e82 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -524,15 +524,24 @@ 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); diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c index d30540b27614..1e96a2f65022 100644 --- a/drivers/mmc/omap.c +++ b/drivers/mmc/omap.c @@ -1099,8 +1099,10 @@ static int __init mmc_omap_probe(struct platform_device *pdev) */ mmc->max_phys_segs = 32; mmc->max_hw_segs = 32; - mmc->max_sectors = 256; /* NBLK max 11-bits, OMAP also limited by DMA */ - mmc->max_seg_size = mmc->max_sectors * 512; + mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */ + 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 6073d998b11f..9774fc68b61a 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -450,6 +450,16 @@ 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; + + /* + * 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 c2d13d7e9911..4bf1fea5e2c4 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) }, @@ -197,15 +206,9 @@ static void sdhci_deactivate_led(struct sdhci_host *host) * * \*****************************************************************************/ -static inline char* sdhci_kmap_sg(struct sdhci_host* host) +static inline char* sdhci_sg_to_buffer(struct sdhci_host* host) { - host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ); - return host->mapped_sg + host->cur_sg->offset; -} - -static inline void sdhci_kunmap_sg(struct sdhci_host* host) -{ - kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ); + return page_address(host->cur_sg->page) + host->cur_sg->offset; } static inline int sdhci_next_sg(struct sdhci_host* host) @@ -240,7 +243,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host) chunk_remain = 0; data = 0; - buffer = sdhci_kmap_sg(host) + host->offset; + buffer = sdhci_sg_to_buffer(host) + host->offset; while (blksize) { if (chunk_remain == 0) { @@ -264,16 +267,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host) } if (host->remain == 0) { - sdhci_kunmap_sg(host); if (sdhci_next_sg(host) == 0) { BUG_ON(blksize != 0); return; } - buffer = sdhci_kmap_sg(host); + buffer = sdhci_sg_to_buffer(host); } } - - sdhci_kunmap_sg(host); } static void sdhci_write_block_pio(struct sdhci_host *host) @@ -290,7 +290,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host) data = 0; bytes = 0; - buffer = sdhci_kmap_sg(host) + host->offset; + buffer = sdhci_sg_to_buffer(host) + host->offset; while (blksize) { size = min(host->size, host->remain); @@ -314,16 +314,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host) } if (host->remain == 0) { - sdhci_kunmap_sg(host); if (sdhci_next_sg(host) == 0) { BUG_ON(blksize != 0); return; } - buffer = sdhci_kmap_sg(host); + buffer = sdhci_sg_to_buffer(host); } } - - sdhci_kunmap_sg(host); } static void sdhci_transfer_pio(struct sdhci_host *host) @@ -372,7 +369,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 */ @@ -674,10 +671,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; @@ -1109,7 +1113,9 @@ static int sdhci_resume (struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - pci_enable_device(pdev); + ret = pci_enable_device(pdev); + if (ret) + return ret; for (i = 0;i < chip->num_slots;i++) { if (!chip->hosts[i]) @@ -1274,15 +1280,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. */ @@ -1294,9 +1291,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) mmc->ocr_avail = 0; if (caps & SDHCI_CAN_VDD_330) mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; - else if (caps & SDHCI_CAN_VDD_300) + if (caps & SDHCI_CAN_VDD_300) mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31; - else if (caps & SDHCI_CAN_VDD_180) + if (caps & SDHCI_CAN_VDD_180) mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19; if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) { @@ -1326,15 +1323,33 @@ 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 + * 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; + + /* + * Maximum block count. + */ + mmc->max_blk_count = 65535; /* * Init tasklets. diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h index f9d1a0a6f03a..e324f0a623dc 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 */ @@ -184,7 +183,6 @@ struct sdhci_host { struct mmc_data *data; /* Current data request */ struct scatterlist *cur_sg; /* We're working on this */ - char *mapped_sg; /* This is where it's mapped */ int num_sg; /* Entries left */ int offset; /* Offset into current sg */ int remain; /* Bytes left in current */ diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c index fa4a52886b97..e65f8a0a9349 100644 --- a/drivers/mmc/tifm_sd.c +++ b/drivers/mmc/tifm_sd.c @@ -17,7 +17,7 @@ #include #define DRIVER_NAME "tifm_sd" -#define DRIVER_VERSION "0.6" +#define DRIVER_VERSION "0.7" static int no_dma = 0; static int fixed_timeout = 0; @@ -79,7 +79,6 @@ typedef enum { enum { FIFO_RDY = 0x0001, /* hardware dependent value */ - HOST_REG = 0x0002, EJECT = 0x0004, EJECT_DONE = 0x0008, CARD_BUSY = 0x0010, @@ -95,46 +94,53 @@ struct tifm_sd { card_state_t state; unsigned int clk_freq; unsigned int clk_div; - unsigned long timeout_jiffies; // software timeout - 2 sec + unsigned long timeout_jiffies; + struct tasklet_struct finish_tasklet; + struct timer_list timer; struct mmc_request *req; - struct work_struct cmd_handler; - struct delayed_work abort_handler; - wait_queue_head_t can_eject; + wait_queue_head_t notify; size_t written_blocks; - char *buffer; size_t buffer_size; size_t buffer_pos; }; +static char* tifm_sd_data_buffer(struct mmc_data *data) +{ + return page_address(data->sg->page) + data->sg->offset; +} + static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host, - unsigned int host_status) + unsigned int host_status) { struct mmc_command *cmd = host->req->cmd; unsigned int t_val = 0, cnt = 0; + char *buffer; if (host_status & TIFM_MMCSD_BRS) { /* in non-dma rx mode BRS fires when fifo is still not empty */ - if (host->buffer && (cmd->data->flags & MMC_DATA_READ)) { + if (no_dma && (cmd->data->flags & MMC_DATA_READ)) { + buffer = tifm_sd_data_buffer(host->req->data); while (host->buffer_size > host->buffer_pos) { t_val = readl(sock->addr + SOCK_MMCSD_DATA); - host->buffer[host->buffer_pos++] = t_val & 0xff; - host->buffer[host->buffer_pos++] = + buffer[host->buffer_pos++] = t_val & 0xff; + buffer[host->buffer_pos++] = (t_val >> 8) & 0xff; } } return 1; - } else if (host->buffer) { + } else if (no_dma) { + buffer = tifm_sd_data_buffer(host->req->data); if ((cmd->data->flags & MMC_DATA_READ) && (host_status & TIFM_MMCSD_AF)) { for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { t_val = readl(sock->addr + SOCK_MMCSD_DATA); if (host->buffer_size > host->buffer_pos) { - host->buffer[host->buffer_pos++] = + buffer[host->buffer_pos++] = t_val & 0xff; - host->buffer[host->buffer_pos++] = + buffer[host->buffer_pos++] = (t_val >> 8) & 0xff; } } @@ -142,11 +148,12 @@ static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host, && (host_status & TIFM_MMCSD_AE)) { for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { if (host->buffer_size > host->buffer_pos) { - t_val = host->buffer[host->buffer_pos++] & 0x00ff; - t_val |= ((host->buffer[host->buffer_pos++]) << 8) - & 0xff00; + t_val = buffer[host->buffer_pos++] + & 0x00ff; + t_val |= ((buffer[host->buffer_pos++]) + << 8) & 0xff00; writel(t_val, - sock->addr + SOCK_MMCSD_DATA); + sock->addr + SOCK_MMCSD_DATA); } } } @@ -206,7 +213,7 @@ static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd) cmd_mask |= TIFM_MMCSD_READ; dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n", - cmd->opcode, cmd->arg, cmd_mask); + cmd->opcode, cmd->arg, cmd_mask); writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH); writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW); @@ -239,65 +246,78 @@ change_state: tifm_sd_fetch_resp(cmd, sock); if (cmd->data) { host->state = BRS; - } else + } else { host->state = READY; + } goto change_state; } break; case BRS: if (tifm_sd_transfer_data(sock, host, host_status)) { - if (!host->req->stop) { - if (cmd->data->flags & MMC_DATA_WRITE) { - host->state = CARD; + if (cmd->data->flags & MMC_DATA_WRITE) { + host->state = CARD; + } else { + if (no_dma) { + if (host->req->stop) { + tifm_sd_exec(host, host->req->stop); + host->state = SCMD; + } else { + host->state = READY; + } } else { - host->state = - host->buffer ? READY : FIFO; + host->state = FIFO; } - goto change_state; } - tifm_sd_exec(host, host->req->stop); - host->state = SCMD; + goto change_state; } break; case SCMD: if (host_status & TIFM_MMCSD_EOC) { tifm_sd_fetch_resp(host->req->stop, sock); - if (cmd->error) { - host->state = READY; - } else if (cmd->data->flags & MMC_DATA_WRITE) { - host->state = CARD; - } else { - host->state = host->buffer ? READY : FIFO; - } + host->state = READY; goto change_state; } break; case CARD: + dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n", + host->written_blocks); if (!(host->flags & CARD_BUSY) && (host->written_blocks == cmd->data->blocks)) { - host->state = host->buffer ? READY : FIFO; + if (no_dma) { + if (host->req->stop) { + tifm_sd_exec(host, host->req->stop); + host->state = SCMD; + } else { + host->state = READY; + } + } else { + host->state = FIFO; + } goto change_state; } break; case FIFO: if (host->flags & FIFO_RDY) { - host->state = READY; host->flags &= ~FIFO_RDY; + if (host->req->stop) { + tifm_sd_exec(host, host->req->stop); + host->state = SCMD; + } else { + host->state = READY; + } goto change_state; } break; case READY: - queue_work(sock->wq, &host->cmd_handler); + tasklet_schedule(&host->finish_tasklet); return; } - queue_delayed_work(sock->wq, &host->abort_handler, - host->timeout_jiffies); } /* 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; @@ -305,7 +325,6 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, spin_lock(&sock->lock); host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); - cancel_delayed_work(&host->abort_handler); if (sock_irq_status & FIFO_EVENT) { fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); @@ -318,19 +337,17 @@ 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; if (host_status & TIFM_MMCSD_ERRMASK) { if (host_status & TIFM_MMCSD_CERR) error_code = MMC_ERR_FAILED; - else if (host_status & - (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO)) + else if (host_status + & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO)) error_code = MMC_ERR_TIMEOUT; - else if (host_status & - (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC)) + else if (host_status + & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC)) error_code = MMC_ERR_BADCRC; writel(TIFM_FIFO_INT_SETALL, @@ -340,12 +357,11 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, if (host->req->stop) { if (host->state == SCMD) { host->req->stop->error = error_code; - } else if(host->state == BRS) { + } else if (host->state == BRS + || host->state == CARD + || host->state == FIFO) { host->req->cmd->error = error_code; tifm_sd_exec(host, host->req->stop); - queue_delayed_work(sock->wq, - &host->abort_handler, - host->timeout_jiffies); host->state = SCMD; goto done; } else { @@ -359,8 +375,8 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, if (host_status & TIFM_MMCSD_CB) host->flags |= CARD_BUSY; - if ((host_status & TIFM_MMCSD_EOFB) && - (host->flags & CARD_BUSY)) { + if ((host_status & TIFM_MMCSD_EOFB) + && (host->flags & CARD_BUSY)) { host->written_blocks++; host->flags &= ~CARD_BUSY; } @@ -370,22 +386,22 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock, tifm_sd_process_cmd(sock, host, host_status); done: dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n", - host_status, fifo_status); + host_status, fifo_status); spin_unlock(&sock->lock); - return sock_irq_status; } -static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd) +static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd) { - struct tifm_dev *sock = card->dev; + struct tifm_dev *sock = host->dev; unsigned int dest_cnt; /* DMA style IO */ - + dev_dbg(&sock->dev, "setting dma for %d blocks\n", + cmd->data->blocks); writel(TIFM_FIFO_INT_SETALL, - sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); + sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); writel(ilog2(cmd->data->blksz) - 2, - sock->addr + SOCK_FIFO_PAGE_SIZE); + sock->addr + SOCK_FIFO_PAGE_SIZE); writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL); writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET); @@ -399,7 +415,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd) if (cmd->data->flags & MMC_DATA_WRITE) { writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN, - sock->addr + SOCK_DMA_CONTROL); + sock->addr + SOCK_DMA_CONTROL); } else { writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL); @@ -407,7 +423,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd) } static void tifm_sd_set_data_timeout(struct tifm_sd *host, - struct mmc_data *data) + struct mmc_data *data) { struct tifm_dev *sock = host->dev; unsigned int data_timeout = data->timeout_clks; @@ -416,22 +432,21 @@ static void tifm_sd_set_data_timeout(struct tifm_sd *host, return; data_timeout += data->timeout_ns / - ((1000000000 / host->clk_freq) * host->clk_div); - data_timeout *= 10; // call it fudge factor for now + ((1000000000UL / host->clk_freq) * host->clk_div); if (data_timeout < 0xffff) { - writel((~TIFM_MMCSD_DPE) & - readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), - sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); + writel((~TIFM_MMCSD_DPE) + & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), + sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); } else { - writel(TIFM_MMCSD_DPE | - readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), - sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); data_timeout = (data_timeout >> 10) + 1; - if(data_timeout > 0xffff) + if (data_timeout > 0xffff) data_timeout = 0; /* set to unlimited */ writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO); + writel(TIFM_MMCSD_DPE + | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG), + sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG); } } @@ -474,11 +489,10 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) } host->req = mrq; + mod_timer(&host->timer, jiffies + host->timeout_jiffies); host->state = CMD; - queue_delayed_work(sock->wq, &host->abort_handler, - host->timeout_jiffies); writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + sock->addr + SOCK_CONTROL); tifm_sd_exec(host, mrq->cmd); spin_unlock_irqrestore(&sock->lock, flags); return; @@ -493,9 +507,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; @@ -504,6 +518,7 @@ static void tifm_sd_end_cmd(struct work_struct *work) spin_lock_irqsave(&sock->lock, flags); + del_timer(&host->timer); mrq = host->req; host->req = NULL; host->state = IDLE; @@ -517,8 +532,8 @@ static void tifm_sd_end_cmd(struct work_struct *work) r_data = mrq->cmd->data; if (r_data) { if (r_data->flags & MMC_DATA_WRITE) { - r_data->bytes_xfered = host->written_blocks * - r_data->blksz; + r_data->bytes_xfered = host->written_blocks + * r_data->blksz; } else { r_data->bytes_xfered = r_data->blocks - readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; @@ -532,7 +547,7 @@ static void tifm_sd_end_cmd(struct work_struct *work) } writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + sock->addr + SOCK_CONTROL); spin_unlock_irqrestore(&sock->lock, flags); mmc_request_done(mmc, mrq); @@ -544,15 +559,6 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq) struct tifm_dev *sock = host->dev; unsigned long flags; struct mmc_data *r_data = mrq->cmd->data; - char *t_buffer = NULL; - - if (r_data) { - t_buffer = kmap(r_data->sg->page); - if (!t_buffer) { - printk(KERN_ERR DRIVER_NAME ": kmap failed\n"); - goto err_out; - } - } spin_lock_irqsave(&sock->lock, flags); if (host->flags & EJECT) { @@ -569,15 +575,14 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq) if (r_data) { tifm_sd_set_data_timeout(host, r_data); - host->buffer = t_buffer + r_data->sg->offset; - host->buffer_size = mrq->cmd->data->blocks * - mrq->cmd->data->blksz; + host->buffer_size = mrq->cmd->data->blocks + * mrq->cmd->data->blksz; - writel(TIFM_MMCSD_BUFINT | - readl(sock->addr + SOCK_MMCSD_INT_ENABLE), + writel(TIFM_MMCSD_BUFINT + | readl(sock->addr + SOCK_MMCSD_INT_ENABLE), sock->addr + SOCK_MMCSD_INT_ENABLE); - writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) | - (TIFM_MMCSD_FIFO_SIZE - 1), + writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) + | (TIFM_MMCSD_FIFO_SIZE - 1), sock->addr + SOCK_MMCSD_BUFFER_CONFIG); host->written_blocks = 0; @@ -588,26 +593,22 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq) } host->req = mrq; + mod_timer(&host->timer, jiffies + host->timeout_jiffies); host->state = CMD; - queue_delayed_work(sock->wq, &host->abort_handler, - host->timeout_jiffies); writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + sock->addr + SOCK_CONTROL); tifm_sd_exec(host, mrq->cmd); spin_unlock_irqrestore(&sock->lock, flags); return; err_out: - if (t_buffer) - kunmap(r_data->sg->page); - mrq->cmd->error = MMC_ERR_TIMEOUT; 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; @@ -616,6 +617,7 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work) spin_lock_irqsave(&sock->lock, flags); + del_timer(&host->timer); mrq = host->req; host->req = NULL; host->state = IDLE; @@ -633,8 +635,8 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work) sock->addr + SOCK_MMCSD_INT_ENABLE); if (r_data->flags & MMC_DATA_WRITE) { - r_data->bytes_xfered = host->written_blocks * - r_data->blksz; + r_data->bytes_xfered = host->written_blocks + * r_data->blksz; } else { r_data->bytes_xfered = r_data->blocks - readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1; @@ -642,29 +644,44 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work) r_data->bytes_xfered += r_data->blksz - readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1; } - host->buffer = NULL; host->buffer_pos = 0; host->buffer_size = 0; } writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + sock->addr + SOCK_CONTROL); spin_unlock_irqrestore(&sock->lock, flags); - if (r_data) - kunmap(r_data->sg->page); - mmc_request_done(mmc, mrq); } -static void tifm_sd_abort(struct work_struct *work) +static void tifm_sd_terminate(struct tifm_sd *host) { - struct tifm_sd *host = - container_of(work, struct tifm_sd, abort_handler.work); + 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"); + ": card failed to respond for a long period of time"); + + tifm_sd_terminate(host); tifm_eject(host->dev); } @@ -683,9 +700,9 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG), sock->addr + SOCK_MMCSD_CONFIG); } else { - writel((~TIFM_MMCSD_4BBUS) & - readl(sock->addr + SOCK_MMCSD_CONFIG), - sock->addr + SOCK_MMCSD_CONFIG); + writel((~TIFM_MMCSD_4BBUS) + & readl(sock->addr + SOCK_MMCSD_CONFIG), + sock->addr + SOCK_MMCSD_CONFIG); } if (ios->clock) { @@ -704,23 +721,24 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios) if ((20000000 / clk_div1) > (24000000 / clk_div2)) { host->clk_freq = 20000000; host->clk_div = clk_div1; - writel((~TIFM_CTRL_FAST_CLK) & - readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + writel((~TIFM_CTRL_FAST_CLK) + & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); } else { host->clk_freq = 24000000; host->clk_div = clk_div2; - writel(TIFM_CTRL_FAST_CLK | - readl(sock->addr + SOCK_CONTROL), - sock->addr + SOCK_CONTROL); + writel(TIFM_CTRL_FAST_CLK + | readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); } } else { host->clk_div = 0; } host->clk_div &= TIFM_MMCSD_CLKMASK; - writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) & - readl(sock->addr + SOCK_MMCSD_CONFIG)), - sock->addr + SOCK_MMCSD_CONFIG); + writel(host->clk_div + | ((~TIFM_MMCSD_CLKMASK) + & readl(sock->addr + SOCK_MMCSD_CONFIG)), + sock->addr + SOCK_MMCSD_CONFIG); if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) host->flags |= OPENDRAIN; @@ -734,7 +752,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); @@ -762,20 +780,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); - 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) @@ -784,8 +849,8 @@ static int tifm_sd_probe(struct tifm_dev *sock) struct tifm_sd *host; int rc = -EIO; - if (!(TIFM_SOCK_STATE_OCCUPIED & - readl(sock->addr + SOCK_PRESENT_STATE))) { + if (!(TIFM_SOCK_STATE_OCCUPIED + & readl(sock->addr + SOCK_PRESENT_STATE))) { printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n"); return rc; } @@ -795,78 +860,42 @@ 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); - INIT_DELAYED_WORK(&host->abort_handler, tifm_sd_abort); - 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 + // 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); - 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); - - queue_delayed_work(sock->wq, &host->abort_handler, - 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; } @@ -874,31 +903,57 @@ 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; - 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); + del_timer_sync(&host->timer); + 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); + sock->addr + SOCK_CONTROL); tifm_set_drvdata(sock, NULL); mmc_free_host(mmc); } +#ifdef CONFIG_PM + +static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state) +{ + struct mmc_host *mmc = tifm_get_drvdata(sock); + int rc; + + rc = mmc_suspend_host(mmc, state); + /* The meaning of the bit majority in this constant is unknown. */ + writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), + sock->addr + SOCK_CONTROL); + return rc; +} + +static int tifm_sd_resume(struct tifm_dev *sock) +{ + struct mmc_host *mmc = tifm_get_drvdata(sock); + struct tifm_sd *host = mmc_priv(mmc); + + if (sock->media_id != FM_SD + || tifm_sd_initialize_host(host)) { + tifm_eject(sock); + return 0; + } else { + return mmc_resume_host(mmc); + } +} + +#else + +#define tifm_sd_suspend NULL +#define tifm_sd_resume NULL + +#endif /* CONFIG_PM */ + static tifm_media_id tifm_sd_id_tbl[] = { FM_SD, 0 }; @@ -910,7 +965,9 @@ static struct tifm_driver tifm_sd_driver = { }, .id_table = tifm_sd_id_tbl, .probe = tifm_sd_probe, - .remove = tifm_sd_remove + .remove = tifm_sd_remove, + .suspend = tifm_sd_suspend, + .resume = tifm_sd_resume }; static int __init tifm_sd_init(void) diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 7a282672f8e9..a44d8777ab9f 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1,7 +1,7 @@ /* * linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver * - * Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved. + * Copyright (C) 2004-2006 Pierre Ossman, 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 @@ -272,16 +272,9 @@ static inline int wbsd_next_sg(struct wbsd_host *host) return host->num_sg; } -static inline char *wbsd_kmap_sg(struct wbsd_host *host) +static inline char *wbsd_sg_to_buffer(struct wbsd_host *host) { - host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) + - host->cur_sg->offset; - return host->mapped_sg; -} - -static inline void wbsd_kunmap_sg(struct wbsd_host *host) -{ - kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ); + return page_address(host->cur_sg->page) + host->cur_sg->offset; } static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data) @@ -302,12 +295,11 @@ static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data) * we do not transfer too much. */ for (i = 0; i < len; i++) { - sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset; + sgbuf = page_address(sg[i].page) + sg[i].offset; if (size < sg[i].length) memcpy(dmabuf, sgbuf, size); else memcpy(dmabuf, sgbuf, sg[i].length); - kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ); dmabuf += sg[i].length; if (size < sg[i].length) @@ -347,7 +339,7 @@ static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data) * we do not transfer too much. */ for (i = 0; i < len; i++) { - sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset; + sgbuf = page_address(sg[i].page) + sg[i].offset; if (size < sg[i].length) memcpy(sgbuf, dmabuf, size); else @@ -497,7 +489,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host) if (data->bytes_xfered == host->size) return; - buffer = wbsd_kmap_sg(host) + host->offset; + buffer = wbsd_sg_to_buffer(host) + host->offset; /* * Drain the fifo. This has a tendency to loop longer @@ -526,17 +518,13 @@ static void wbsd_empty_fifo(struct wbsd_host *host) /* * Transfer done? */ - if (data->bytes_xfered == host->size) { - wbsd_kunmap_sg(host); + if (data->bytes_xfered == host->size) return; - } /* * End of scatter list entry? */ if (host->remain == 0) { - wbsd_kunmap_sg(host); - /* * Get next entry. Check if last. */ @@ -554,13 +542,11 @@ static void wbsd_empty_fifo(struct wbsd_host *host) return; } - buffer = wbsd_kmap_sg(host); + buffer = wbsd_sg_to_buffer(host); } } } - wbsd_kunmap_sg(host); - /* * This is a very dirty hack to solve a * hardware problem. The chip doesn't trigger @@ -583,7 +569,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host) if (data->bytes_xfered == host->size) return; - buffer = wbsd_kmap_sg(host) + host->offset; + buffer = wbsd_sg_to_buffer(host) + host->offset; /* * Fill the fifo. This has a tendency to loop longer @@ -612,17 +598,13 @@ static void wbsd_fill_fifo(struct wbsd_host *host) /* * Transfer done? */ - if (data->bytes_xfered == host->size) { - wbsd_kunmap_sg(host); + if (data->bytes_xfered == host->size) return; - } /* * End of scatter list entry? */ if (host->remain == 0) { - wbsd_kunmap_sg(host); - /* * Get next entry. Check if last. */ @@ -640,13 +622,11 @@ static void wbsd_fill_fifo(struct wbsd_host *host) return; } - buffer = wbsd_kmap_sg(host); + buffer = wbsd_sg_to_buffer(host); } } } - wbsd_kunmap_sg(host); - /* * The controller stops sending interrupts for * 'FIFO empty' under certain conditions. So we @@ -909,6 +889,45 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) * transfered. */ if (cmd->data && (cmd->error == MMC_ERR_NONE)) { + /* + * The hardware is so delightfully stupid that it has a list + * of "data" commands. If a command isn't on this list, it'll + * just go back to the idle state and won't send any data + * interrupts. + */ + switch (cmd->opcode) { + case 11: + case 17: + case 18: + case 20: + case 24: + case 25: + case 26: + case 27: + case 30: + case 42: + case 56: + break; + + /* ACMDs. We don't keep track of state, so we just treat them + * like any other command. */ + case 51: + break; + + default: +#ifdef CONFIG_MMC_DEBUG + printk(KERN_WARNING "%s: Data command %d is not " + "supported by this controller.\n", + mmc_hostname(host->mmc), cmd->opcode); +#endif + cmd->data->error = MMC_ERR_INVALID; + + if (cmd->data->stop) + wbsd_send_command(host, cmd->data->stop); + + goto done; + }; + /* * Dirty fix for hardware bug. */ @@ -1343,16 +1362,27 @@ 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 + * space for CRC. So the maximum is 4095 - 4*2 = 4087. + */ + 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); diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h index 6072993f01e3..d06718b0e2ab 100644 --- a/drivers/mmc/wbsd.h +++ b/drivers/mmc/wbsd.h @@ -154,7 +154,6 @@ struct wbsd_host struct scatterlist* cur_sg; /* Current SG entry */ unsigned int num_sg; /* Number of entries left */ - void* mapped_sg; /* vaddr of mapped sg */ unsigned int offset; /* Offset into current entry */ unsigned int remain; /* Data left in curren entry */ diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 80bdcf846234..716a47210aa3 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -792,8 +792,7 @@ static void poll_vortex(struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); unsigned long flags; - local_save_flags(flags); - local_irq_disable(); + local_irq_save(flags); (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev); local_irq_restore(flags); } diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8aa8dd02b910..ad92b6a76ee6 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -190,7 +190,7 @@ config MII config MACB tristate "Atmel MACB support" - depends on NET_ETHERNET && AVR32 + depends on NET_ETHERNET && (AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263) select MII help The Atmel MACB ethernet interface is found on many AT32 and AT91 @@ -235,16 +235,6 @@ config BMAC To compile this driver as a module, choose M here: the module will be called bmac. -config OAKNET - tristate "National DP83902AV (Oak ethernet) support" - depends on NET_ETHERNET && PPC && BROKEN - select CRC32 - help - Say Y if your machine has this type of Ethernet network card. - - To compile this driver as a module, choose M here: the module - will be called oaknet. - config ARIADNE tristate "Ariadne support" depends on NET_ETHERNET && ZORRO @@ -1155,21 +1145,6 @@ config SEEQ8005 . The module will be called seeq8005. -config SKMC - tristate "SKnet MCA support" - depends on NET_ETHERNET && MCA && BROKEN - ---help--- - These are Micro Channel Ethernet adapters. You need to say Y to "MCA - support" in order to use this driver. Supported cards are the SKnet - Junior MC2 and the SKnet MC2(+). The driver automatically - distinguishes between the two cards. Note that using multiple boards - of different type hasn't been tested with this driver. Say Y if you - have one of these Ethernet adapters. - - To compile this driver as a module, choose M here and read - . The module - will be called sk_mca. - config NE2_MCA tristate "NE/2 (ne2000 MCA version) support" depends on NET_ETHERNET && MCA_LEGACY @@ -1788,6 +1763,18 @@ config LAN_SAA9730 workstations. See . +config SC92031 + tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)" + depends on NET_PCI && PCI && EXPERIMENTAL + select CRC32 + ---help--- + This is a driver for the Fast Ethernet PCI network cards based on + the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you + have one of these, say Y here. + + To compile this driver as a module, choose M here: the module + will be called sc92031. This is recommended. + config NET_POCKET bool "Pocket and portable adapters" depends on NET_ETHERNET && PARPORT @@ -2392,6 +2379,24 @@ config CHELSIO_T1_NAPI NAPI is a driver API designed to reduce CPU and interrupt load when the driver is receiving lots of packets from the card. +config CHELSIO_T3 + tristate "Chelsio Communications T3 10Gb Ethernet support" + depends on PCI + help + This driver supports Chelsio T3-based gigabit and 10Gb Ethernet + adapters. + + For general information about Chelsio and our products, visit + our website at . + + For customer support, please visit our customer support page at + . + + Please send feedback to . + + To compile this driver as a module, choose M here: the module + will be called cxgb3. + config EHEA tristate "eHEA Ethernet support" depends on IBMEBUS @@ -2488,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" @@ -2541,6 +2553,7 @@ config DEFXX config SKFP tristate "SysKonnect FDDI PCI support" depends on FDDI && PCI + select BITREVERSE ---help--- Say Y here if you have a SysKonnect FDDI PCI adapter. The following adapters are supported by this driver: diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4c0d4e5ce42b..0878e3df5174 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_CHELSIO_T1) += chelsio/ +obj-$(CONFIG_CHELSIO_T3) += cxgb3/ obj-$(CONFIG_EHEA) += ehea/ obj-$(CONFIG_BONDING) += bonding/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o @@ -36,8 +37,6 @@ obj-$(CONFIG_CASSINI) += cassini.o obj-$(CONFIG_MACE) += mace.o obj-$(CONFIG_BMAC) += bmac.o -obj-$(CONFIG_OAKNET) += oaknet.o 8390.o - obj-$(CONFIG_DGRS) += dgrs.o obj-$(CONFIG_VORTEX) += 3c59x.o obj-$(CONFIG_TYPHOON) += typhoon.o @@ -137,7 +136,6 @@ obj-$(CONFIG_AT1700) += at1700.o obj-$(CONFIG_EL1) += 3c501.o obj-$(CONFIG_EL16) += 3c507.o obj-$(CONFIG_ELMC) += 3c523.o -obj-$(CONFIG_SKMC) += sk_mca.o obj-$(CONFIG_IBMLANA) += ibmlana.o obj-$(CONFIG_ELMC_II) += 3c527.o obj-$(CONFIG_EL3) += 3c509.o @@ -160,6 +158,7 @@ obj-$(CONFIG_APRICOT) += 82596.o obj-$(CONFIG_LASI_82596) += lasi_82596.o obj-$(CONFIG_MVME16x_NET) += 82596.o obj-$(CONFIG_BVME6000_NET) += 82596.o +obj-$(CONFIG_SC92031) += sc92031.o # This is also a 82596 and should probably be merged obj-$(CONFIG_LP486E) += lp486e.o @@ -196,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/Space.c b/drivers/net/Space.c index 9305eb9b1b98..dd8ed456c8b2 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -59,7 +59,6 @@ extern struct net_device *wavelan_probe(int unit); extern struct net_device *arlan_probe(int unit); extern struct net_device *el16_probe(int unit); extern struct net_device *elmc_probe(int unit); -extern struct net_device *skmca_probe(int unit); extern struct net_device *elplus_probe(int unit); extern struct net_device *ac3200_probe(int unit); extern struct net_device *es_probe(int unit); @@ -152,9 +151,6 @@ static struct devprobe2 mca_probes[] __initdata = { #endif #ifdef CONFIG_ELMC_II /* 3c527 */ {mc32_probe, 0}, -#endif -#ifdef CONFIG_SKMC /* SKnet Microchannel */ - {skmca_probe, 0}, #endif {NULL, 0}, }; diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 18896f24d407..9c399aaefbdd 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1334,8 +1334,7 @@ err_no_interrupt: static void amd8111e_poll(struct net_device *dev) { unsigned long flags; - local_save_flags(flags); - local_irq_disable(); + local_irq_save(flags); amd8111e_interrupt(0, dev); local_irq_restore(flags); } 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/b44.c b/drivers/net/b44.c index 303a8d94ad4b..5ff7882297d6 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -721,7 +721,7 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) struct ring_info *src_map, *dest_map; struct rx_header *rh; int dest_idx; - u32 ctrl; + __le32 ctrl; dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1); dest_desc = &bp->rx_ring[dest_idx]; @@ -783,7 +783,7 @@ static int b44_rx(struct b44 *bp, int budget) RX_PKT_BUF_SZ, PCI_DMA_FROMDEVICE); rh = (struct rx_header *) skb->data; - len = cpu_to_le16(rh->len); + len = le16_to_cpu(rh->len); if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) || (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) { drop_it: @@ -799,7 +799,7 @@ static int b44_rx(struct b44 *bp, int budget) do { udelay(2); barrier(); - len = cpu_to_le16(rh->len); + len = le16_to_cpu(rh->len); } while (len == 0 && i++ < 5); if (len == 0) goto drop_it; @@ -2061,7 +2061,7 @@ out: static int b44_read_eeprom(struct b44 *bp, u8 *data) { long i; - u16 *ptr = (u16 *) data; + __le16 *ptr = (__le16 *) data; for (i = 0; i < 128; i += 2) ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i)); diff --git a/drivers/net/b44.h b/drivers/net/b44.h index 4944507fad23..18fc13336628 100644 --- a/drivers/net/b44.h +++ b/drivers/net/b44.h @@ -308,8 +308,8 @@ #define MII_TLEDCTRL_ENABLE 0x0040 struct dma_desc { - u32 ctrl; - u32 addr; + __le32 ctrl; + __le32 addr; }; /* There are only 12 bits in the DMA engine for descriptor offsetting @@ -327,9 +327,9 @@ struct dma_desc { #define RX_COPY_THRESHOLD 256 struct rx_header { - u16 len; - u16 flags; - u16 pad[12]; + __le16 len; + __le16 flags; + __le16 pad[12]; }; #define RX_HEADER_LEN 28 diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 4528ce9c4e43..c143304dcff5 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -140,7 +141,6 @@ static unsigned char *bmac_emergency_rxbuf; + (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \ + sizeof(struct sk_buff_head)) -static unsigned char bitrev(unsigned char b); static int bmac_open(struct net_device *dev); static int bmac_close(struct net_device *dev); static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev); @@ -586,18 +586,6 @@ bmac_construct_rxbuff(struct sk_buff *skb, volatile struct dbdma_cmd *cp) virt_to_bus(addr), 0); } -/* Bit-reverse one byte of an ethernet hardware address. */ -static unsigned char -bitrev(unsigned char b) -{ - int d = 0, i; - - for (i = 0; i < 8; ++i, b >>= 1) - d = (d << 1) | (b & 1); - return d; -} - - static void bmac_init_tx_ring(struct bmac_data *bp) { @@ -1224,8 +1212,8 @@ bmac_get_station_address(struct net_device *dev, unsigned char *ea) { reset_and_select_srom(dev); data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits); - ea[2*i] = bitrev(data & 0x0ff); - ea[2*i+1] = bitrev((data >> 8) & 0x0ff); + ea[2*i] = bitrev8(data & 0x0ff); + ea[2*i+1] = bitrev8((data >> 8) & 0x0ff); } } @@ -1315,7 +1303,7 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i rev = addr[0] == 0 && addr[1] == 0xA0; for (j = 0; j < 6; ++j) - dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j]; + dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j]; /* Enable chip without interrupts for now */ bmac_enable_and_reset_chip(dev); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index ee7b75b976b5..5a96d7611af1 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -39,12 +39,9 @@ #include #define BCM_VLAN 1 #endif -#ifdef NETIF_F_TSO #include #include #include -#define BCM_TSO 1 -#endif #include #include #include @@ -1728,7 +1725,7 @@ bnx2_tx_int(struct bnx2 *bp) tx_buf = &bp->tx_buf_ring[sw_ring_cons]; skb = tx_buf->skb; -#ifdef BCM_TSO + /* partial BD completions possible with TSO packets */ if (skb_is_gso(skb)) { u16 last_idx, last_ring_idx; @@ -1744,7 +1741,7 @@ bnx2_tx_int(struct bnx2 *bp) break; } } -#endif + pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping), skb_headlen(skb), PCI_DMA_TODEVICE); @@ -4514,7 +4511,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) vlan_tag_flags |= (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16)); } -#ifdef BCM_TSO if ((mss = skb_shinfo(skb)->gso_size) && (skb->len > (bp->dev->mtu + ETH_HLEN))) { u32 tcp_opt_len, ip_tcp_len; @@ -4547,7 +4543,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) } } else -#endif { mss = 0; } @@ -5544,10 +5539,8 @@ static const struct ethtool_ops bnx2_ethtool_ops = { .set_tx_csum = ethtool_op_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, -#ifdef BCM_TSO .get_tso = ethtool_op_get_tso, .set_tso = bnx2_set_tso, -#endif .self_test_count = bnx2_self_test_count, .self_test = bnx2_self_test, .get_strings = bnx2_get_strings, @@ -5954,8 +5947,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) * responding after a while. * * AMD believes this incompatibility is unique to the 5706, and - * prefers to locally disable MSI rather than globally disabling it - * using pci_msi_quirk. + * prefers to locally disable MSI rather than globally disabling it. */ if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) { struct pci_dev *amd_8132 = NULL; @@ -6104,9 +6096,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) #ifdef BCM_VLAN dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; #endif -#ifdef BCM_TSO dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; -#endif netif_carrier_off(bp->dev); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6482aed4bb7c..d3801a00d3d5 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4704,6 +4704,7 @@ static int bond_check_params(struct bond_params *params) static struct lock_class_key bonding_netdev_xmit_lock_key; /* Create a new bond based on the specified name and bonding parameters. + * If name is NULL, obtain a suitable "bond%d" name for us. * Caller must NOT hold rtnl_lock; we need to release it here before we * set up our sysfs entries. */ @@ -4713,7 +4714,8 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond int res; rtnl_lock(); - bond_dev = alloc_netdev(sizeof(struct bonding), name, ether_setup); + bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "", + ether_setup); if (!bond_dev) { printk(KERN_ERR DRV_NAME ": %s: eek! can't alloc netdev!\n", @@ -4722,6 +4724,12 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond goto out_rtnl; } + if (!name) { + res = dev_alloc_name(bond_dev, "bond%d"); + if (res < 0) + goto out_netdev; + } + /* bond_init() must be called after dev_alloc_name() (for the * /proc files), but before register_netdevice(), because we * need to set function pointers. @@ -4748,14 +4756,19 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond rtnl_unlock(); /* allows sysfs registration of net device */ res = bond_create_sysfs_entry(bond_dev->priv); - goto done; + if (res < 0) { + rtnl_lock(); + goto out_bond; + } + + return 0; + out_bond: bond_deinit(bond_dev); out_netdev: free_netdev(bond_dev); out_rtnl: rtnl_unlock(); -done: return res; } @@ -4763,7 +4776,6 @@ static int __init bonding_init(void) { int i; int res; - char new_bond_name[8]; /* Enough room for 999 bonds at init. */ printk(KERN_INFO "%s", version); @@ -4776,8 +4788,7 @@ static int __init bonding_init(void) bond_create_proc_dir(); #endif for (i = 0; i < max_bonds; i++) { - sprintf(new_bond_name, "bond%d",i); - res = bond_create(new_bond_name,&bonding_defaults, NULL); + res = bond_create(NULL, &bonding_defaults, NULL); if (res) goto err; } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index ced9ed8f995a..878f7aabeeac 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,11 +1428,26 @@ 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; ret = class_create_file(netdev_class, &class_attr_bonding_masters); + /* + * Permit multiple loads of the module by ignoring failures to + * create the bonding_masters sysfs file. Bonding devices + * created by second or subsequent loads of the module will + * not be listed in, or controllable by, bonding_masters, but + * will have the usual "bonding" sysfs directory. + * + * This is done to preserve backwards compatibility for + * initscripts/sysconfig, which load bonding multiple times to + * configure multiple bonding devices. + */ + if (ret == -EEXIST) { + netdev_class = NULL; + return 0; + } return ret; @@ -1395,13 +1471,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 +1488,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/bonding/bonding.h b/drivers/net/bonding/bonding.h index 0978c9ac6d2b..41aa78bf1f78 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -22,8 +22,8 @@ #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.1.1" -#define DRV_RELDATE "September 26, 2006" +#define DRV_VERSION "3.1.2" +#define DRV_RELDATE "January 20, 2007" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" @@ -237,12 +237,13 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) #define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \ BOND_ARP_VALIDATE_BACKUP) -extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave) +static inline int slave_do_arp_validate(struct bonding *bond, + struct slave *slave) { return bond->params.arp_validate & (1 << slave->state); } -extern inline unsigned long slave_last_rx(struct bonding *bond, +static inline unsigned long slave_last_rx(struct bonding *bond, struct slave *slave) { if (slave_do_arp_validate(bond, slave)) diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 74758d2c7af8..787f2f2820fe 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -324,7 +324,7 @@ struct board_info { unsigned char mdio_phybaseaddr; struct gmac *gmac; struct gphy *gphy; - struct mdio_ops *mdio_ops; + struct mdio_ops *mdio_ops; const char *desc; }; diff --git a/drivers/net/chelsio/cpl5_cmd.h b/drivers/net/chelsio/cpl5_cmd.h index 35f565be4fd3..e36d45b78cc7 100644 --- a/drivers/net/chelsio/cpl5_cmd.h +++ b/drivers/net/chelsio/cpl5_cmd.h @@ -103,7 +103,7 @@ enum CPL_opcode { CPL_MIGRATE_C2T_RPL = 0xDD, CPL_ERROR = 0xD7, - /* internal: driver -> TOM */ + /* internal: driver -> TOM */ CPL_MSS_CHANGE = 0xE1 }; @@ -159,8 +159,8 @@ enum { // TX_PKT_LSO ethernet types }; union opcode_tid { - u32 opcode_tid; - u8 opcode; + u32 opcode_tid; + u8 opcode; }; #define S_OPCODE 24 @@ -234,7 +234,7 @@ struct cpl_pass_accept_req { u32 local_ip; u32 peer_ip; u32 tos_tid; - struct tcp_options tcp_options; + struct tcp_options tcp_options; u8 dst_mac[6]; u16 vlan_tag; u8 src_mac[6]; @@ -250,12 +250,12 @@ struct cpl_pass_accept_rpl { u32 peer_ip; u32 opt0h; union { - u32 opt0l; - struct { - u8 rsvd[3]; - u8 status; + u32 opt0l; + struct { + u8 rsvd[3]; + u8 status; + }; }; - }; }; struct cpl_act_open_req { diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index fd5d821f3f2a..7d0f24f69777 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -69,14 +69,14 @@ static inline void cancel_mac_stats_update(struct adapter *ap) cancel_delayed_work(&ap->stats_update_task); } -#define MAX_CMDQ_ENTRIES 16384 -#define MAX_CMDQ1_ENTRIES 1024 -#define MAX_RX_BUFFERS 16384 -#define MAX_RX_JUMBO_BUFFERS 16384 +#define MAX_CMDQ_ENTRIES 16384 +#define MAX_CMDQ1_ENTRIES 1024 +#define MAX_RX_BUFFERS 16384 +#define MAX_RX_JUMBO_BUFFERS 16384 #define MAX_TX_BUFFERS_HIGH 16384U #define MAX_TX_BUFFERS_LOW 1536U #define MAX_TX_BUFFERS 1460U -#define MIN_FL_ENTRIES 32 +#define MIN_FL_ENTRIES 32 #define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ @@ -143,7 +143,7 @@ static void link_report(struct port_info *p) case SPEED_100: s = "100Mbps"; break; } - printk(KERN_INFO "%s: link up, %s, %s-duplex\n", + printk(KERN_INFO "%s: link up, %s, %s-duplex\n", p->dev->name, s, p->link_config.duplex == DUPLEX_FULL ? "full" : "half"); } @@ -233,7 +233,7 @@ static int cxgb_up(struct adapter *adapter) t1_sge_start(adapter->sge); t1_interrupts_enable(adapter); - out_err: +out_err: return err; } @@ -454,51 +454,21 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats, const struct cmac_statistics *s; const struct sge_intr_counts *t; struct sge_port_stats ss; + unsigned int len; s = mac->ops->statistics_update(mac, MAC_STATS_UPDATE_FULL); - *data++ = s->TxOctetsOK; - *data++ = s->TxOctetsBad; - *data++ = s->TxUnicastFramesOK; - *data++ = s->TxMulticastFramesOK; - *data++ = s->TxBroadcastFramesOK; - *data++ = s->TxPauseFrames; - *data++ = s->TxFramesWithDeferredXmissions; - *data++ = s->TxLateCollisions; - *data++ = s->TxTotalCollisions; - *data++ = s->TxFramesAbortedDueToXSCollisions; - *data++ = s->TxUnderrun; - *data++ = s->TxLengthErrors; - *data++ = s->TxInternalMACXmitError; - *data++ = s->TxFramesWithExcessiveDeferral; - *data++ = s->TxFCSErrors; + len = sizeof(u64)*(&s->TxFCSErrors + 1 - &s->TxOctetsOK); + memcpy(data, &s->TxOctetsOK, len); + data += len; - *data++ = s->RxOctetsOK; - *data++ = s->RxOctetsBad; - *data++ = s->RxUnicastFramesOK; - *data++ = s->RxMulticastFramesOK; - *data++ = s->RxBroadcastFramesOK; - *data++ = s->RxPauseFrames; - *data++ = s->RxFCSErrors; - *data++ = s->RxAlignErrors; - *data++ = s->RxSymbolErrors; - *data++ = s->RxDataErrors; - *data++ = s->RxSequenceErrors; - *data++ = s->RxRuntErrors; - *data++ = s->RxJabberErrors; - *data++ = s->RxInternalMACRcvError; - *data++ = s->RxInRangeLengthErrors; - *data++ = s->RxOutOfRangeLengthField; - *data++ = s->RxFrameTooLongErrors; + len = sizeof(u64)*(&s->RxFrameTooLongErrors + 1 - &s->RxOctetsOK); + memcpy(data, &s->RxOctetsOK, len); + data += len; t1_sge_get_port_stats(adapter->sge, dev->if_port, &ss); - *data++ = ss.rx_packets; - *data++ = ss.rx_cso_good; - *data++ = ss.tx_packets; - *data++ = ss.tx_cso; - *data++ = ss.tx_tso; - *data++ = ss.vlan_xtract; - *data++ = ss.vlan_insert; + memcpy(data, &ss, sizeof(ss)); + data += sizeof(ss); t = t1_sge_get_intr_counts(adapter->sge); *data++ = t->rx_drops; @@ -749,7 +719,7 @@ static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) return -EINVAL; if (adapter->flags & FULL_INIT_DONE) - return -EBUSY; + return -EBUSY; adapter->params.sge.freelQ_size[!jumbo_fl] = e->rx_pending; adapter->params.sge.freelQ_size[jumbo_fl] = e->rx_jumbo_pending; @@ -764,7 +734,7 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) struct adapter *adapter = dev->priv; adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs; - adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce; + adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce; adapter->params.sge.sample_interval_usecs = c->rate_sample_interval; t1_sge_set_coalesce_params(adapter->sge, &adapter->params.sge); return 0; @@ -782,9 +752,9 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) static int get_eeprom_len(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->priv; - return t1_is_asic(adapter) ? EEPROM_SIZE : 0; + return t1_is_asic(adapter) ? EEPROM_SIZE : 0; } #define EEPROM_MAGIC(ap) \ @@ -848,7 +818,7 @@ static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) u32 val; if (!phy->mdio_read) - return -EOPNOTSUPP; + return -EOPNOTSUPP; phy->mdio_read(adapter, data->phy_id, 0, data->reg_num & 0x1f, &val); data->val_out = val; @@ -860,7 +830,7 @@ static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) if (!capable(CAP_NET_ADMIN)) return -EPERM; if (!phy->mdio_write) - return -EOPNOTSUPP; + return -EOPNOTSUPP; phy->mdio_write(adapter, data->phy_id, 0, data->reg_num & 0x1f, data->val_in); break; @@ -879,9 +849,9 @@ static int t1_change_mtu(struct net_device *dev, int new_mtu) struct cmac *mac = adapter->port[dev->if_port].mac; if (!mac->ops->set_mtu) - return -EOPNOTSUPP; + return -EOPNOTSUPP; if (new_mtu < 68) - return -EINVAL; + return -EINVAL; if ((ret = mac->ops->set_mtu(mac, new_mtu))) return ret; dev->mtu = new_mtu; @@ -1211,9 +1181,9 @@ static int __devinit init_one(struct pci_dev *pdev, return 0; - out_release_adapter_res: +out_release_adapter_res: t1_free_sw_modules(adapter); - out_free_dev: +out_free_dev: if (adapter) { if (adapter->regs) iounmap(adapter->regs); @@ -1222,7 +1192,7 @@ static int __devinit init_one(struct pci_dev *pdev, free_netdev(adapter->port[i].dev); } pci_release_regions(pdev); - out_disable_pdev: +out_disable_pdev: pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); return err; @@ -1273,28 +1243,27 @@ static int t1_clock(struct adapter *adapter, int mode) int M_MEM_VAL; enum { - M_CORE_BITS = 9, - T_CORE_VAL = 0, - T_CORE_BITS = 2, - N_CORE_VAL = 0, - N_CORE_BITS = 2, - M_MEM_BITS = 9, - T_MEM_VAL = 0, - T_MEM_BITS = 2, - N_MEM_VAL = 0, - N_MEM_BITS = 2, - NP_LOAD = 1 << 17, - S_LOAD_MEM = 1 << 5, - S_LOAD_CORE = 1 << 6, - S_CLOCK = 1 << 3 + M_CORE_BITS = 9, + T_CORE_VAL = 0, + T_CORE_BITS = 2, + N_CORE_VAL = 0, + N_CORE_BITS = 2, + M_MEM_BITS = 9, + T_MEM_VAL = 0, + T_MEM_BITS = 2, + N_MEM_VAL = 0, + N_MEM_BITS = 2, + NP_LOAD = 1 << 17, + S_LOAD_MEM = 1 << 5, + S_LOAD_CORE = 1 << 6, + S_CLOCK = 1 << 3 }; if (!t1_is_T1B(adapter)) return -ENODEV; /* Can't re-clock this chip. */ - if (mode & 2) { + if (mode & 2) return 0; /* show current mode. */ - } if ((adapter->t1powersave & 1) == (mode & 1)) return -EALREADY; /* ASIC already running in mode. */ @@ -1386,26 +1355,26 @@ static inline void t1_sw_reset(struct pci_dev *pdev) static void __devexit remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); + struct adapter *adapter = dev->priv; + int i; - if (dev) { - int i; - struct adapter *adapter = dev->priv; - - for_each_port(adapter, i) - if (test_bit(i, &adapter->registered_device_map)) - unregister_netdev(adapter->port[i].dev); - - t1_free_sw_modules(adapter); - iounmap(adapter->regs); - while (--i >= 0) - if (adapter->port[i].dev) - free_netdev(adapter->port[i].dev); - - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - t1_sw_reset(pdev); + for_each_port(adapter, i) { + if (test_bit(i, &adapter->registered_device_map)) + unregister_netdev(adapter->port[i].dev); } + + t1_free_sw_modules(adapter); + iounmap(adapter->regs); + + while (--i >= 0) { + if (adapter->port[i].dev) + free_netdev(adapter->port[i].dev); + } + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + t1_sw_reset(pdev); } static struct pci_driver driver = { diff --git a/drivers/net/chelsio/elmer0.h b/drivers/net/chelsio/elmer0.h index 9ebecaa97d31..eef655c827d9 100644 --- a/drivers/net/chelsio/elmer0.h +++ b/drivers/net/chelsio/elmer0.h @@ -46,14 +46,14 @@ enum { }; /* ELMER0 registers */ -#define A_ELMER0_VERSION 0x100000 -#define A_ELMER0_PHY_CFG 0x100004 -#define A_ELMER0_INT_ENABLE 0x100008 -#define A_ELMER0_INT_CAUSE 0x10000c -#define A_ELMER0_GPI_CFG 0x100010 -#define A_ELMER0_GPI_STAT 0x100014 -#define A_ELMER0_GPO 0x100018 -#define A_ELMER0_PORT0_MI1_CFG 0x400000 +#define A_ELMER0_VERSION 0x100000 +#define A_ELMER0_PHY_CFG 0x100004 +#define A_ELMER0_INT_ENABLE 0x100008 +#define A_ELMER0_INT_CAUSE 0x10000c +#define A_ELMER0_GPI_CFG 0x100010 +#define A_ELMER0_GPI_STAT 0x100014 +#define A_ELMER0_GPO 0x100018 +#define A_ELMER0_PORT0_MI1_CFG 0x400000 #define S_MI1_MDI_ENABLE 0 #define V_MI1_MDI_ENABLE(x) ((x) << S_MI1_MDI_ENABLE) @@ -111,18 +111,18 @@ enum { #define V_MI1_OP_BUSY(x) ((x) << S_MI1_OP_BUSY) #define F_MI1_OP_BUSY V_MI1_OP_BUSY(1U) -#define A_ELMER0_PORT1_MI1_CFG 0x500000 -#define A_ELMER0_PORT1_MI1_ADDR 0x500004 -#define A_ELMER0_PORT1_MI1_DATA 0x500008 -#define A_ELMER0_PORT1_MI1_OP 0x50000c -#define A_ELMER0_PORT2_MI1_CFG 0x600000 -#define A_ELMER0_PORT2_MI1_ADDR 0x600004 -#define A_ELMER0_PORT2_MI1_DATA 0x600008 -#define A_ELMER0_PORT2_MI1_OP 0x60000c -#define A_ELMER0_PORT3_MI1_CFG 0x700000 -#define A_ELMER0_PORT3_MI1_ADDR 0x700004 -#define A_ELMER0_PORT3_MI1_DATA 0x700008 -#define A_ELMER0_PORT3_MI1_OP 0x70000c +#define A_ELMER0_PORT1_MI1_CFG 0x500000 +#define A_ELMER0_PORT1_MI1_ADDR 0x500004 +#define A_ELMER0_PORT1_MI1_DATA 0x500008 +#define A_ELMER0_PORT1_MI1_OP 0x50000c +#define A_ELMER0_PORT2_MI1_CFG 0x600000 +#define A_ELMER0_PORT2_MI1_ADDR 0x600004 +#define A_ELMER0_PORT2_MI1_DATA 0x600008 +#define A_ELMER0_PORT2_MI1_OP 0x60000c +#define A_ELMER0_PORT3_MI1_CFG 0x700000 +#define A_ELMER0_PORT3_MI1_ADDR 0x700004 +#define A_ELMER0_PORT3_MI1_DATA 0x700008 +#define A_ELMER0_PORT3_MI1_OP 0x70000c /* Simple bit definition for GPI and GP0 registers. */ #define ELMER0_GP_BIT0 0x0001 diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c index 4192f0f5b3ee..d7c5406a6c3f 100644 --- a/drivers/net/chelsio/espi.c +++ b/drivers/net/chelsio/espi.c @@ -202,9 +202,9 @@ static void espi_setup_for_pm3393(adapter_t *adapter) static void espi_setup_for_vsc7321(adapter_t *adapter) { - writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0); - writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1); - writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2); + writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0); + writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1); + writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2); writel(0xa00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK); writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK); writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH); @@ -247,10 +247,10 @@ int t1_espi_init(struct peespi *espi, int mac_type, int nports) writel(V_OUT_OF_SYNC_COUNT(4) | V_DIP2_PARITY_ERR_THRES(3) | V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL); - writel(nports == 4 ? 0x200040 : 0x1000080, + writel(nports == 4 ? 0x200040 : 0x1000080, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); } else - writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); + writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2); if (mac_type == CHBT_MAC_PM3393) espi_setup_for_pm3393(adapter); @@ -301,7 +301,8 @@ void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val) { struct peespi *espi = adapter->espi; - if (!is_T2(adapter)) return; + if (!is_T2(adapter)) + return; spin_lock(&espi->lock); espi->misc_ctrl = (val & ~MON_MASK) | (espi->misc_ctrl & MON_MASK); @@ -340,32 +341,31 @@ u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait) * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in * one shot, since there is no per port counter on the out side. */ -int -t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait) +int t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait) { - struct peespi *espi = adapter->espi; + struct peespi *espi = adapter->espi; u8 i, nport = (u8)adapter->params.nports; - if (!wait) { - if (!spin_trylock(&espi->lock)) - return -1; - } else - spin_lock(&espi->lock); + if (!wait) { + if (!spin_trylock(&espi->lock)) + return -1; + } else + spin_lock(&espi->lock); - if ( (espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION ) { + if ((espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION) { espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) | F_MONITORED_DIRECTION; - writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); - } + writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); + } for (i = 0 ; i < nport; i++, valp++) { if (i) { writel(espi->misc_ctrl | V_MONITORED_PORT_NUM(i), adapter->regs + A_ESPI_MISC_CONTROL); } - *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3); - } + *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3); + } - writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); - spin_unlock(&espi->lock); - return 0; + writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); + spin_unlock(&espi->lock); + return 0; } diff --git a/drivers/net/chelsio/fpga_defs.h b/drivers/net/chelsio/fpga_defs.h index 17a3c2ba36a3..ccdb2bc9ae98 100644 --- a/drivers/net/chelsio/fpga_defs.h +++ b/drivers/net/chelsio/fpga_defs.h @@ -98,9 +98,9 @@ #define A_MI0_DATA_INT 0xb10 /* GMAC registers */ -#define A_GMAC_MACID_LO 0x28 -#define A_GMAC_MACID_HI 0x2c -#define A_GMAC_CSR 0x30 +#define A_GMAC_MACID_LO 0x28 +#define A_GMAC_MACID_HI 0x2c +#define A_GMAC_CSR 0x30 #define S_INTERFACE 0 #define M_INTERFACE 0x3 diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/chelsio/gmac.h index a2b8ad9b5535..006a2eb2d362 100644 --- a/drivers/net/chelsio/gmac.h +++ b/drivers/net/chelsio/gmac.h @@ -42,8 +42,15 @@ #include "common.h" -enum { MAC_STATS_UPDATE_FAST, MAC_STATS_UPDATE_FULL }; -enum { MAC_DIRECTION_RX = 1, MAC_DIRECTION_TX = 2 }; +enum { + MAC_STATS_UPDATE_FAST, + MAC_STATS_UPDATE_FULL +}; + +enum { + MAC_DIRECTION_RX = 1, + MAC_DIRECTION_TX = 2 +}; struct cmac_statistics { /* Transmit */ diff --git a/drivers/net/chelsio/ixf1010.c b/drivers/net/chelsio/ixf1010.c index 5b8f144e83d4..10b2a9a19006 100644 --- a/drivers/net/chelsio/ixf1010.c +++ b/drivers/net/chelsio/ixf1010.c @@ -145,48 +145,61 @@ static void disable_port(struct cmac *mac) t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val); } -#define RMON_UPDATE(mac, name, stat_name) \ - t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \ - (mac)->stats.stat_name += val; - /* * Read the current values of the RMON counters and add them to the cumulative * port statistics. The HW RMON counters are cleared by this operation. */ static void port_stats_update(struct cmac *mac) { - u32 val; + static struct { + unsigned int reg; + unsigned int offset; + } hw_stats[] = { - /* Rx stats */ - RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK); - RMON_UPDATE(mac, RxOctetsBad, RxOctetsBad); - RMON_UPDATE(mac, RxUCPkts, RxUnicastFramesOK); - RMON_UPDATE(mac, RxMCPkts, RxMulticastFramesOK); - RMON_UPDATE(mac, RxBCPkts, RxBroadcastFramesOK); - RMON_UPDATE(mac, RxJumboPkts, RxJumboFramesOK); - RMON_UPDATE(mac, RxFCSErrors, RxFCSErrors); - RMON_UPDATE(mac, RxAlignErrors, RxAlignErrors); - RMON_UPDATE(mac, RxLongErrors, RxFrameTooLongErrors); - RMON_UPDATE(mac, RxVeryLongErrors, RxFrameTooLongErrors); - RMON_UPDATE(mac, RxPauseMacControlCounter, RxPauseFrames); - RMON_UPDATE(mac, RxDataErrors, RxDataErrors); - RMON_UPDATE(mac, RxJabberErrors, RxJabberErrors); - RMON_UPDATE(mac, RxRuntErrors, RxRuntErrors); - RMON_UPDATE(mac, RxShortErrors, RxRuntErrors); - RMON_UPDATE(mac, RxSequenceErrors, RxSequenceErrors); - RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors); +#define HW_STAT(name, stat_name) \ + { REG_##name, \ + (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL } - /* Tx stats (skip collision stats as we are full-duplex only) */ - RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK); - RMON_UPDATE(mac, TxOctetsBad, TxOctetsBad); - RMON_UPDATE(mac, TxUCPkts, TxUnicastFramesOK); - RMON_UPDATE(mac, TxMCPkts, TxMulticastFramesOK); - RMON_UPDATE(mac, TxBCPkts, TxBroadcastFramesOK); - RMON_UPDATE(mac, TxJumboPkts, TxJumboFramesOK); - RMON_UPDATE(mac, TxPauseFrames, TxPauseFrames); - RMON_UPDATE(mac, TxExcessiveLengthDrop, TxLengthErrors); - RMON_UPDATE(mac, TxUnderrun, TxUnderrun); - RMON_UPDATE(mac, TxCRCErrors, TxFCSErrors); + /* Rx stats */ + HW_STAT(RxOctetsTotalOK, RxOctetsOK), + HW_STAT(RxOctetsBad, RxOctetsBad), + HW_STAT(RxUCPkts, RxUnicastFramesOK), + HW_STAT(RxMCPkts, RxMulticastFramesOK), + HW_STAT(RxBCPkts, RxBroadcastFramesOK), + HW_STAT(RxJumboPkts, RxJumboFramesOK), + HW_STAT(RxFCSErrors, RxFCSErrors), + HW_STAT(RxAlignErrors, RxAlignErrors), + HW_STAT(RxLongErrors, RxFrameTooLongErrors), + HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors), + HW_STAT(RxPauseMacControlCounter, RxPauseFrames), + HW_STAT(RxDataErrors, RxDataErrors), + HW_STAT(RxJabberErrors, RxJabberErrors), + HW_STAT(RxRuntErrors, RxRuntErrors), + HW_STAT(RxShortErrors, RxRuntErrors), + HW_STAT(RxSequenceErrors, RxSequenceErrors), + HW_STAT(RxSymbolErrors, RxSymbolErrors), + + /* Tx stats (skip collision stats as we are full-duplex only) */ + HW_STAT(TxOctetsTotalOK, TxOctetsOK), + HW_STAT(TxOctetsBad, TxOctetsBad), + HW_STAT(TxUCPkts, TxUnicastFramesOK), + HW_STAT(TxMCPkts, TxMulticastFramesOK), + HW_STAT(TxBCPkts, TxBroadcastFramesOK), + HW_STAT(TxJumboPkts, TxJumboFramesOK), + HW_STAT(TxPauseFrames, TxPauseFrames), + HW_STAT(TxExcessiveLengthDrop, TxLengthErrors), + HW_STAT(TxUnderrun, TxUnderrun), + HW_STAT(TxCRCErrors, TxFCSErrors) + }, *p = hw_stats; + u64 *stats = (u64 *) &mac->stats; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(hw_stats); i++) { + u32 val; + + t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val); + stats[p->offset] += val; + } } /* No-op interrupt operation as this MAC does not support interrupts */ @@ -273,7 +286,8 @@ static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) static int mac_set_mtu(struct cmac *mac, int mtu) { /* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */ - if (mtu > (MAX_FRAME_SIZE - 14 - 4)) return -EINVAL; + if (mtu > (MAX_FRAME_SIZE - 14 - 4)) + return -EINVAL; t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE), mtu + 14 + 4); return 0; @@ -357,8 +371,8 @@ static void enable_port(struct cmac *mac) val |= (1 << index); t1_tpi_write(adapter, REG_PORT_ENABLE, val); - index <<= 2; - if (is_T2(adapter)) { + index <<= 2; + if (is_T2(adapter)) { /* T204: set the Fifo water level & threshold */ t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740); t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730); @@ -389,6 +403,10 @@ static int mac_disable(struct cmac *mac, int which) return 0; } +#define RMON_UPDATE(mac, name, stat_name) \ + t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \ + (mac)->stats.stat_name += val; + /* * This function is called periodically to accumulate the current values of the * RMON counters into the port statistics. Since the counters are only 32 bits @@ -460,10 +478,12 @@ static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index) struct cmac *mac; u32 val; - if (index > 9) return NULL; + if (index > 9) + return NULL; mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); - if (!mac) return NULL; + if (!mac) + return NULL; mac->ops = &ixf1010_ops; mac->instance = (cmac_instance *)(mac + 1); diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c index 28ac93ff7c4f..5867e3b0a887 100644 --- a/drivers/net/chelsio/mv88e1xxx.c +++ b/drivers/net/chelsio/mv88e1xxx.c @@ -73,9 +73,8 @@ static int mv88e1xxx_interrupt_enable(struct cphy *cphy) t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); elmer |= ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) { - elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; - } + if (is_T2(cphy->adapter)) + elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4; t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); } return 0; @@ -92,9 +91,8 @@ static int mv88e1xxx_interrupt_disable(struct cphy *cphy) t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); elmer &= ~ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) { + if (is_T2(cphy->adapter)) elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4); - } t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); } return 0; @@ -112,9 +110,8 @@ static int mv88e1xxx_interrupt_clear(struct cphy *cphy) if (t1_is_asic(cphy->adapter)) { t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer); elmer |= ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) { + if (is_T2(cphy->adapter)) elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; - } t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer); } return 0; @@ -300,7 +297,7 @@ static int mv88e1xxx_interrupt_handler(struct cphy *cphy) /* * Loop until cause reads zero. Need to handle bouncing interrupts. - */ + */ while (1) { u32 cause; @@ -308,15 +305,16 @@ static int mv88e1xxx_interrupt_handler(struct cphy *cphy) MV88E1XXX_INTERRUPT_STATUS_REGISTER, &cause); cause &= INTR_ENABLE_MASK; - if (!cause) break; + if (!cause) + break; if (cause & MV88E1XXX_INTR_LINK_CHNG) { (void) simple_mdio_read(cphy, MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status); - if (status & MV88E1XXX_INTR_LINK_CHNG) { + if (status & MV88E1XXX_INTR_LINK_CHNG) cphy->state |= PHY_LINK_UP; - } else { + else { cphy->state &= ~PHY_LINK_UP; if (cphy->state & PHY_AUTONEG_EN) cphy->state &= ~PHY_AUTONEG_RDY; @@ -360,7 +358,8 @@ static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr, { struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); - if (!cphy) return NULL; + if (!cphy) + return NULL; cphy_init(cphy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops); @@ -377,11 +376,11 @@ static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr, } (void) mv88e1xxx_downshift_set(cphy, 1); /* Enable downshift */ - /* LED */ + /* LED */ if (is_T2(adapter)) { (void) simple_mdio_write(cphy, MV88E1XXX_LED_CONTROL_REGISTER, 0x1); - } + } return cphy; } diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c index 82fed1dd5005..87dde3e60046 100644 --- a/drivers/net/chelsio/my3126.c +++ b/drivers/net/chelsio/my3126.c @@ -10,25 +10,25 @@ static int my3126_reset(struct cphy *cphy, int wait) * This can be done through registers. It is not required since * a full chip reset is used. */ - return (0); + return 0; } static int my3126_interrupt_enable(struct cphy *cphy) { schedule_delayed_work(&cphy->phy_update, HZ/30); t1_tpi_read(cphy->adapter, A_ELMER0_GPO, &cphy->elmer_gpo); - return (0); + return 0; } static int my3126_interrupt_disable(struct cphy *cphy) { cancel_rearming_delayed_work(&cphy->phy_update); - return (0); + return 0; } static int my3126_interrupt_clear(struct cphy *cphy) { - return (0); + return 0; } #define OFFSET(REG_ADDR) (REG_ADDR << 2) @@ -102,7 +102,7 @@ static void my3216_poll(struct work_struct *work) static int my3126_set_loopback(struct cphy *cphy, int on) { - return (0); + return 0; } /* To check the activity LED */ @@ -146,7 +146,7 @@ static int my3126_get_link_status(struct cphy *cphy, if (fc) *fc = PAUSE_RX | PAUSE_TX; - return (0); + return 0; } static void my3126_destroy(struct cphy *cphy) @@ -177,7 +177,7 @@ static struct cphy *my3126_phy_create(adapter_t *adapter, INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll); cphy->bmsr = 0; - return (cphy); + return cphy; } /* Chip Reset */ @@ -198,7 +198,7 @@ static int my3126_phy_reset(adapter_t * adapter) val |= 0x8000; t1_tpi_write(adapter, A_ELMER0_GPO, val); udelay(100); - return (0); + return 0; } struct gphy t1_my3126_ops = { diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c index 63cabeb98afe..69129edeefd6 100644 --- a/drivers/net/chelsio/pm3393.c +++ b/drivers/net/chelsio/pm3393.c @@ -446,17 +446,51 @@ static void pm3393_rmon_update(struct adapter *adapter, u32 offs, u64 *val, *val += 1ull << 40; } -#define RMON_UPDATE(mac, name, stat_name) \ - pm3393_rmon_update((mac)->adapter, OFFSET(name), \ - &(mac)->stats.stat_name, \ - (ro &((name - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2))) - - static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac, int flag) { - u64 ro; - u32 val0, val1, val2, val3; + static struct { + unsigned int reg; + unsigned int offset; + } hw_stats [] = { + +#define HW_STAT(name, stat_name) \ + { name, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL } + + /* Rx stats */ + HW_STAT(RxOctetsReceivedOK, RxOctetsOK), + HW_STAT(RxUnicastFramesReceivedOK, RxUnicastFramesOK), + HW_STAT(RxMulticastFramesReceivedOK, RxMulticastFramesOK), + HW_STAT(RxBroadcastFramesReceivedOK, RxBroadcastFramesOK), + HW_STAT(RxPAUSEMACCtrlFramesReceived, RxPauseFrames), + HW_STAT(RxFrameCheckSequenceErrors, RxFCSErrors), + HW_STAT(RxFramesLostDueToInternalMACErrors, + RxInternalMACRcvError), + HW_STAT(RxSymbolErrors, RxSymbolErrors), + HW_STAT(RxInRangeLengthErrors, RxInRangeLengthErrors), + HW_STAT(RxFramesTooLongErrors , RxFrameTooLongErrors), + HW_STAT(RxJabbers, RxJabberErrors), + HW_STAT(RxFragments, RxRuntErrors), + HW_STAT(RxUndersizedFrames, RxRuntErrors), + HW_STAT(RxJumboFramesReceivedOK, RxJumboFramesOK), + HW_STAT(RxJumboOctetsReceivedOK, RxJumboOctetsOK), + + /* Tx stats */ + HW_STAT(TxOctetsTransmittedOK, TxOctetsOK), + HW_STAT(TxFramesLostDueToInternalMACTransmissionError, + TxInternalMACXmitError), + HW_STAT(TxTransmitSystemError, TxFCSErrors), + HW_STAT(TxUnicastFramesTransmittedOK, TxUnicastFramesOK), + HW_STAT(TxMulticastFramesTransmittedOK, TxMulticastFramesOK), + HW_STAT(TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK), + HW_STAT(TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames), + HW_STAT(TxJumboFramesReceivedOK, TxJumboFramesOK), + HW_STAT(TxJumboOctetsReceivedOK, TxJumboOctetsOK) + }, *p = hw_stats; + u64 ro; + u32 val0, val1, val2, val3; + u64 *stats = (u64 *) &mac->stats; + unsigned int i; /* Snap the counters */ pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL, @@ -470,35 +504,14 @@ static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac, ro = ((u64)val0 & 0xffff) | (((u64)val1 & 0xffff) << 16) | (((u64)val2 & 0xffff) << 32) | (((u64)val3 & 0xffff) << 48); - /* Rx stats */ - RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK); - RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK); - RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK); - RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK); - RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames); - RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors); - RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors, - RxInternalMACRcvError); - RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors); - RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors); - RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors); - RMON_UPDATE(mac, RxJabbers, RxJabberErrors); - RMON_UPDATE(mac, RxFragments, RxRuntErrors); - RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors); - RMON_UPDATE(mac, RxJumboFramesReceivedOK, RxJumboFramesOK); - RMON_UPDATE(mac, RxJumboOctetsReceivedOK, RxJumboOctetsOK); + for (i = 0; i < ARRAY_SIZE(hw_stats); i++) { + unsigned reg = p->reg - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW; + + pm3393_rmon_update((mac)->adapter, OFFSET(p->reg), + stats + p->offset, ro & (reg >> 2)); + } + - /* Tx stats */ - RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK); - RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError, - TxInternalMACXmitError); - RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors); - RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK); - RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK); - RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK); - RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames); - RMON_UPDATE(mac, TxJumboFramesReceivedOK, TxJumboFramesOK); - RMON_UPDATE(mac, TxJumboOctetsReceivedOK, TxJumboOctetsOK); return &mac->stats; } @@ -534,9 +547,9 @@ static int pm3393_macaddress_set(struct cmac *cmac, u8 ma[6]) /* Store local copy */ memcpy(cmac->instance->mac_addr, ma, 6); - lo = ((u32) ma[1] << 8) | (u32) ma[0]; + lo = ((u32) ma[1] << 8) | (u32) ma[0]; mid = ((u32) ma[3] << 8) | (u32) ma[2]; - hi = ((u32) ma[5] << 8) | (u32) ma[4]; + hi = ((u32) ma[5] << 8) | (u32) ma[4]; /* Disable Rx/Tx MAC before configuring it. */ if (enabled) diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 659cb2252e44..89a682702fa9 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -71,12 +71,9 @@ #define SGE_FREEL_REFILL_THRESH 16 #define SGE_RESPQ_E_N 1024 #define SGE_INTRTIMER_NRES 1000 -#define SGE_RX_COPY_THRES 256 #define SGE_RX_SM_BUF_SIZE 1536 #define SGE_TX_DESC_MAX_PLEN 16384 -# define SGE_RX_DROP_THRES 2 - #define SGE_RESPQ_REPLENISH_THRES (SGE_RESPQ_E_N / 4) /* @@ -85,10 +82,6 @@ */ #define TX_RECLAIM_PERIOD (HZ / 4) -#ifndef NET_IP_ALIGN -# define NET_IP_ALIGN 2 -#endif - #define M_CMD_LEN 0x7fffffff #define V_CMD_LEN(v) (v) #define G_CMD_LEN(v) ((v) & M_CMD_LEN) @@ -195,7 +188,7 @@ struct cmdQ { struct cmdQ_e *entries; /* HW command descriptor Q */ struct cmdQ_ce *centries; /* SW command context descriptor Q */ dma_addr_t dma_addr; /* DMA addr HW command descriptor Q */ - spinlock_t lock; /* Lock to protect cmdQ enqueuing */ + spinlock_t lock; /* Lock to protect cmdQ enqueuing */ }; struct freelQ { @@ -241,9 +234,9 @@ struct sched_port { /* Per T204 device */ struct sched { ktime_t last_updated; /* last time quotas were computed */ - unsigned int max_avail; /* max bits to be sent to any port */ - unsigned int port; /* port index (round robin ports) */ - unsigned int num; /* num skbs in per port queues */ + unsigned int max_avail; /* max bits to be sent to any port */ + unsigned int port; /* port index (round robin ports) */ + unsigned int num; /* num skbs in per port queues */ struct sched_port p[MAX_NPORTS]; struct tasklet_struct sched_tsk;/* tasklet used to run scheduler */ }; @@ -259,10 +252,10 @@ static void restart_sched(unsigned long); * contention. */ struct sge { - struct adapter *adapter; /* adapter backpointer */ + struct adapter *adapter; /* adapter backpointer */ struct net_device *netdev; /* netdevice backpointer */ - struct freelQ freelQ[SGE_FREELQ_N]; /* buffer free lists */ - struct respQ respQ; /* response Q */ + struct freelQ freelQ[SGE_FREELQ_N]; /* buffer free lists */ + struct respQ respQ; /* response Q */ unsigned long stopped_tx_queues; /* bitmap of suspended Tx queues */ unsigned int rx_pkt_pad; /* RX padding for L2 packets */ unsigned int jumbo_fl; /* jumbo freelist Q index */ @@ -460,7 +453,7 @@ static struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb, if (credits < MAX_SKB_FRAGS + 1) goto out; - again: +again: for (i = 0; i < MAX_NPORTS; i++) { s->port = ++s->port & (MAX_NPORTS - 1); skbq = &s->p[s->port].skbq; @@ -483,8 +476,8 @@ static struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb, if (update-- && sched_update_avail(sge)) goto again; - out: - /* If there are more pending skbs, we use the hardware to schedule us +out: + /* If there are more pending skbs, we use the hardware to schedule us * again. */ if (s->num && !skb) { @@ -575,11 +568,10 @@ static int alloc_rx_resources(struct sge *sge, struct sge_params *p) q->size = p->freelQ_size[i]; q->dma_offset = sge->rx_pkt_pad ? 0 : NET_IP_ALIGN; size = sizeof(struct freelQ_e) * q->size; - q->entries = (struct freelQ_e *) - pci_alloc_consistent(pdev, size, &q->dma_addr); + q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr); if (!q->entries) goto err_no_mem; - memset(q->entries, 0, size); + size = sizeof(struct freelQ_ce) * q->size; q->centries = kzalloc(size, GFP_KERNEL); if (!q->centries) @@ -613,11 +605,10 @@ static int alloc_rx_resources(struct sge *sge, struct sge_params *p) sge->respQ.size = SGE_RESPQ_E_N; sge->respQ.credits = 0; size = sizeof(struct respQ_e) * sge->respQ.size; - sge->respQ.entries = (struct respQ_e *) + sge->respQ.entries = pci_alloc_consistent(pdev, size, &sge->respQ.dma_addr); if (!sge->respQ.entries) goto err_no_mem; - memset(sge->respQ.entries, 0, size); return 0; err_no_mem: @@ -637,20 +628,12 @@ static void free_cmdQ_buffers(struct sge *sge, struct cmdQ *q, unsigned int n) q->in_use -= n; ce = &q->centries[cidx]; while (n--) { - if (q->sop) { - if (likely(pci_unmap_len(ce, dma_len))) { - pci_unmap_single(pdev, - pci_unmap_addr(ce, dma_addr), - pci_unmap_len(ce, dma_len), - PCI_DMA_TODEVICE); + if (likely(pci_unmap_len(ce, dma_len))) { + pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr), + pci_unmap_len(ce, dma_len), + PCI_DMA_TODEVICE); + if (q->sop) q->sop = 0; - } - } else { - if (likely(pci_unmap_len(ce, dma_len))) { - pci_unmap_page(pdev, pci_unmap_addr(ce, dma_addr), - pci_unmap_len(ce, dma_len), - PCI_DMA_TODEVICE); - } } if (ce->skb) { dev_kfree_skb_any(ce->skb); @@ -711,11 +694,10 @@ static int alloc_tx_resources(struct sge *sge, struct sge_params *p) q->stop_thres = 0; spin_lock_init(&q->lock); size = sizeof(struct cmdQ_e) * q->size; - q->entries = (struct cmdQ_e *) - pci_alloc_consistent(pdev, size, &q->dma_addr); + q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr); if (!q->entries) goto err_no_mem; - memset(q->entries, 0, size); + size = sizeof(struct cmdQ_ce) * q->size; q->centries = kzalloc(size, GFP_KERNEL); if (!q->centries) @@ -770,7 +752,7 @@ void t1_set_vlan_accel(struct adapter *adapter, int on_off) static void configure_sge(struct sge *sge, struct sge_params *p) { struct adapter *ap = sge->adapter; - + writel(0, ap->regs + A_SG_CONTROL); setup_ring_params(ap, sge->cmdQ[0].dma_addr, sge->cmdQ[0].size, A_SG_CMD0BASELWR, A_SG_CMD0BASEUPR, A_SG_CMD0SIZE); @@ -850,7 +832,6 @@ static void refill_free_list(struct sge *sge, struct freelQ *q) struct freelQ_e *e = &q->entries[q->pidx]; unsigned int dma_len = q->rx_buffer_size - q->dma_offset; - while (q->credits < q->size) { struct sk_buff *skb; dma_addr_t mapping; @@ -862,6 +843,8 @@ static void refill_free_list(struct sge *sge, struct freelQ *q) skb_reserve(skb, q->dma_offset); mapping = pci_map_single(pdev, skb->data, dma_len, PCI_DMA_FROMDEVICE); + skb_reserve(skb, sge->rx_pkt_pad); + ce->skb = skb; pci_unmap_addr_set(ce, dma_addr, mapping); pci_unmap_len_set(ce, dma_len, dma_len); @@ -881,7 +864,6 @@ static void refill_free_list(struct sge *sge, struct freelQ *q) } q->credits++; } - } /* @@ -1041,6 +1023,10 @@ static void recycle_fl_buf(struct freelQ *fl, int idx) } } +static int copybreak __read_mostly = 256; +module_param(copybreak, int, 0); +MODULE_PARM_DESC(copybreak, "Receive copy threshold"); + /** * get_packet - return the next ingress packet buffer * @pdev: the PCI device that received the packet @@ -1060,45 +1046,42 @@ static void recycle_fl_buf(struct freelQ *fl, int idx) * be copied but there is no memory for the copy. */ static inline struct sk_buff *get_packet(struct pci_dev *pdev, - struct freelQ *fl, unsigned int len, - int dma_pad, int skb_pad, - unsigned int copy_thres, - unsigned int drop_thres) + struct freelQ *fl, unsigned int len) { struct sk_buff *skb; - struct freelQ_ce *ce = &fl->centries[fl->cidx]; + const struct freelQ_ce *ce = &fl->centries[fl->cidx]; - if (len < copy_thres) { - skb = alloc_skb(len + skb_pad, GFP_ATOMIC); - if (likely(skb != NULL)) { - skb_reserve(skb, skb_pad); - skb_put(skb, len); - pci_dma_sync_single_for_cpu(pdev, - pci_unmap_addr(ce, dma_addr), - pci_unmap_len(ce, dma_len), - PCI_DMA_FROMDEVICE); - memcpy(skb->data, ce->skb->data + dma_pad, len); - pci_dma_sync_single_for_device(pdev, - pci_unmap_addr(ce, dma_addr), - pci_unmap_len(ce, dma_len), - PCI_DMA_FROMDEVICE); - } else if (!drop_thres) + if (len < copybreak) { + skb = alloc_skb(len + 2, GFP_ATOMIC); + if (!skb) goto use_orig_buf; + skb_reserve(skb, 2); /* align IP header */ + skb_put(skb, len); + pci_dma_sync_single_for_cpu(pdev, + pci_unmap_addr(ce, dma_addr), + pci_unmap_len(ce, dma_len), + PCI_DMA_FROMDEVICE); + memcpy(skb->data, ce->skb->data, len); + pci_dma_sync_single_for_device(pdev, + pci_unmap_addr(ce, dma_addr), + pci_unmap_len(ce, dma_len), + PCI_DMA_FROMDEVICE); recycle_fl_buf(fl, fl->cidx); return skb; } - if (fl->credits < drop_thres) { +use_orig_buf: + if (fl->credits < 2) { recycle_fl_buf(fl, fl->cidx); return NULL; } -use_orig_buf: pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr), pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE); skb = ce->skb; - skb_reserve(skb, dma_pad); + prefetch(skb->data); + skb_put(skb, len); return skb; } @@ -1137,6 +1120,7 @@ static void unexpected_offload(struct adapter *adapter, struct freelQ *fl) static inline unsigned int compute_large_page_tx_descs(struct sk_buff *skb) { unsigned int count = 0; + if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) { unsigned int nfrags = skb_shinfo(skb)->nr_frags; unsigned int i, len = skb->len - skb->data_len; @@ -1343,7 +1327,7 @@ static void restart_sched(unsigned long arg) while ((skb = sched_skb(sge, NULL, credits)) != NULL) { unsigned int genbit, pidx, count; count = 1 + skb_shinfo(skb)->nr_frags; - count += compute_large_page_tx_descs(skb); + count += compute_large_page_tx_descs(skb); q->in_use += count; genbit = q->genbit; pidx = q->pidx; @@ -1375,27 +1359,25 @@ static void restart_sched(unsigned long arg) * * Process an ingress ethernet pakcet and deliver it to the stack. */ -static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) +static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) { struct sk_buff *skb; - struct cpl_rx_pkt *p; + const struct cpl_rx_pkt *p; struct adapter *adapter = sge->adapter; struct sge_port_stats *st; - skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad, - sge->rx_pkt_pad, 2, SGE_RX_COPY_THRES, - SGE_RX_DROP_THRES); + skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad); if (unlikely(!skb)) { sge->stats.rx_drops++; - return 0; + return; } - p = (struct cpl_rx_pkt *)skb->data; - skb_pull(skb, sizeof(*p)); + p = (const struct cpl_rx_pkt *) skb->data; if (p->iff >= adapter->params.nports) { kfree_skb(skb); - return 0; + return; } + __skb_pull(skb, sizeof(*p)); skb->dev = adapter->port[p->iff].dev; skb->dev->last_rx = jiffies; @@ -1427,7 +1409,6 @@ static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) netif_rx(skb); #endif } - return 0; } /* @@ -1448,29 +1429,28 @@ static inline int enough_free_Tx_descs(const struct cmdQ *q) static void restart_tx_queues(struct sge *sge) { struct adapter *adap = sge->adapter; + int i; - if (enough_free_Tx_descs(&sge->cmdQ[0])) { - int i; + if (!enough_free_Tx_descs(&sge->cmdQ[0])) + return; - for_each_port(adap, i) { - struct net_device *nd = adap->port[i].dev; + for_each_port(adap, i) { + struct net_device *nd = adap->port[i].dev; - if (test_and_clear_bit(nd->if_port, - &sge->stopped_tx_queues) && - netif_running(nd)) { - sge->stats.cmdQ_restarted[2]++; - netif_wake_queue(nd); - } + if (test_and_clear_bit(nd->if_port, &sge->stopped_tx_queues) && + netif_running(nd)) { + sge->stats.cmdQ_restarted[2]++; + netif_wake_queue(nd); } } } /* - * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0 + * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0 * information. */ -static unsigned int update_tx_info(struct adapter *adapter, - unsigned int flags, +static unsigned int update_tx_info(struct adapter *adapter, + unsigned int flags, unsigned int pr0) { struct sge *sge = adapter->sge; @@ -1510,29 +1490,30 @@ static int process_responses(struct adapter *adapter, int budget) struct sge *sge = adapter->sge; struct respQ *q = &sge->respQ; struct respQ_e *e = &q->entries[q->cidx]; - int budget_left = budget; + int done = 0; unsigned int flags = 0; unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; - - while (likely(budget_left && e->GenerationBit == q->genbit)) { + while (done < budget && e->GenerationBit == q->genbit) { flags |= e->Qsleeping; - + cmdq_processed[0] += e->Cmdq0CreditReturn; cmdq_processed[1] += e->Cmdq1CreditReturn; - + /* We batch updates to the TX side to avoid cacheline * ping-pong of TX state information on MP where the sender * might run on a different CPU than this function... */ - if (unlikely(flags & F_CMDQ0_ENABLE || cmdq_processed[0] > 64)) { + if (unlikely((flags & F_CMDQ0_ENABLE) || cmdq_processed[0] > 64)) { flags = update_tx_info(adapter, flags, cmdq_processed[0]); cmdq_processed[0] = 0; } + if (unlikely(cmdq_processed[1] > 16)) { sge->cmdQ[1].processed += cmdq_processed[1]; cmdq_processed[1] = 0; } + if (likely(e->DataValid)) { struct freelQ *fl = &sge->freelQ[e->FreelistQid]; @@ -1542,12 +1523,16 @@ static int process_responses(struct adapter *adapter, int budget) else sge_rx(sge, fl, e->BufferLength); + ++done; + /* * Note: this depends on each packet consuming a * single free-list buffer; cf. the BUG above. */ if (++fl->cidx == fl->size) fl->cidx = 0; + prefetch(fl->centries[fl->cidx].skb); + if (unlikely(--fl->credits < fl->size - SGE_FREEL_REFILL_THRESH)) refill_free_list(sge, fl); @@ -1566,14 +1551,20 @@ static int process_responses(struct adapter *adapter, int budget) writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT); q->credits = 0; } - --budget_left; } - flags = update_tx_info(adapter, flags, cmdq_processed[0]); + flags = update_tx_info(adapter, flags, cmdq_processed[0]); sge->cmdQ[1].processed += cmdq_processed[1]; - budget -= budget_left; - return budget; + return done; +} + +static inline int responses_pending(const struct adapter *adapter) +{ + const struct respQ *Q = &adapter->sge->respQ; + const struct respQ_e *e = &Q->entries[Q->cidx]; + + return (e->GenerationBit == Q->genbit); } #ifdef CONFIG_CHELSIO_T1_NAPI @@ -1585,19 +1576,25 @@ static int process_responses(struct adapter *adapter, int budget) * which the caller must ensure is a valid pure response. Returns 1 if it * encounters a valid data-carrying response, 0 otherwise. */ -static int process_pure_responses(struct adapter *adapter, struct respQ_e *e) +static int process_pure_responses(struct adapter *adapter) { struct sge *sge = adapter->sge; struct respQ *q = &sge->respQ; + struct respQ_e *e = &q->entries[q->cidx]; + const struct freelQ *fl = &sge->freelQ[e->FreelistQid]; unsigned int flags = 0; unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; + prefetch(fl->centries[fl->cidx].skb); + if (e->DataValid) + return 1; + do { flags |= e->Qsleeping; cmdq_processed[0] += e->Cmdq0CreditReturn; cmdq_processed[1] += e->Cmdq1CreditReturn; - + e++; if (unlikely(++q->cidx == q->size)) { q->cidx = 0; @@ -1613,7 +1610,7 @@ static int process_pure_responses(struct adapter *adapter, struct respQ_e *e) sge->stats.pure_rsps++; } while (e->GenerationBit == q->genbit && !e->DataValid); - flags = update_tx_info(adapter, flags, cmdq_processed[0]); + flags = update_tx_info(adapter, flags, cmdq_processed[0]); sge->cmdQ[1].processed += cmdq_processed[1]; return e->GenerationBit == q->genbit; @@ -1627,23 +1624,20 @@ static int process_pure_responses(struct adapter *adapter, struct respQ_e *e) int t1_poll(struct net_device *dev, int *budget) { struct adapter *adapter = dev->priv; - int effective_budget = min(*budget, dev->quota); - int work_done = process_responses(adapter, effective_budget); + int work_done; + work_done = process_responses(adapter, min(*budget, dev->quota)); *budget -= work_done; dev->quota -= work_done; - if (work_done >= effective_budget) + if (unlikely(responses_pending(adapter))) return 1; - spin_lock_irq(&adapter->async_lock); - __netif_rx_complete(dev); + netif_rx_complete(dev); writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); - writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA, - adapter->regs + A_PL_ENABLE); - spin_unlock_irq(&adapter->async_lock); return 0; + } /* @@ -1652,44 +1646,33 @@ int t1_poll(struct net_device *dev, int *budget) irqreturn_t t1_interrupt(int irq, void *data) { struct adapter *adapter = data; - struct net_device *dev = adapter->sge->netdev; struct sge *sge = adapter->sge; - u32 cause; - int handled = 0; + int handled; - cause = readl(adapter->regs + A_PL_CAUSE); - if (cause == 0 || cause == ~0) - return IRQ_NONE; + if (likely(responses_pending(adapter))) { + struct net_device *dev = sge->netdev; + + writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); + + if (__netif_rx_schedule_prep(dev)) { + if (process_pure_responses(adapter)) + __netif_rx_schedule(dev); + else { + /* no data, no NAPI needed */ + writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); + netif_poll_enable(dev); /* undo schedule_prep */ + } + } + return IRQ_HANDLED; + } spin_lock(&adapter->async_lock); - if (cause & F_PL_INTR_SGE_DATA) { - struct respQ *q = &adapter->sge->respQ; - struct respQ_e *e = &q->entries[q->cidx]; - - handled = 1; - writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); - - if (e->GenerationBit == q->genbit && - __netif_rx_schedule_prep(dev)) { - if (e->DataValid || process_pure_responses(adapter, e)) { - /* mask off data IRQ */ - writel(adapter->slow_intr_mask, - adapter->regs + A_PL_ENABLE); - __netif_rx_schedule(sge->netdev); - goto unlock; - } - /* no data, no NAPI needed */ - netif_poll_enable(dev); - - } - writel(q->cidx, adapter->regs + A_SG_SLEEPING); - } else - handled = t1_slow_intr_handler(adapter); + handled = t1_slow_intr_handler(adapter); + spin_unlock(&adapter->async_lock); if (!handled) sge->stats.unhandled_irqs++; -unlock: - spin_unlock(&adapter->async_lock); + return IRQ_RETVAL(handled != 0); } @@ -1712,17 +1695,13 @@ unlock: irqreturn_t t1_interrupt(int irq, void *cookie) { int work_done; - struct respQ_e *e; struct adapter *adapter = cookie; - struct respQ *Q = &adapter->sge->respQ; spin_lock(&adapter->async_lock); - e = &Q->entries[Q->cidx]; - prefetch(e); writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); - if (likely(e->GenerationBit == Q->genbit)) + if (likely(responses_pending(adapter))) work_done = process_responses(adapter, -1); else work_done = t1_slow_intr_handler(adapter); @@ -1796,7 +1775,7 @@ static int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter, * through the scheduler. */ if (sge->tx_sched && !qid && skb->dev) { - use_sched: +use_sched: use_sched_skb = 1; /* Note that the scheduler might return a different skb than * the one passed in. @@ -1900,7 +1879,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) cpl = (struct cpl_tx_pkt *)hdr; } else { /* - * Packets shorter than ETH_HLEN can break the MAC, drop them + * Packets shorter than ETH_HLEN can break the MAC, drop them * early. Also, we may get oversized packets because some * parts of the kernel don't handle our unusual hard_header_len * right, drop those too. @@ -1984,9 +1963,9 @@ send: * then silently discard to avoid leak. */ if (unlikely(ret != NETDEV_TX_OK && skb != orig_skb)) { - dev_kfree_skb_any(skb); + dev_kfree_skb_any(skb); ret = NETDEV_TX_OK; - } + } return ret; } @@ -2099,31 +2078,35 @@ static void espibug_workaround_t204(unsigned long data) if (adapter->open_device_map & PORT_MASK) { int i; - if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0) { - return; - } - for (i = 0; i < nports; i++) { - struct sk_buff *skb = sge->espibug_skb[i]; - if ( (netif_running(adapter->port[i].dev)) && - !(netif_queue_stopped(adapter->port[i].dev)) && - (seop[i] && ((seop[i] & 0xfff) == 0)) && - skb ) { - if (!skb->cb[0]) { - u8 ch_mac_addr[ETH_ALEN] = - {0x0, 0x7, 0x43, 0x0, 0x0, 0x0}; - memcpy(skb->data + sizeof(struct cpl_tx_pkt), - ch_mac_addr, ETH_ALEN); - memcpy(skb->data + skb->len - 10, - ch_mac_addr, ETH_ALEN); - skb->cb[0] = 0xff; - } - /* bump the reference count to avoid freeing of - * the skb once the DMA has completed. - */ - skb = skb_get(skb); - t1_sge_tx(skb, adapter, 0, adapter->port[i].dev); + if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0) + return; + + for (i = 0; i < nports; i++) { + struct sk_buff *skb = sge->espibug_skb[i]; + + if (!netif_running(adapter->port[i].dev) || + netif_queue_stopped(adapter->port[i].dev) || + !seop[i] || ((seop[i] & 0xfff) != 0) || !skb) + continue; + + if (!skb->cb[0]) { + u8 ch_mac_addr[ETH_ALEN] = { + 0x0, 0x7, 0x43, 0x0, 0x0, 0x0 + }; + + memcpy(skb->data + sizeof(struct cpl_tx_pkt), + ch_mac_addr, ETH_ALEN); + memcpy(skb->data + skb->len - 10, + ch_mac_addr, ETH_ALEN); + skb->cb[0] = 0xff; } + + /* bump the reference count to avoid freeing of + * the skb once the DMA has completed. + */ + skb = skb_get(skb); + t1_sge_tx(skb, adapter, 0, adapter->port[i].dev); } } mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout); @@ -2192,9 +2175,8 @@ struct sge * __devinit t1_sge_create(struct adapter *adapter, if (adapter->params.nports > 1) { tx_sched_init(sge); sge->espibug_timer.function = espibug_workaround_t204; - } else { + } else sge->espibug_timer.function = espibug_workaround; - } sge->espibug_timer.data = (unsigned long)sge->adapter; sge->espibug_timeout = 1; @@ -2202,7 +2184,7 @@ struct sge * __devinit t1_sge_create(struct adapter *adapter, if (adapter->params.nports > 1) sge->espibug_timeout = HZ/100; } - + p->cmdQ_size[0] = SGE_CMDQ0_E_N; p->cmdQ_size[1] = SGE_CMDQ1_E_N; diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index 22ed9a383c08..c2522cdfab37 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c @@ -223,13 +223,13 @@ static int fpga_slow_intr(adapter_t *adapter) t1_sge_intr_error_handler(adapter->sge); if (cause & FPGA_PCIX_INTERRUPT_GMAC) - fpga_phy_intr_handler(adapter); + fpga_phy_intr_handler(adapter); if (cause & FPGA_PCIX_INTERRUPT_TP) { - /* + /* * FPGA doesn't support MC4 interrupts and it requires * this odd layer of indirection for MC5. - */ + */ u32 tp_cause = readl(adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE); /* Clear TP interrupt */ @@ -262,8 +262,7 @@ static int mi1_wait_until_ready(adapter_t *adapter, int mi1_reg) udelay(10); } while (busy && --attempts); if (busy) - CH_ALERT("%s: MDIO operation timed out\n", - adapter->name); + CH_ALERT("%s: MDIO operation timed out\n", adapter->name); return busy; } @@ -605,22 +604,23 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter) switch (board_info(adapter)->board) { #ifdef CONFIG_CHELSIO_T1_1G - case CHBT_BOARD_CHT204: - case CHBT_BOARD_CHT204E: - case CHBT_BOARD_CHN204: - case CHBT_BOARD_CHT204V: { - int i, port_bit; + case CHBT_BOARD_CHT204: + case CHBT_BOARD_CHT204E: + case CHBT_BOARD_CHN204: + case CHBT_BOARD_CHT204V: { + int i, port_bit; for_each_port(adapter, i) { port_bit = i + 1; - if (!(cause & (1 << port_bit))) continue; + if (!(cause & (1 << port_bit))) + continue; - phy = adapter->port[i].phy; + phy = adapter->port[i].phy; phy_cause = phy->ops->interrupt_handler(phy); if (phy_cause & cphy_cause_link_change) t1_link_changed(adapter, i); } - break; - } + break; + } case CHBT_BOARD_CHT101: if (cause & ELMER0_GP_BIT1) { /* Marvell 88E1111 interrupt */ phy = adapter->port[0].phy; @@ -631,13 +631,13 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter) break; case CHBT_BOARD_7500: { int p; - /* + /* * Elmer0's interrupt cause isn't useful here because there is * only one bit that can be set for all 4 ports. This means * we are forced to check every PHY's interrupt status * register to see who initiated the interrupt. - */ - for_each_port(adapter, p) { + */ + for_each_port(adapter, p) { phy = adapter->port[p].phy; phy_cause = phy->ops->interrupt_handler(phy); if (phy_cause & cphy_cause_link_change) @@ -658,7 +658,7 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter) break; case CHBT_BOARD_8000: case CHBT_BOARD_CHT110: - CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n", + CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n", cause); if (cause & ELMER0_GP_BIT1) { /* PMC3393 INTB */ struct cmac *mac = adapter->port[0].mac; @@ -670,9 +670,9 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter) t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect); - CH_MSG(adapter, INFO, LINK, "XPAK %s\n", + CH_MSG(adapter, INFO, LINK, "XPAK %s\n", mod_detect ? "removed" : "inserted"); - } + } break; #ifdef CONFIG_CHELSIO_T1_COUGAR case CHBT_BOARD_COUGAR: @@ -688,7 +688,8 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter) for_each_port(adapter, i) { port_bit = i ? i + 1 : 0; - if (!(cause & (1 << port_bit))) continue; + if (!(cause & (1 << port_bit))) + continue; phy = adapter->port[i].phy; phy_cause = phy->ops->interrupt_handler(phy); @@ -755,7 +756,7 @@ void t1_interrupts_disable(adapter_t* adapter) /* Disable PCIX & external chip interrupts. */ if (t1_is_asic(adapter)) - writel(0, adapter->regs + A_PL_ENABLE); + writel(0, adapter->regs + A_PL_ENABLE); /* PCI-X interrupts */ pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, 0); @@ -830,11 +831,11 @@ int t1_slow_intr_handler(adapter_t *adapter) /* Power sequencing is a work-around for Intel's XPAKs. */ static void power_sequence_xpak(adapter_t* adapter) { - u32 mod_detect; - u32 gpo; + u32 mod_detect; + u32 gpo; - /* Check for XPAK */ - t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect); + /* Check for XPAK */ + t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect); if (!(ELMER0_GP_BIT5 & mod_detect)) { /* XPAK is present */ t1_tpi_read(adapter, A_ELMER0_GPO, &gpo); @@ -877,31 +878,31 @@ static int board_init(adapter_t *adapter, const struct board_info *bi) case CHBT_BOARD_N210: case CHBT_BOARD_CHT210: case CHBT_BOARD_COUGAR: - t1_tpi_par(adapter, 0xf); - t1_tpi_write(adapter, A_ELMER0_GPO, 0x800); + t1_tpi_par(adapter, 0xf); + t1_tpi_write(adapter, A_ELMER0_GPO, 0x800); break; case CHBT_BOARD_CHT110: - t1_tpi_par(adapter, 0xf); - t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800); + t1_tpi_par(adapter, 0xf); + t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800); - /* TBD XXX Might not need. This fixes a problem - * described in the Intel SR XPAK errata. - */ - power_sequence_xpak(adapter); + /* TBD XXX Might not need. This fixes a problem + * described in the Intel SR XPAK errata. + */ + power_sequence_xpak(adapter); break; #ifdef CONFIG_CHELSIO_T1_1G - case CHBT_BOARD_CHT204E: - /* add config space write here */ + case CHBT_BOARD_CHT204E: + /* add config space write here */ case CHBT_BOARD_CHT204: case CHBT_BOARD_CHT204V: case CHBT_BOARD_CHN204: - t1_tpi_par(adapter, 0xf); - t1_tpi_write(adapter, A_ELMER0_GPO, 0x804); - break; + t1_tpi_par(adapter, 0xf); + t1_tpi_write(adapter, A_ELMER0_GPO, 0x804); + break; case CHBT_BOARD_CHT101: case CHBT_BOARD_7500: - t1_tpi_par(adapter, 0xf); - t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804); + t1_tpi_par(adapter, 0xf); + t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804); break; #endif } @@ -941,7 +942,7 @@ int t1_init_hw_modules(adapter_t *adapter) goto out_err; err = 0; - out_err: +out_err: return err; } @@ -983,7 +984,7 @@ void t1_free_sw_modules(adapter_t *adapter) if (adapter->espi) t1_espi_destroy(adapter->espi); #ifdef CONFIG_CHELSIO_T1_COUGAR - if (adapter->cspi) + if (adapter->cspi) t1_cspi_destroy(adapter->cspi); #endif } @@ -1010,7 +1011,7 @@ static void __devinit init_link_config(struct link_config *lc, CH_ERR("%s: CSPI initialization failed\n", adapter->name); goto error; - } + } #endif /* diff --git a/drivers/net/chelsio/tp.c b/drivers/net/chelsio/tp.c index 0ca0b6e19e43..6222d585e447 100644 --- a/drivers/net/chelsio/tp.c +++ b/drivers/net/chelsio/tp.c @@ -17,39 +17,36 @@ struct petp { static void tp_init(adapter_t * ap, const struct tp_params *p, unsigned int tp_clk) { - if (t1_is_asic(ap)) { - u32 val; + u32 val; - val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM | - F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET; - if (!p->pm_size) - val |= F_OFFLOAD_DISABLE; - else - val |= F_TP_IN_ESPI_CHECK_IP_CSUM | - F_TP_IN_ESPI_CHECK_TCP_CSUM; - writel(val, ap->regs + A_TP_IN_CONFIG); - writel(F_TP_OUT_CSPI_CPL | - F_TP_OUT_ESPI_ETHERNET | - F_TP_OUT_ESPI_GENERATE_IP_CSUM | - F_TP_OUT_ESPI_GENERATE_TCP_CSUM, - ap->regs + A_TP_OUT_CONFIG); - writel(V_IP_TTL(64) | - F_PATH_MTU /* IP DF bit */ | - V_5TUPLE_LOOKUP(p->use_5tuple_mode) | - V_SYN_COOKIE_PARAMETER(29), - ap->regs + A_TP_GLOBAL_CONFIG); - /* - * Enable pause frame deadlock prevention. - */ - if (is_T2(ap) && ap->params.nports > 1) { - u32 drop_ticks = DROP_MSEC * (tp_clk / 1000); + if (!t1_is_asic(ap)) + return; - writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR | - V_DROP_TICKS_CNT(drop_ticks) | - V_NUM_PKTS_DROPPED(DROP_PKTS_CNT), - ap->regs + A_TP_TX_DROP_CONFIG); - } + val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM | + F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET; + if (!p->pm_size) + val |= F_OFFLOAD_DISABLE; + else + val |= F_TP_IN_ESPI_CHECK_IP_CSUM | F_TP_IN_ESPI_CHECK_TCP_CSUM; + writel(val, ap->regs + A_TP_IN_CONFIG); + writel(F_TP_OUT_CSPI_CPL | + F_TP_OUT_ESPI_ETHERNET | + F_TP_OUT_ESPI_GENERATE_IP_CSUM | + F_TP_OUT_ESPI_GENERATE_TCP_CSUM, ap->regs + A_TP_OUT_CONFIG); + writel(V_IP_TTL(64) | + F_PATH_MTU /* IP DF bit */ | + V_5TUPLE_LOOKUP(p->use_5tuple_mode) | + V_SYN_COOKIE_PARAMETER(29), ap->regs + A_TP_GLOBAL_CONFIG); + /* + * Enable pause frame deadlock prevention. + */ + if (is_T2(ap) && ap->params.nports > 1) { + u32 drop_ticks = DROP_MSEC * (tp_clk / 1000); + writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR | + V_DROP_TICKS_CNT(drop_ticks) | + V_NUM_PKTS_DROPPED(DROP_PKTS_CNT), + ap->regs + A_TP_TX_DROP_CONFIG); } } @@ -61,6 +58,7 @@ void t1_tp_destroy(struct petp *tp) struct petp *__devinit t1_tp_create(adapter_t * adapter, struct tp_params *p) { struct petp *tp = kzalloc(sizeof(*tp), GFP_KERNEL); + if (!tp) return NULL; diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c index 85dc3b1dc309..534ffa0f616e 100644 --- a/drivers/net/chelsio/vsc7326.c +++ b/drivers/net/chelsio/vsc7326.c @@ -226,22 +226,21 @@ static void run_table(adapter_t *adapter, struct init_table *ib, int len) if (ib[i].addr == INITBLOCK_SLEEP) { udelay( ib[i].data ); CH_ERR("sleep %d us\n",ib[i].data); - } else { + } else vsc_write( adapter, ib[i].addr, ib[i].data ); - } } } static int bist_rd(adapter_t *adapter, int moduleid, int address) { - int data=0; - u32 result=0; + int data = 0; + u32 result = 0; - if( (address != 0x0) && - (address != 0x1) && - (address != 0x2) && - (address != 0xd) && - (address != 0xe)) + if ((address != 0x0) && + (address != 0x1) && + (address != 0x2) && + (address != 0xd) && + (address != 0xe)) CH_ERR("No bist address: 0x%x\n", address); data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) | @@ -251,27 +250,27 @@ static int bist_rd(adapter_t *adapter, int moduleid, int address) udelay(10); vsc_read(adapter, REG_RAM_BIST_RESULT, &result); - if((result & (1<<9)) != 0x0) + if ((result & (1 << 9)) != 0x0) CH_ERR("Still in bist read: 0x%x\n", result); - else if((result & (1<<8)) != 0x0) + else if ((result & (1 << 8)) != 0x0) CH_ERR("bist read error: 0x%x\n", result); - return(result & 0xff); + return (result & 0xff); } static int bist_wr(adapter_t *adapter, int moduleid, int address, int value) { - int data=0; - u32 result=0; + int data = 0; + u32 result = 0; - if( (address != 0x0) && - (address != 0x1) && - (address != 0x2) && - (address != 0xd) && - (address != 0xe)) + if ((address != 0x0) && + (address != 0x1) && + (address != 0x2) && + (address != 0xd) && + (address != 0xe)) CH_ERR("No bist address: 0x%x\n", address); - if( value>255 ) + if (value > 255) CH_ERR("Suspicious write out of range value: 0x%x\n", value); data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) | @@ -281,12 +280,12 @@ static int bist_wr(adapter_t *adapter, int moduleid, int address, int value) udelay(5); vsc_read(adapter, REG_RAM_BIST_CMD, &result); - if((result & (1<<27)) != 0x0) + if ((result & (1 << 27)) != 0x0) CH_ERR("Still in bist write: 0x%x\n", result); - else if((result & (1<<26)) != 0x0) + else if ((result & (1 << 26)) != 0x0) CH_ERR("bist write error: 0x%x\n", result); - return(0); + return 0; } static int run_bist(adapter_t *adapter, int moduleid) @@ -295,7 +294,7 @@ static int run_bist(adapter_t *adapter, int moduleid) (void) bist_wr(adapter,moduleid, 0x00, 0x02); (void) bist_wr(adapter,moduleid, 0x01, 0x01); - return(0); + return 0; } static int check_bist(adapter_t *adapter, int moduleid) @@ -309,27 +308,26 @@ static int check_bist(adapter_t *adapter, int moduleid) if ((result & 3) != 0x3) CH_ERR("Result: 0x%x BIST error in ram %d, column: 0x%04x\n", result, moduleid, column); - return(0); + return 0; } static int enable_mem(adapter_t *adapter, int moduleid) { /*enable mem*/ (void) bist_wr(adapter,moduleid, 0x00, 0x00); - return(0); + return 0; } static int run_bist_all(adapter_t *adapter) { - int port=0; - u32 val=0; + int port = 0; + u32 val = 0; vsc_write(adapter, REG_MEM_BIST, 0x5); vsc_read(adapter, REG_MEM_BIST, &val); - for(port=0; port<12; port++){ + for (port = 0; port < 12; port++) vsc_write(adapter, REG_DEV_SETUP(port), 0x0); - } udelay(300); vsc_write(adapter, REG_SPI4_MISC, 0x00040409); @@ -352,13 +350,13 @@ static int run_bist_all(adapter_t *adapter) udelay(300); vsc_write(adapter, REG_SPI4_MISC, 0x60040400); udelay(300); - for(port=0; port<12; port++){ + for (port = 0; port < 12; port++) vsc_write(adapter, REG_DEV_SETUP(port), 0x1); - } + udelay(300); vsc_write(adapter, REG_MEM_BIST, 0x0); mdelay(10); - return(0); + return 0; } static int mac_intr_handler(struct cmac *mac) @@ -591,40 +589,46 @@ static void rmon_update(struct cmac *mac, unsigned int addr, u64 *stat) static void port_stats_update(struct cmac *mac) { - int port = mac->instance->index; + struct { + unsigned int reg; + unsigned int offset; + } hw_stats[] = { - /* Rx stats */ +#define HW_STAT(reg, stat_name) \ + { reg, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL } + + /* Rx stats */ + HW_STAT(RxUnicast, RxUnicastFramesOK), + HW_STAT(RxMulticast, RxMulticastFramesOK), + HW_STAT(RxBroadcast, RxBroadcastFramesOK), + HW_STAT(Crc, RxFCSErrors), + HW_STAT(RxAlignment, RxAlignErrors), + HW_STAT(RxOversize, RxFrameTooLongErrors), + HW_STAT(RxPause, RxPauseFrames), + HW_STAT(RxJabbers, RxJabberErrors), + HW_STAT(RxFragments, RxRuntErrors), + HW_STAT(RxUndersize, RxRuntErrors), + HW_STAT(RxSymbolCarrier, RxSymbolErrors), + HW_STAT(RxSize1519ToMax, RxJumboFramesOK), + + /* Tx stats (skip collision stats as we are full-duplex only) */ + HW_STAT(TxUnicast, TxUnicastFramesOK), + HW_STAT(TxMulticast, TxMulticastFramesOK), + HW_STAT(TxBroadcast, TxBroadcastFramesOK), + HW_STAT(TxPause, TxPauseFrames), + HW_STAT(TxUnderrun, TxUnderrun), + HW_STAT(TxSize1519ToMax, TxJumboFramesOK), + }, *p = hw_stats; + unsigned int port = mac->instance->index; + u64 *stats = (u64 *)&mac->stats; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(hw_stats); i++) + rmon_update(mac, CRA(0x4, port, p->reg), stats + p->offset); + + rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK); rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK); rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad); - rmon_update(mac, REG_RX_UNICAST(port), &mac->stats.RxUnicastFramesOK); - rmon_update(mac, REG_RX_MULTICAST(port), - &mac->stats.RxMulticastFramesOK); - rmon_update(mac, REG_RX_BROADCAST(port), - &mac->stats.RxBroadcastFramesOK); - rmon_update(mac, REG_CRC(port), &mac->stats.RxFCSErrors); - rmon_update(mac, REG_RX_ALIGNMENT(port), &mac->stats.RxAlignErrors); - rmon_update(mac, REG_RX_OVERSIZE(port), - &mac->stats.RxFrameTooLongErrors); - rmon_update(mac, REG_RX_PAUSE(port), &mac->stats.RxPauseFrames); - rmon_update(mac, REG_RX_JABBERS(port), &mac->stats.RxJabberErrors); - rmon_update(mac, REG_RX_FRAGMENTS(port), &mac->stats.RxRuntErrors); - rmon_update(mac, REG_RX_UNDERSIZE(port), &mac->stats.RxRuntErrors); - rmon_update(mac, REG_RX_SYMBOL_CARRIER(port), - &mac->stats.RxSymbolErrors); - rmon_update(mac, REG_RX_SIZE_1519_TO_MAX(port), - &mac->stats.RxJumboFramesOK); - - /* Tx stats (skip collision stats as we are full-duplex only) */ - rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK); - rmon_update(mac, REG_TX_UNICAST(port), &mac->stats.TxUnicastFramesOK); - rmon_update(mac, REG_TX_MULTICAST(port), - &mac->stats.TxMulticastFramesOK); - rmon_update(mac, REG_TX_BROADCAST(port), - &mac->stats.TxBroadcastFramesOK); - rmon_update(mac, REG_TX_PAUSE(port), &mac->stats.TxPauseFrames); - rmon_update(mac, REG_TX_UNDERRUN(port), &mac->stats.TxUnderrun); - rmon_update(mac, REG_TX_SIZE_1519_TO_MAX(port), - &mac->stats.TxJumboFramesOK); } /* @@ -686,7 +690,8 @@ static struct cmac *vsc7326_mac_create(adapter_t *adapter, int index) int i; mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); - if (!mac) return NULL; + if (!mac) + return NULL; mac->ops = &vsc7326_ops; mac->instance = (cmac_instance *)(mac + 1); diff --git a/drivers/net/chelsio/vsc7326_reg.h b/drivers/net/chelsio/vsc7326_reg.h index 491bcf75c4fb..479edbcabe68 100644 --- a/drivers/net/chelsio/vsc7326_reg.h +++ b/drivers/net/chelsio/vsc7326_reg.h @@ -192,73 +192,84 @@ #define REG_HDX(pn) CRA(0x1,pn,0x19) /* Half-duplex config */ /* Statistics */ +/* CRA(0x4,pn,reg) */ +/* reg below */ /* pn = port number, 0-a, a = 10GbE */ -#define REG_RX_IN_BYTES(pn) CRA(0x4,pn,0x00) /* # Rx in octets */ -#define REG_RX_SYMBOL_CARRIER(pn) CRA(0x4,pn,0x01) /* Frames w/ symbol errors */ -#define REG_RX_PAUSE(pn) CRA(0x4,pn,0x02) /* # pause frames received */ -#define REG_RX_UNSUP_OPCODE(pn) CRA(0x4,pn,0x03) /* # control frames with unsupported opcode */ -#define REG_RX_OK_BYTES(pn) CRA(0x4,pn,0x04) /* # octets in good frames */ -#define REG_RX_BAD_BYTES(pn) CRA(0x4,pn,0x05) /* # octets in bad frames */ -#define REG_RX_UNICAST(pn) CRA(0x4,pn,0x06) /* # good unicast frames */ -#define REG_RX_MULTICAST(pn) CRA(0x4,pn,0x07) /* # good multicast frames */ -#define REG_RX_BROADCAST(pn) CRA(0x4,pn,0x08) /* # good broadcast frames */ -#define REG_CRC(pn) CRA(0x4,pn,0x09) /* # frames w/ bad CRC only */ -#define REG_RX_ALIGNMENT(pn) CRA(0x4,pn,0x0a) /* # frames w/ alignment err */ -#define REG_RX_UNDERSIZE(pn) CRA(0x4,pn,0x0b) /* # frames undersize */ -#define REG_RX_FRAGMENTS(pn) CRA(0x4,pn,0x0c) /* # frames undersize w/ crc err */ -#define REG_RX_IN_RANGE_LENGTH_ERROR(pn) CRA(0x4,pn,0x0d) /* # frames with length error */ -#define REG_RX_OUT_OF_RANGE_ERROR(pn) CRA(0x4,pn,0x0e) /* # frames with illegal length field */ -#define REG_RX_OVERSIZE(pn) CRA(0x4,pn,0x0f) /* # frames oversize */ -#define REG_RX_JABBERS(pn) CRA(0x4,pn,0x10) /* # frames oversize w/ crc err */ -#define REG_RX_SIZE_64(pn) CRA(0x4,pn,0x11) /* # frames 64 octets long */ -#define REG_RX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x12) /* # frames 65-127 octets */ -#define REG_RX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x13) /* # frames 128-255 */ -#define REG_RX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x14) /* # frames 256-511 */ -#define REG_RX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x15) /* # frames 512-1023 */ -#define REG_RX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x16) /* # frames 1024-1518 */ -#define REG_RX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x17) /* # frames 1519-max */ -#define REG_TX_OUT_BYTES(pn) CRA(0x4,pn,0x18) /* # octets tx */ -#define REG_TX_PAUSE(pn) CRA(0x4,pn,0x19) /* # pause frames sent */ -#define REG_TX_OK_BYTES(pn) CRA(0x4,pn,0x1a) /* # octets tx OK */ -#define REG_TX_UNICAST(pn) CRA(0x4,pn,0x1b) /* # frames unicast */ -#define REG_TX_MULTICAST(pn) CRA(0x4,pn,0x1c) /* # frames multicast */ -#define REG_TX_BROADCAST(pn) CRA(0x4,pn,0x1d) /* # frames broadcast */ -#define REG_TX_MULTIPLE_COLL(pn) CRA(0x4,pn,0x1e) /* # frames tx after multiple collisions */ -#define REG_TX_LATE_COLL(pn) CRA(0x4,pn,0x1f) /* # late collisions detected */ -#define REG_TX_XCOLL(pn) CRA(0x4,pn,0x20) /* # frames lost, excessive collisions */ -#define REG_TX_DEFER(pn) CRA(0x4,pn,0x21) /* # frames deferred on first tx attempt */ -#define REG_TX_XDEFER(pn) CRA(0x4,pn,0x22) /* # frames excessively deferred */ -#define REG_TX_CSENSE(pn) CRA(0x4,pn,0x23) /* carrier sense errors at frame end */ -#define REG_TX_SIZE_64(pn) CRA(0x4,pn,0x24) /* # frames 64 octets long */ -#define REG_TX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x25) /* # frames 65-127 octets */ -#define REG_TX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x26) /* # frames 128-255 */ -#define REG_TX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x27) /* # frames 256-511 */ -#define REG_TX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x28) /* # frames 512-1023 */ -#define REG_TX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x29) /* # frames 1024-1518 */ -#define REG_TX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x2a) /* # frames 1519-max */ -#define REG_TX_SINGLE_COLL(pn) CRA(0x4,pn,0x2b) /* # frames tx after single collision */ -#define REG_TX_BACKOFF2(pn) CRA(0x4,pn,0x2c) /* # frames tx ok after 2 backoffs/collisions */ -#define REG_TX_BACKOFF3(pn) CRA(0x4,pn,0x2d) /* after 3 backoffs/collisions */ -#define REG_TX_BACKOFF4(pn) CRA(0x4,pn,0x2e) /* after 4 */ -#define REG_TX_BACKOFF5(pn) CRA(0x4,pn,0x2f) /* after 5 */ -#define REG_TX_BACKOFF6(pn) CRA(0x4,pn,0x30) /* after 6 */ -#define REG_TX_BACKOFF7(pn) CRA(0x4,pn,0x31) /* after 7 */ -#define REG_TX_BACKOFF8(pn) CRA(0x4,pn,0x32) /* after 8 */ -#define REG_TX_BACKOFF9(pn) CRA(0x4,pn,0x33) /* after 9 */ -#define REG_TX_BACKOFF10(pn) CRA(0x4,pn,0x34) /* after 10 */ -#define REG_TX_BACKOFF11(pn) CRA(0x4,pn,0x35) /* after 11 */ -#define REG_TX_BACKOFF12(pn) CRA(0x4,pn,0x36) /* after 12 */ -#define REG_TX_BACKOFF13(pn) CRA(0x4,pn,0x37) /* after 13 */ -#define REG_TX_BACKOFF14(pn) CRA(0x4,pn,0x38) /* after 14 */ -#define REG_TX_BACKOFF15(pn) CRA(0x4,pn,0x39) /* after 15 */ -#define REG_TX_UNDERRUN(pn) CRA(0x4,pn,0x3a) /* # frames dropped from underrun */ -#define REG_RX_XGMII_PROT_ERR CRA(0x4,0xa,0x3b) /* # protocol errors detected on XGMII interface */ -#define REG_RX_IPG_SHRINK(pn) CRA(0x4,pn,0x3c) /* # of IPG shrinks detected */ +enum { + RxInBytes = 0x00, // # Rx in octets + RxSymbolCarrier = 0x01, // Frames w/ symbol errors + RxPause = 0x02, // # pause frames received + RxUnsupOpcode = 0x03, // # control frames with unsupported opcode + RxOkBytes = 0x04, // # octets in good frames + RxBadBytes = 0x05, // # octets in bad frames + RxUnicast = 0x06, // # good unicast frames + RxMulticast = 0x07, // # good multicast frames + RxBroadcast = 0x08, // # good broadcast frames + Crc = 0x09, // # frames w/ bad CRC only + RxAlignment = 0x0a, // # frames w/ alignment err + RxUndersize = 0x0b, // # frames undersize + RxFragments = 0x0c, // # frames undersize w/ crc err + RxInRangeLengthError = 0x0d, // # frames with length error + RxOutOfRangeError = 0x0e, // # frames with illegal length field + RxOversize = 0x0f, // # frames oversize + RxJabbers = 0x10, // # frames oversize w/ crc err + RxSize64 = 0x11, // # frames 64 octets long + RxSize65To127 = 0x12, // # frames 65-127 octets + RxSize128To255 = 0x13, // # frames 128-255 + RxSize256To511 = 0x14, // # frames 256-511 + RxSize512To1023 = 0x15, // # frames 512-1023 + RxSize1024To1518 = 0x16, // # frames 1024-1518 + RxSize1519ToMax = 0x17, // # frames 1519-max -#define REG_STAT_STICKY1G(pn) CRA(0x4,pn,0x3e) /* tri-speed sticky bits */ -#define REG_STAT_STICKY10G CRA(0x4,0xa,0x3e) /* 10GbE sticky bits */ -#define REG_STAT_INIT(pn) CRA(0x4,pn,0x3f) /* Clear all statistics */ + TxOutBytes = 0x18, // # octets tx + TxPause = 0x19, // # pause frames sent + TxOkBytes = 0x1a, // # octets tx OK + TxUnicast = 0x1b, // # frames unicast + TxMulticast = 0x1c, // # frames multicast + TxBroadcast = 0x1d, // # frames broadcast + TxMultipleColl = 0x1e, // # frames tx after multiple collisions + TxLateColl = 0x1f, // # late collisions detected + TxXcoll = 0x20, // # frames lost, excessive collisions + TxDefer = 0x21, // # frames deferred on first tx attempt + TxXdefer = 0x22, // # frames excessively deferred + TxCsense = 0x23, // carrier sense errors at frame end + TxSize64 = 0x24, // # frames 64 octets long + TxSize65To127 = 0x25, // # frames 65-127 octets + TxSize128To255 = 0x26, // # frames 128-255 + TxSize256To511 = 0x27, // # frames 256-511 + TxSize512To1023 = 0x28, // # frames 512-1023 + TxSize1024To1518 = 0x29, // # frames 1024-1518 + TxSize1519ToMax = 0x2a, // # frames 1519-max + TxSingleColl = 0x2b, // # frames tx after single collision + TxBackoff2 = 0x2c, // # frames tx ok after 2 backoffs/collisions + TxBackoff3 = 0x2d, // after 3 backoffs/collisions + TxBackoff4 = 0x2e, // after 4 + TxBackoff5 = 0x2f, // after 5 + TxBackoff6 = 0x30, // after 6 + TxBackoff7 = 0x31, // after 7 + TxBackoff8 = 0x32, // after 8 + TxBackoff9 = 0x33, // after 9 + TxBackoff10 = 0x34, // after 10 + TxBackoff11 = 0x35, // after 11 + TxBackoff12 = 0x36, // after 12 + TxBackoff13 = 0x37, // after 13 + TxBackoff14 = 0x38, // after 14 + TxBackoff15 = 0x39, // after 15 + TxUnderrun = 0x3a, // # frames dropped from underrun + // Hole. See REG_RX_XGMII_PROT_ERR below. + RxIpgShrink = 0x3c, // # of IPG shrinks detected + // Duplicate. See REG_STAT_STICKY10G below. + StatSticky1G = 0x3e, // tri-speed sticky bits + StatInit = 0x3f // Clear all statistics +}; + +#define REG_RX_XGMII_PROT_ERR CRA(0x4,0xa,0x3b) /* # protocol errors detected on XGMII interface */ +#define REG_STAT_STICKY10G CRA(0x4,0xa,StatSticky1G) /* 10GbE sticky bits */ + +#define REG_RX_OK_BYTES(pn) CRA(0x4,pn,RxOkBytes) +#define REG_RX_BAD_BYTES(pn) CRA(0x4,pn,RxBadBytes) +#define REG_TX_OK_BYTES(pn) CRA(0x4,pn,TxOkBytes) /* MII-Management Block registers */ /* These are for MII-M interface 0, which is the bidirectional LVTTL one. If diff --git a/drivers/net/chelsio/vsc8244.c b/drivers/net/chelsio/vsc8244.c index c493e783d459..251d4859c91d 100644 --- a/drivers/net/chelsio/vsc8244.c +++ b/drivers/net/chelsio/vsc8244.c @@ -54,7 +54,7 @@ enum { }; #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ - VSC_INTR_NEG_DONE) + VSC_INTR_NEG_DONE) #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ VSC_INTR_ENABLE) @@ -94,19 +94,18 @@ static int vsc8244_intr_enable(struct cphy *cphy) { simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK); - /* Enable interrupts through Elmer */ + /* Enable interrupts through Elmer */ if (t1_is_asic(cphy->adapter)) { u32 elmer; t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); elmer |= ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) { + if (is_T2(cphy->adapter)) elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; - } t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); } - return 0; + return 0; } static int vsc8244_intr_disable(struct cphy *cphy) @@ -118,19 +117,18 @@ static int vsc8244_intr_disable(struct cphy *cphy) t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); elmer &= ~ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) { + if (is_T2(cphy->adapter)) elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4); - } t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); } - return 0; + return 0; } static int vsc8244_intr_clear(struct cphy *cphy) { u32 val; - u32 elmer; + u32 elmer; /* Clear PHY interrupts by reading the register. */ simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val); @@ -138,13 +136,12 @@ static int vsc8244_intr_clear(struct cphy *cphy) if (t1_is_asic(cphy->adapter)) { t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer); elmer |= ELMER0_GP_BIT1; - if (is_T2(cphy->adapter)) { + if (is_T2(cphy->adapter)) elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; - } t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer); } - return 0; + return 0; } /* @@ -179,13 +176,13 @@ static int vsc8244_set_speed_duplex(struct cphy *phy, int speed, int duplex) int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits) { - int ret; - unsigned int val; + int ret; + unsigned int val; - ret = mdio_read(phy, mmd, reg, &val); - if (!ret) - ret = mdio_write(phy, mmd, reg, val | bits); - return ret; + ret = mdio_read(phy, mmd, reg, &val); + if (!ret) + ret = mdio_write(phy, mmd, reg, val | bits); + return ret; } static int vsc8244_autoneg_enable(struct cphy *cphy) @@ -235,7 +232,7 @@ static int vsc8244_advertise(struct cphy *phy, unsigned int advertise_map) } static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok, - int *speed, int *duplex, int *fc) + int *speed, int *duplex, int *fc) { unsigned int bmcr, status, lpa, adv; int err, sp = -1, dplx = -1, pause = 0; @@ -343,11 +340,13 @@ static struct cphy_ops vsc8244_ops = { .get_link_status = vsc8244_get_link_status }; -static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr, struct mdio_ops *mdio_ops) +static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr, + struct mdio_ops *mdio_ops) { struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); - if (!cphy) return NULL; + if (!cphy) + return NULL; cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops); diff --git a/drivers/net/cxgb3/Makefile b/drivers/net/cxgb3/Makefile new file mode 100644 index 000000000000..343467985321 --- /dev/null +++ b/drivers/net/cxgb3/Makefile @@ -0,0 +1,8 @@ +# +# Chelsio T3 driver +# + +obj-$(CONFIG_CHELSIO_T3) += cxgb3.o + +cxgb3-objs := cxgb3_main.o ael1002.o vsc8211.o t3_hw.o mc5.o \ + xgmac.o sge.o l2t.o cxgb3_offload.o diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h new file mode 100644 index 000000000000..5c97a64451ce --- /dev/null +++ b/drivers/net/cxgb3/adapter.h @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* This file should not be included directly. Include common.h instead. */ + +#ifndef __T3_ADAPTER_H__ +#define __T3_ADAPTER_H__ + +#include +#include +#include +#include +#include +#include +#include "t3cdev.h" +#include +#include +#include + +typedef irqreturn_t(*intr_handler_t) (int, void *); + +struct vlan_group; + +struct port_info { + struct vlan_group *vlan_grp; + const struct port_type_info *port_type; + u8 port_id; + u8 rx_csum_offload; + u8 nqsets; + u8 first_qset; + struct cphy phy; + struct cmac mac; + struct link_config link_config; + struct net_device_stats netstats; + int activity; +}; + +enum { /* adapter flags */ + FULL_INIT_DONE = (1 << 0), + USING_MSI = (1 << 1), + USING_MSIX = (1 << 2), + QUEUES_BOUND = (1 << 3), +}; + +struct rx_desc; +struct rx_sw_desc; + +struct sge_fl { /* SGE per free-buffer list state */ + unsigned int buf_size; /* size of each Rx buffer */ + unsigned int credits; /* # of available Rx buffers */ + unsigned int size; /* capacity of free list */ + unsigned int cidx; /* consumer index */ + unsigned int pidx; /* producer index */ + unsigned int gen; /* free list generation */ + struct rx_desc *desc; /* address of HW Rx descriptor ring */ + struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */ + dma_addr_t phys_addr; /* physical address of HW ring start */ + unsigned int cntxt_id; /* SGE context id for the free list */ + unsigned long empty; /* # of times queue ran out of buffers */ +}; + +/* + * Bundle size for grouping offload RX packets for delivery to the stack. + * Don't make this too big as we do prefetch on each packet in a bundle. + */ +# define RX_BUNDLE_SIZE 8 + +struct rsp_desc; + +struct sge_rspq { /* state for an SGE response queue */ + unsigned int credits; /* # of pending response credits */ + unsigned int size; /* capacity of response queue */ + unsigned int cidx; /* consumer index */ + unsigned int gen; /* current generation bit */ + unsigned int polling; /* is the queue serviced through NAPI? */ + unsigned int holdoff_tmr; /* interrupt holdoff timer in 100ns */ + unsigned int next_holdoff; /* holdoff time for next interrupt */ + struct rsp_desc *desc; /* address of HW response ring */ + dma_addr_t phys_addr; /* physical address of the ring */ + unsigned int cntxt_id; /* SGE context id for the response q */ + spinlock_t lock; /* guards response processing */ + struct sk_buff *rx_head; /* offload packet receive queue head */ + struct sk_buff *rx_tail; /* offload packet receive queue tail */ + + unsigned long offload_pkts; + unsigned long offload_bundles; + unsigned long eth_pkts; /* # of ethernet packets */ + unsigned long pure_rsps; /* # of pure (non-data) responses */ + unsigned long imm_data; /* responses with immediate data */ + unsigned long rx_drops; /* # of packets dropped due to no mem */ + unsigned long async_notif; /* # of asynchronous notification events */ + unsigned long empty; /* # of times queue ran out of credits */ + unsigned long nomem; /* # of responses deferred due to no mem */ + unsigned long unhandled_irqs; /* # of spurious intrs */ +}; + +struct tx_desc; +struct tx_sw_desc; + +struct sge_txq { /* state for an SGE Tx queue */ + unsigned long flags; /* HW DMA fetch status */ + unsigned int in_use; /* # of in-use Tx descriptors */ + unsigned int size; /* # of descriptors */ + unsigned int processed; /* total # of descs HW has processed */ + unsigned int cleaned; /* total # of descs SW has reclaimed */ + unsigned int stop_thres; /* SW TX queue suspend threshold */ + unsigned int cidx; /* consumer index */ + unsigned int pidx; /* producer index */ + unsigned int gen; /* current value of generation bit */ + unsigned int unacked; /* Tx descriptors used since last COMPL */ + struct tx_desc *desc; /* address of HW Tx descriptor ring */ + struct tx_sw_desc *sdesc; /* address of SW Tx descriptor ring */ + spinlock_t lock; /* guards enqueueing of new packets */ + unsigned int token; /* WR token */ + dma_addr_t phys_addr; /* physical address of the ring */ + struct sk_buff_head sendq; /* List of backpressured offload packets */ + struct tasklet_struct qresume_tsk; /* restarts the queue */ + unsigned int cntxt_id; /* SGE context id for the Tx q */ + unsigned long stops; /* # of times q has been stopped */ + unsigned long restarts; /* # of queue restarts */ +}; + +enum { /* per port SGE statistics */ + SGE_PSTAT_TSO, /* # of TSO requests */ + SGE_PSTAT_RX_CSUM_GOOD, /* # of successful RX csum offloads */ + SGE_PSTAT_TX_CSUM, /* # of TX checksum offloads */ + SGE_PSTAT_VLANEX, /* # of VLAN tag extractions */ + SGE_PSTAT_VLANINS, /* # of VLAN tag insertions */ + + SGE_PSTAT_MAX /* must be last */ +}; + +struct sge_qset { /* an SGE queue set */ + struct sge_rspq rspq; + struct sge_fl fl[SGE_RXQ_PER_SET]; + struct sge_txq txq[SGE_TXQ_PER_SET]; + struct net_device *netdev; /* associated net device */ + unsigned long txq_stopped; /* which Tx queues are stopped */ + struct timer_list tx_reclaim_timer; /* reclaims TX buffers */ + unsigned long port_stats[SGE_PSTAT_MAX]; +} ____cacheline_aligned; + +struct sge { + struct sge_qset qs[SGE_QSETS]; + spinlock_t reg_lock; /* guards non-atomic SGE registers (eg context) */ +}; + +struct adapter { + struct t3cdev tdev; + struct list_head adapter_list; + void __iomem *regs; + struct pci_dev *pdev; + unsigned long registered_device_map; + unsigned long open_device_map; + unsigned long flags; + + const char *name; + int msg_enable; + unsigned int mmio_len; + + struct adapter_params params; + unsigned int slow_intr_mask; + unsigned long irq_stats[IRQ_NUM_STATS]; + + struct { + unsigned short vec; + char desc[22]; + } msix_info[SGE_QSETS + 1]; + + /* T3 modules */ + struct sge sge; + struct mc7 pmrx; + struct mc7 pmtx; + struct mc7 cm; + struct mc5 mc5; + + struct net_device *port[MAX_NPORTS]; + unsigned int check_task_cnt; + struct delayed_work adap_check_task; + struct work_struct ext_intr_handler_task; + + /* + * Dummy netdevices are needed when using multiple receive queues with + * NAPI as each netdevice can service only one queue. + */ + struct net_device *dummy_netdev[SGE_QSETS - 1]; + + struct dentry *debugfs_root; + + struct mutex mdio_lock; + spinlock_t stats_lock; + spinlock_t work_lock; +}; + +static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr) +{ + u32 val = readl(adapter->regs + reg_addr); + + CH_DBG(adapter, MMIO, "read register 0x%x value 0x%x\n", reg_addr, val); + return val; +} + +static inline void t3_write_reg(struct adapter *adapter, u32 reg_addr, u32 val) +{ + CH_DBG(adapter, MMIO, "setting register 0x%x to 0x%x\n", reg_addr, val); + writel(val, adapter->regs + reg_addr); +} + +static inline struct port_info *adap2pinfo(struct adapter *adap, int idx) +{ + return netdev_priv(adap->port[idx]); +} + +/* + * We use the spare atalk_ptr to map a net device to its SGE queue set. + * This is a macro so it can be used as l-value. + */ +#define dev2qset(netdev) ((netdev)->atalk_ptr) + +#define OFFLOAD_DEVMAP_BIT 15 + +#define tdev2adap(d) container_of(d, struct adapter, tdev) + +static inline int offload_running(struct adapter *adapter) +{ + return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); +} + +int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb); + +void t3_os_ext_intr_handler(struct adapter *adapter); +void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status, + int speed, int duplex, int fc); + +void t3_sge_start(struct adapter *adap); +void t3_sge_stop(struct adapter *adap); +void t3_free_sge_resources(struct adapter *adap); +void t3_sge_err_intr_handler(struct adapter *adapter); +intr_handler_t t3_intr_handler(struct adapter *adap, int polling); +int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev); +int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb); +void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p); +int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, + int irq_vec_idx, const struct qset_params *p, + int ntxq, struct net_device *netdev); +int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx, + unsigned char *data); +irqreturn_t t3_sge_intr_msix(int irq, void *cookie); + +#endif /* __T3_ADAPTER_H__ */ diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c new file mode 100644 index 000000000000..73a41e6a5bfc --- /dev/null +++ b/drivers/net/cxgb3/ael1002.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" +#include "regs.h" + +enum { + AEL100X_TX_DISABLE = 9, + AEL100X_TX_CONFIG1 = 0xc002, + AEL1002_PWR_DOWN_HI = 0xc011, + AEL1002_PWR_DOWN_LO = 0xc012, + AEL1002_XFI_EQL = 0xc015, + AEL1002_LB_EN = 0xc017, + + LASI_CTRL = 0x9002, + LASI_STAT = 0x9005 +}; + +static void ael100x_txon(struct cphy *phy) +{ + int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL; + + msleep(100); + t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio); + msleep(30); +} + +static int ael1002_power_down(struct cphy *phy, int enable) +{ + int err; + + err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable); + if (!err) + err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, + BMCR_PDOWN, enable ? BMCR_PDOWN : 0); + return err; +} + +static int ael1002_reset(struct cphy *phy, int wait) +{ + int err; + + if ((err = ael1002_power_down(phy, 0)) || + (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) || + (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) || + (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) || + (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) || + (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN, + 0, 1 << 5))) + return err; + return 0; +} + +static int ael1002_intr_noop(struct cphy *phy) +{ + return 0; +} + +static int ael100x_get_link_status(struct cphy *phy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + if (link_ok) { + unsigned int status; + int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status); + + /* + * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it + * once more to get the current link state. + */ + if (!err && !(status & BMSR_LSTATUS)) + err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, + &status); + if (err) + return err; + *link_ok = !!(status & BMSR_LSTATUS); + } + if (speed) + *speed = SPEED_10000; + if (duplex) + *duplex = DUPLEX_FULL; + return 0; +} + +static struct cphy_ops ael1002_ops = { + .reset = ael1002_reset, + .intr_enable = ael1002_intr_noop, + .intr_disable = ael1002_intr_noop, + .intr_clear = ael1002_intr_noop, + .intr_handler = ael1002_intr_noop, + .get_link_status = ael100x_get_link_status, + .power_down = ael1002_power_down, +}; + +void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops); + ael100x_txon(phy); +} + +static int ael1006_reset(struct cphy *phy, int wait) +{ + return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait); +} + +static int ael1006_intr_enable(struct cphy *phy) +{ + return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1); +} + +static int ael1006_intr_disable(struct cphy *phy) +{ + return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0); +} + +static int ael1006_intr_clear(struct cphy *phy) +{ + u32 val; + + return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val); +} + +static int ael1006_intr_handler(struct cphy *phy) +{ + unsigned int status; + int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status); + + if (err) + return err; + return (status & 1) ? cphy_cause_link_change : 0; +} + +static int ael1006_power_down(struct cphy *phy, int enable) +{ + return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR, + BMCR_PDOWN, enable ? BMCR_PDOWN : 0); +} + +static struct cphy_ops ael1006_ops = { + .reset = ael1006_reset, + .intr_enable = ael1006_intr_enable, + .intr_disable = ael1006_intr_disable, + .intr_clear = ael1006_intr_clear, + .intr_handler = ael1006_intr_handler, + .get_link_status = ael100x_get_link_status, + .power_down = ael1006_power_down, +}; + +void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops); + ael100x_txon(phy); +} + +static struct cphy_ops qt2045_ops = { + .reset = ael1006_reset, + .intr_enable = ael1006_intr_enable, + .intr_disable = ael1006_intr_disable, + .intr_clear = ael1006_intr_clear, + .intr_handler = ael1006_intr_handler, + .get_link_status = ael100x_get_link_status, + .power_down = ael1006_power_down, +}; + +void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + unsigned int stat; + + cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops); + + /* + * Some cards where the PHY is supposed to be at address 0 actually + * have it at 1. + */ + if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) && + stat == 0xffff) + phy->addr = 1; +} + +static int xaui_direct_reset(struct cphy *phy, int wait) +{ + return 0; +} + +static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + if (link_ok) { + unsigned int status; + + status = t3_read_reg(phy->adapter, + XGM_REG(A_XGM_SERDES_STAT0, phy->addr)); + *link_ok = !(status & F_LOWSIG0); + } + if (speed) + *speed = SPEED_10000; + if (duplex) + *duplex = DUPLEX_FULL; + return 0; +} + +static int xaui_direct_power_down(struct cphy *phy, int enable) +{ + return 0; +} + +static struct cphy_ops xaui_direct_ops = { + .reset = xaui_direct_reset, + .intr_enable = ael1002_intr_noop, + .intr_disable = ael1002_intr_noop, + .intr_clear = ael1002_intr_noop, + .intr_handler = ael1002_intr_noop, + .get_link_status = xaui_direct_get_link_status, + .power_down = xaui_direct_power_down, +}; + +void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops); +} diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h new file mode 100644 index 000000000000..e23deeb7d06d --- /dev/null +++ b/drivers/net/cxgb3/common.h @@ -0,0 +1,729 @@ +/* + * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __CHELSIO_COMMON_H +#define __CHELSIO_COMMON_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "version.h" + +#define CH_ERR(adap, fmt, ...) dev_err(&adap->pdev->dev, fmt, ## __VA_ARGS__) +#define CH_WARN(adap, fmt, ...) dev_warn(&adap->pdev->dev, fmt, ## __VA_ARGS__) +#define CH_ALERT(adap, fmt, ...) \ + dev_printk(KERN_ALERT, &adap->pdev->dev, fmt, ## __VA_ARGS__) + +/* + * More powerful macro that selectively prints messages based on msg_enable. + * For info and debugging messages. + */ +#define CH_MSG(adapter, level, category, fmt, ...) do { \ + if ((adapter)->msg_enable & NETIF_MSG_##category) \ + dev_printk(KERN_##level, &adapter->pdev->dev, fmt, \ + ## __VA_ARGS__); \ +} while (0) + +#ifdef DEBUG +# define CH_DBG(adapter, category, fmt, ...) \ + CH_MSG(adapter, DEBUG, category, fmt, ## __VA_ARGS__) +#else +# define CH_DBG(adapter, category, fmt, ...) +#endif + +/* Additional NETIF_MSG_* categories */ +#define NETIF_MSG_MMIO 0x8000000 + +struct t3_rx_mode { + struct net_device *dev; + struct dev_mc_list *mclist; + unsigned int idx; +}; + +static inline void init_rx_mode(struct t3_rx_mode *p, struct net_device *dev, + struct dev_mc_list *mclist) +{ + p->dev = dev; + p->mclist = mclist; + p->idx = 0; +} + +static inline u8 *t3_get_next_mcaddr(struct t3_rx_mode *rm) +{ + u8 *addr = NULL; + + if (rm->mclist && rm->idx < rm->dev->mc_count) { + addr = rm->mclist->dmi_addr; + rm->mclist = rm->mclist->next; + rm->idx++; + } + return addr; +} + +enum { + MAX_NPORTS = 2, /* max # of ports */ + MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */ + EEPROMSIZE = 8192, /* Serial EEPROM size */ + RSS_TABLE_SIZE = 64, /* size of RSS lookup and mapping tables */ + TCB_SIZE = 128, /* TCB size */ + NMTUS = 16, /* size of MTU table */ + NCCTRL_WIN = 32, /* # of congestion control windows */ +}; + +#define MAX_RX_COALESCING_LEN 16224U + +enum { + PAUSE_RX = 1 << 0, + PAUSE_TX = 1 << 1, + PAUSE_AUTONEG = 1 << 2 +}; + +enum { + SUPPORTED_OFFLOAD = 1 << 24, + SUPPORTED_IRQ = 1 << 25 +}; + +enum { /* adapter interrupt-maintained statistics */ + STAT_ULP_CH0_PBL_OOB, + STAT_ULP_CH1_PBL_OOB, + STAT_PCI_CORR_ECC, + + IRQ_NUM_STATS /* keep last */ +}; + +enum { + SGE_QSETS = 8, /* # of SGE Tx/Rx/RspQ sets */ + SGE_RXQ_PER_SET = 2, /* # of Rx queues per set */ + SGE_TXQ_PER_SET = 3 /* # of Tx queues per set */ +}; + +enum sge_context_type { /* SGE egress context types */ + SGE_CNTXT_RDMA = 0, + SGE_CNTXT_ETH = 2, + SGE_CNTXT_OFLD = 4, + SGE_CNTXT_CTRL = 5 +}; + +enum { + AN_PKT_SIZE = 32, /* async notification packet size */ + IMMED_PKT_SIZE = 48 /* packet size for immediate data */ +}; + +struct sg_ent { /* SGE scatter/gather entry */ + u32 len[2]; + u64 addr[2]; +}; + +#ifndef SGE_NUM_GENBITS +/* Must be 1 or 2 */ +# define SGE_NUM_GENBITS 2 +#endif + +#define TX_DESC_FLITS 16U +#define WR_FLITS (TX_DESC_FLITS + 1 - SGE_NUM_GENBITS) + +struct cphy; +struct adapter; + +struct mdio_ops { + int (*read)(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int *val); + int (*write)(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int val); +}; + +struct adapter_info { + unsigned char nports; /* # of ports */ + unsigned char phy_base_addr; /* MDIO PHY base address */ + unsigned char mdien; + unsigned char mdiinv; + unsigned int gpio_out; /* GPIO output settings */ + unsigned int gpio_intr; /* GPIO IRQ enable mask */ + unsigned long caps; /* adapter capabilities */ + const struct mdio_ops *mdio_ops; /* MDIO operations */ + const char *desc; /* product description */ +}; + +struct port_type_info { + void (*phy_prep)(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *ops); + unsigned int caps; + const char *desc; +}; + +struct mc5_stats { + unsigned long parity_err; + unsigned long active_rgn_full; + unsigned long nfa_srch_err; + unsigned long unknown_cmd; + unsigned long reqq_parity_err; + unsigned long dispq_parity_err; + unsigned long del_act_empty; +}; + +struct mc7_stats { + unsigned long corr_err; + unsigned long uncorr_err; + unsigned long parity_err; + unsigned long addr_err; +}; + +struct mac_stats { + u64 tx_octets; /* total # of octets in good frames */ + u64 tx_octets_bad; /* total # of octets in error frames */ + u64 tx_frames; /* all good frames */ + u64 tx_mcast_frames; /* good multicast frames */ + u64 tx_bcast_frames; /* good broadcast frames */ + u64 tx_pause; /* # of transmitted pause frames */ + u64 tx_deferred; /* frames with deferred transmissions */ + u64 tx_late_collisions; /* # of late collisions */ + u64 tx_total_collisions; /* # of total collisions */ + u64 tx_excess_collisions; /* frame errors from excessive collissions */ + u64 tx_underrun; /* # of Tx FIFO underruns */ + u64 tx_len_errs; /* # of Tx length errors */ + u64 tx_mac_internal_errs; /* # of internal MAC errors on Tx */ + u64 tx_excess_deferral; /* # of frames with excessive deferral */ + u64 tx_fcs_errs; /* # of frames with bad FCS */ + + u64 tx_frames_64; /* # of Tx frames in a particular range */ + u64 tx_frames_65_127; + u64 tx_frames_128_255; + u64 tx_frames_256_511; + u64 tx_frames_512_1023; + u64 tx_frames_1024_1518; + u64 tx_frames_1519_max; + + u64 rx_octets; /* total # of octets in good frames */ + u64 rx_octets_bad; /* total # of octets in error frames */ + u64 rx_frames; /* all good frames */ + u64 rx_mcast_frames; /* good multicast frames */ + u64 rx_bcast_frames; /* good broadcast frames */ + u64 rx_pause; /* # of received pause frames */ + u64 rx_fcs_errs; /* # of received frames with bad FCS */ + u64 rx_align_errs; /* alignment errors */ + u64 rx_symbol_errs; /* symbol errors */ + u64 rx_data_errs; /* data errors */ + u64 rx_sequence_errs; /* sequence errors */ + u64 rx_runt; /* # of runt frames */ + u64 rx_jabber; /* # of jabber frames */ + u64 rx_short; /* # of short frames */ + u64 rx_too_long; /* # of oversized frames */ + u64 rx_mac_internal_errs; /* # of internal MAC errors on Rx */ + + u64 rx_frames_64; /* # of Rx frames in a particular range */ + u64 rx_frames_65_127; + u64 rx_frames_128_255; + u64 rx_frames_256_511; + u64 rx_frames_512_1023; + u64 rx_frames_1024_1518; + u64 rx_frames_1519_max; + + u64 rx_cong_drops; /* # of Rx drops due to SGE congestion */ + + unsigned long tx_fifo_parity_err; + unsigned long rx_fifo_parity_err; + unsigned long tx_fifo_urun; + unsigned long rx_fifo_ovfl; + unsigned long serdes_signal_loss; + unsigned long xaui_pcs_ctc_err; + unsigned long xaui_pcs_align_change; +}; + +struct tp_mib_stats { + u32 ipInReceive_hi; + u32 ipInReceive_lo; + u32 ipInHdrErrors_hi; + u32 ipInHdrErrors_lo; + u32 ipInAddrErrors_hi; + u32 ipInAddrErrors_lo; + u32 ipInUnknownProtos_hi; + u32 ipInUnknownProtos_lo; + u32 ipInDiscards_hi; + u32 ipInDiscards_lo; + u32 ipInDelivers_hi; + u32 ipInDelivers_lo; + u32 ipOutRequests_hi; + u32 ipOutRequests_lo; + u32 ipOutDiscards_hi; + u32 ipOutDiscards_lo; + u32 ipOutNoRoutes_hi; + u32 ipOutNoRoutes_lo; + u32 ipReasmTimeout; + u32 ipReasmReqds; + u32 ipReasmOKs; + u32 ipReasmFails; + + u32 reserved[8]; + + u32 tcpActiveOpens; + u32 tcpPassiveOpens; + u32 tcpAttemptFails; + u32 tcpEstabResets; + u32 tcpOutRsts; + u32 tcpCurrEstab; + u32 tcpInSegs_hi; + u32 tcpInSegs_lo; + u32 tcpOutSegs_hi; + u32 tcpOutSegs_lo; + u32 tcpRetransSeg_hi; + u32 tcpRetransSeg_lo; + u32 tcpInErrs_hi; + u32 tcpInErrs_lo; + u32 tcpRtoMin; + u32 tcpRtoMax; +}; + +struct tp_params { + unsigned int nchan; /* # of channels */ + unsigned int pmrx_size; /* total PMRX capacity */ + unsigned int pmtx_size; /* total PMTX capacity */ + unsigned int cm_size; /* total CM capacity */ + unsigned int chan_rx_size; /* per channel Rx size */ + unsigned int chan_tx_size; /* per channel Tx size */ + unsigned int rx_pg_size; /* Rx page size */ + unsigned int tx_pg_size; /* Tx page size */ + unsigned int rx_num_pgs; /* # of Rx pages */ + unsigned int tx_num_pgs; /* # of Tx pages */ + unsigned int ntimer_qs; /* # of timer queues */ +}; + +struct qset_params { /* SGE queue set parameters */ + unsigned int polling; /* polling/interrupt service for rspq */ + unsigned int coalesce_usecs; /* irq coalescing timer */ + unsigned int rspq_size; /* # of entries in response queue */ + unsigned int fl_size; /* # of entries in regular free list */ + unsigned int jumbo_size; /* # of entries in jumbo free list */ + unsigned int txq_size[SGE_TXQ_PER_SET]; /* Tx queue sizes */ + unsigned int cong_thres; /* FL congestion threshold */ +}; + +struct sge_params { + unsigned int max_pkt_size; /* max offload pkt size */ + struct qset_params qset[SGE_QSETS]; +}; + +struct mc5_params { + unsigned int mode; /* selects MC5 width */ + unsigned int nservers; /* size of server region */ + unsigned int nfilters; /* size of filter region */ + unsigned int nroutes; /* size of routing region */ +}; + +/* Default MC5 region sizes */ +enum { + DEFAULT_NSERVERS = 512, + DEFAULT_NFILTERS = 128 +}; + +/* MC5 modes, these must be non-0 */ +enum { + MC5_MODE_144_BIT = 1, + MC5_MODE_72_BIT = 2 +}; + +struct vpd_params { + unsigned int cclk; + unsigned int mclk; + unsigned int uclk; + unsigned int mdc; + unsigned int mem_timing; + u8 eth_base[6]; + u8 port_type[MAX_NPORTS]; + unsigned short xauicfg[2]; +}; + +struct pci_params { + unsigned int vpd_cap_addr; + unsigned int pcie_cap_addr; + unsigned short speed; + unsigned char width; + unsigned char variant; +}; + +enum { + PCI_VARIANT_PCI, + PCI_VARIANT_PCIX_MODE1_PARITY, + PCI_VARIANT_PCIX_MODE1_ECC, + PCI_VARIANT_PCIX_266_MODE2, + PCI_VARIANT_PCIE +}; + +struct adapter_params { + struct sge_params sge; + struct mc5_params mc5; + struct tp_params tp; + struct vpd_params vpd; + struct pci_params pci; + + const struct adapter_info *info; + + unsigned short mtus[NMTUS]; + unsigned short a_wnd[NCCTRL_WIN]; + unsigned short b_wnd[NCCTRL_WIN]; + + unsigned int nports; /* # of ethernet ports */ + unsigned int stats_update_period; /* MAC stats accumulation period */ + unsigned int linkpoll_period; /* link poll period in 0.1s */ + unsigned int rev; /* chip revision */ +}; + +struct trace_params { + u32 sip; + u32 sip_mask; + u32 dip; + u32 dip_mask; + u16 sport; + u16 sport_mask; + u16 dport; + u16 dport_mask; + u32 vlan:12; + u32 vlan_mask:12; + u32 intf:4; + u32 intf_mask:4; + u8 proto; + u8 proto_mask; +}; + +struct link_config { + unsigned int supported; /* link capabilities */ + unsigned int advertising; /* advertised capabilities */ + unsigned short requested_speed; /* speed user has requested */ + unsigned short speed; /* actual link speed */ + unsigned char requested_duplex; /* duplex user has requested */ + unsigned char duplex; /* actual link duplex */ + unsigned char requested_fc; /* flow control user has requested */ + unsigned char fc; /* actual link flow control */ + unsigned char autoneg; /* autonegotiating? */ + unsigned int link_ok; /* link up? */ +}; + +#define SPEED_INVALID 0xffff +#define DUPLEX_INVALID 0xff + +struct mc5 { + struct adapter *adapter; + unsigned int tcam_size; + unsigned char part_type; + unsigned char parity_enabled; + unsigned char mode; + struct mc5_stats stats; +}; + +static inline unsigned int t3_mc5_size(const struct mc5 *p) +{ + return p->tcam_size; +} + +struct mc7 { + struct adapter *adapter; /* backpointer to adapter */ + unsigned int size; /* memory size in bytes */ + unsigned int width; /* MC7 interface width */ + unsigned int offset; /* register address offset for MC7 instance */ + const char *name; /* name of MC7 instance */ + struct mc7_stats stats; /* MC7 statistics */ +}; + +static inline unsigned int t3_mc7_size(const struct mc7 *p) +{ + return p->size; +} + +struct cmac { + struct adapter *adapter; + unsigned int offset; + unsigned int nucast; /* # of address filters for unicast MACs */ + struct mac_stats stats; +}; + +enum { + MAC_DIRECTION_RX = 1, + MAC_DIRECTION_TX = 2, + MAC_RXFIFO_SIZE = 32768 +}; + +/* IEEE 802.3ae specified MDIO devices */ +enum { + MDIO_DEV_PMA_PMD = 1, + MDIO_DEV_WIS = 2, + MDIO_DEV_PCS = 3, + MDIO_DEV_XGXS = 4 +}; + +/* PHY loopback direction */ +enum { + PHY_LOOPBACK_TX = 1, + PHY_LOOPBACK_RX = 2 +}; + +/* PHY interrupt types */ +enum { + cphy_cause_link_change = 1, + cphy_cause_fifo_error = 2 +}; + +/* PHY operations */ +struct cphy_ops { + void (*destroy)(struct cphy *phy); + int (*reset)(struct cphy *phy, int wait); + + int (*intr_enable)(struct cphy *phy); + int (*intr_disable)(struct cphy *phy); + int (*intr_clear)(struct cphy *phy); + int (*intr_handler)(struct cphy *phy); + + int (*autoneg_enable)(struct cphy *phy); + int (*autoneg_restart)(struct cphy *phy); + + int (*advertise)(struct cphy *phy, unsigned int advertise_map); + int (*set_loopback)(struct cphy *phy, int mmd, int dir, int enable); + int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex); + int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed, + int *duplex, int *fc); + int (*power_down)(struct cphy *phy, int enable); +}; + +/* A PHY instance */ +struct cphy { + int addr; /* PHY address */ + struct adapter *adapter; /* associated adapter */ + unsigned long fifo_errors; /* FIFO over/under-flows */ + const struct cphy_ops *ops; /* PHY operations */ + int (*mdio_read)(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int *val); + int (*mdio_write)(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int val); +}; + +/* Convenience MDIO read/write wrappers */ +static inline int mdio_read(struct cphy *phy, int mmd, int reg, + unsigned int *valp) +{ + return phy->mdio_read(phy->adapter, phy->addr, mmd, reg, valp); +} + +static inline int mdio_write(struct cphy *phy, int mmd, int reg, + unsigned int val) +{ + return phy->mdio_write(phy->adapter, phy->addr, mmd, reg, val); +} + +/* Convenience initializer */ +static inline void cphy_init(struct cphy *phy, struct adapter *adapter, + int phy_addr, struct cphy_ops *phy_ops, + const struct mdio_ops *mdio_ops) +{ + phy->adapter = adapter; + phy->addr = phy_addr; + phy->ops = phy_ops; + if (mdio_ops) { + phy->mdio_read = mdio_ops->read; + phy->mdio_write = mdio_ops->write; + } +} + +/* Accumulate MAC statistics every 180 seconds. For 1G we multiply by 10. */ +#define MAC_STATS_ACCUM_SECS 180 + +#define XGM_REG(reg_addr, idx) \ + ((reg_addr) + (idx) * (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR)) + +struct addr_val_pair { + unsigned int reg_addr; + unsigned int val; +}; + +#include "adapter.h" + +#ifndef PCI_VENDOR_ID_CHELSIO +# define PCI_VENDOR_ID_CHELSIO 0x1425 +#endif + +#define for_each_port(adapter, iter) \ + for (iter = 0; iter < (adapter)->params.nports; ++iter) + +#define adapter_info(adap) ((adap)->params.info) + +static inline int uses_xaui(const struct adapter *adap) +{ + return adapter_info(adap)->caps & SUPPORTED_AUI; +} + +static inline int is_10G(const struct adapter *adap) +{ + return adapter_info(adap)->caps & SUPPORTED_10000baseT_Full; +} + +static inline int is_offload(const struct adapter *adap) +{ + return adapter_info(adap)->caps & SUPPORTED_OFFLOAD; +} + +static inline unsigned int core_ticks_per_usec(const struct adapter *adap) +{ + return adap->params.vpd.cclk / 1000; +} + +static inline unsigned int is_pcie(const struct adapter *adap) +{ + return adap->params.pci.variant == PCI_VARIANT_PCIE; +} + +void t3_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask, + u32 val); +void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p, + int n, unsigned int offset); +int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, + int polarity, int attempts, int delay, u32 *valp); +static inline int t3_wait_op_done(struct adapter *adapter, int reg, u32 mask, + int polarity, int attempts, int delay) +{ + return t3_wait_op_done_val(adapter, reg, mask, polarity, attempts, + delay, NULL); +} +int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, + unsigned int set); +int t3_phy_reset(struct cphy *phy, int mmd, int wait); +int t3_phy_advertise(struct cphy *phy, unsigned int advert); +int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex); + +void t3_intr_enable(struct adapter *adapter); +void t3_intr_disable(struct adapter *adapter); +void t3_intr_clear(struct adapter *adapter); +void t3_port_intr_enable(struct adapter *adapter, int idx); +void t3_port_intr_disable(struct adapter *adapter, int idx); +void t3_port_intr_clear(struct adapter *adapter, int idx); +int t3_slow_intr_handler(struct adapter *adapter); +int t3_phy_intr_handler(struct adapter *adapter); + +void t3_link_changed(struct adapter *adapter, int port_id); +int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc); +const struct adapter_info *t3_get_adapter_info(unsigned int board_id); +int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data); +int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data); +int t3_seeprom_wp(struct adapter *adapter, int enable); +int t3_read_flash(struct adapter *adapter, unsigned int addr, + unsigned int nwords, u32 *data, int byte_oriented); +int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size); +int t3_get_fw_version(struct adapter *adapter, u32 *vers); +int t3_check_fw_version(struct adapter *adapter); +int t3_init_hw(struct adapter *adapter, u32 fw_params); +void mac_prep(struct cmac *mac, struct adapter *adapter, int index); +void early_hw_init(struct adapter *adapter, const struct adapter_info *ai); +int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai, + int reset); +void t3_led_ready(struct adapter *adapter); +void t3_fatal_err(struct adapter *adapter); +void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on); +void t3_config_rss(struct adapter *adapter, unsigned int rss_config, + const u8 * cpus, const u16 *rspq); +int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map); +int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask); +int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr, + unsigned int n, unsigned int *valp); +int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, + u64 *buf); + +int t3_mac_reset(struct cmac *mac); +void t3b_pcs_reset(struct cmac *mac); +int t3_mac_enable(struct cmac *mac, int which); +int t3_mac_disable(struct cmac *mac, int which); +int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu); +int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm); +int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]); +int t3_mac_set_num_ucast(struct cmac *mac, int n); +const struct mac_stats *t3_mac_update_stats(struct cmac *mac); +int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc); + +void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode); +int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, + unsigned int nroutes); +void t3_mc5_intr_handler(struct mc5 *mc5); +int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start, unsigned int n, + u32 *buf); + +int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh); +void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size); +void t3_tp_set_offload_mode(struct adapter *adap, int enable); +void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps); +void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS], + unsigned short alpha[NCCTRL_WIN], + unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap); +void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS]); +void t3_get_cong_cntl_tab(struct adapter *adap, + unsigned short incr[NMTUS][NCCTRL_WIN]); +void t3_config_trace_filter(struct adapter *adapter, + const struct trace_params *tp, int filter_index, + int invert, int enable); +int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched); + +void t3_sge_prep(struct adapter *adap, struct sge_params *p); +void t3_sge_init(struct adapter *adap, struct sge_params *p); +int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable, + enum sge_context_type type, int respq, u64 base_addr, + unsigned int size, unsigned int token, int gen, + unsigned int cidx); +int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id, + int gts_enable, u64 base_addr, unsigned int size, + unsigned int esize, unsigned int cong_thres, int gen, + unsigned int cidx); +int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id, + int irq_vec_idx, u64 base_addr, unsigned int size, + unsigned int fl_thres, int gen, unsigned int cidx); +int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr, + unsigned int size, int rspq, int ovfl_mode, + unsigned int credits, unsigned int credit_thres); +int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable); +int t3_sge_disable_fl(struct adapter *adapter, unsigned int id); +int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id); +int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id); +int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4]); +int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4]); +int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4]); +int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4]); +int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, + unsigned int credits); + +void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr, + const struct mdio_ops *mdio_ops); +void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops); +#endif /* __CHELSIO_COMMON_H */ diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h new file mode 100644 index 000000000000..2095ddacff78 --- /dev/null +++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _CXGB3_OFFLOAD_CTL_DEFS_H +#define _CXGB3_OFFLOAD_CTL_DEFS_H + +enum { + GET_MAX_OUTSTANDING_WR, + GET_TX_MAX_CHUNK, + GET_TID_RANGE, + GET_STID_RANGE, + GET_RTBL_RANGE, + GET_L2T_CAPACITY, + GET_MTUS, + GET_WR_LEN, + GET_IFF_FROM_MAC, + GET_DDP_PARAMS, + GET_PORTS, + + ULP_ISCSI_GET_PARAMS, + ULP_ISCSI_SET_PARAMS, + + RDMA_GET_PARAMS, + RDMA_CQ_OP, + RDMA_CQ_SETUP, + RDMA_CQ_DISABLE, + RDMA_CTRL_QP_SETUP, + RDMA_GET_MEM, +}; + +/* + * Structure used to describe a TID range. Valid TIDs are [base, base+num). + */ +struct tid_range { + unsigned int base; /* first TID */ + unsigned int num; /* number of TIDs in range */ +}; + +/* + * Structure used to request the size and contents of the MTU table. + */ +struct mtutab { + unsigned int size; /* # of entries in the MTU table */ + const unsigned short *mtus; /* the MTU table values */ +}; + +struct net_device; + +/* + * Structure used to request the adapter net_device owning a given MAC address. + */ +struct iff_mac { + struct net_device *dev; /* the net_device */ + const unsigned char *mac_addr; /* MAC address to lookup */ + u16 vlan_tag; +}; + +struct pci_dev; + +/* + * Structure used to request the TCP DDP parameters. + */ +struct ddp_params { + unsigned int llimit; /* TDDP region start address */ + unsigned int ulimit; /* TDDP region end address */ + unsigned int tag_mask; /* TDDP tag mask */ + struct pci_dev *pdev; +}; + +struct adap_ports { + unsigned int nports; /* number of ports on this adapter */ + struct net_device *lldevs[2]; +}; + +/* + * Structure used to return information to the iscsi layer. + */ +struct ulp_iscsi_info { + unsigned int offset; + unsigned int llimit; + unsigned int ulimit; + unsigned int tagmask; + unsigned int pgsz3; + unsigned int pgsz2; + unsigned int pgsz1; + unsigned int pgsz0; + unsigned int max_rxsz; + unsigned int max_txsz; + struct pci_dev *pdev; +}; + +/* + * Structure used to return information to the RDMA layer. + */ +struct rdma_info { + unsigned int tpt_base; /* TPT base address */ + unsigned int tpt_top; /* TPT last entry address */ + unsigned int pbl_base; /* PBL base address */ + unsigned int pbl_top; /* PBL last entry address */ + unsigned int rqt_base; /* RQT base address */ + unsigned int rqt_top; /* RQT last entry address */ + unsigned int udbell_len; /* user doorbell region length */ + unsigned long udbell_physbase; /* user doorbell physical start addr */ + void __iomem *kdb_addr; /* kernel doorbell register address */ + struct pci_dev *pdev; /* associated PCI device */ +}; + +/* + * Structure used to request an operation on an RDMA completion queue. + */ +struct rdma_cq_op { + unsigned int id; + unsigned int op; + unsigned int credits; +}; + +/* + * Structure used to setup RDMA completion queues. + */ +struct rdma_cq_setup { + unsigned int id; + unsigned long long base_addr; + unsigned int size; + unsigned int credits; + unsigned int credit_thres; + unsigned int ovfl_mode; +}; + +/* + * Structure used to setup the RDMA control egress context. + */ +struct rdma_ctrlqp_setup { + unsigned long long base_addr; + unsigned int size; +}; +#endif /* _CXGB3_OFFLOAD_CTL_DEFS_H */ diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h new file mode 100644 index 000000000000..16e004990c59 --- /dev/null +++ b/drivers/net/cxgb3/cxgb3_defs.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _CHELSIO_DEFS_H +#define _CHELSIO_DEFS_H + +#include +#include + +#include "t3cdev.h" + +#include "cxgb3_offload.h" + +#define VALIDATE_TID 1 + +void *cxgb_alloc_mem(unsigned long size); +void cxgb_free_mem(void *addr); +void cxgb_neigh_update(struct neighbour *neigh); +void cxgb_redirect(struct dst_entry *old, struct dst_entry *new); + +/* + * Map an ATID or STID to their entries in the corresponding TID tables. + */ +static inline union active_open_entry *atid2entry(const struct tid_info *t, + unsigned int atid) +{ + return &t->atid_tab[atid - t->atid_base]; +} + +static inline union listen_entry *stid2entry(const struct tid_info *t, + unsigned int stid) +{ + return &t->stid_tab[stid - t->stid_base]; +} + +/* + * Find the connection corresponding to a TID. + */ +static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t, + unsigned int tid) +{ + return tid < t->ntids ? &(t->tid_tab[tid]) : NULL; +} + +/* + * Find the connection corresponding to a server TID. + */ +static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t, + unsigned int tid) +{ + if (tid < t->stid_base || tid >= t->stid_base + t->nstids) + return NULL; + return &(stid2entry(t, tid)->t3c_tid); +} + +/* + * Find the connection corresponding to an active-open TID. + */ +static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t, + unsigned int tid) +{ + if (tid < t->atid_base || tid >= t->atid_base + t->natids) + return NULL; + return &(atid2entry(t, tid)->t3c_tid); +} + +int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n); +int attach_t3cdev(struct t3cdev *dev); +void detach_t3cdev(struct t3cdev *dev); +#endif diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h new file mode 100644 index 000000000000..a94281861a66 --- /dev/null +++ b/drivers/net/cxgb3/cxgb3_ioctl.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __CHIOCTL_H__ +#define __CHIOCTL_H__ + +/* + * Ioctl commands specific to this driver. + */ +enum { + CHELSIO_SETREG = 1024, + CHELSIO_GETREG, + CHELSIO_SETTPI, + CHELSIO_GETTPI, + CHELSIO_GETMTUTAB, + CHELSIO_SETMTUTAB, + CHELSIO_GETMTU, + CHELSIO_SET_PM, + CHELSIO_GET_PM, + CHELSIO_GET_TCAM, + CHELSIO_SET_TCAM, + CHELSIO_GET_TCB, + CHELSIO_GET_MEM, + CHELSIO_LOAD_FW, + CHELSIO_GET_PROTO, + CHELSIO_SET_PROTO, + CHELSIO_SET_TRACE_FILTER, + CHELSIO_SET_QSET_PARAMS, + CHELSIO_GET_QSET_PARAMS, + CHELSIO_SET_QSET_NUM, + CHELSIO_GET_QSET_NUM, + CHELSIO_SET_PKTSCHED, +}; + +struct ch_reg { + uint32_t cmd; + uint32_t addr; + uint32_t val; +}; + +struct ch_cntxt { + uint32_t cmd; + uint32_t cntxt_type; + uint32_t cntxt_id; + uint32_t data[4]; +}; + +/* context types */ +enum { CNTXT_TYPE_EGRESS, CNTXT_TYPE_FL, CNTXT_TYPE_RSP, CNTXT_TYPE_CQ }; + +struct ch_desc { + uint32_t cmd; + uint32_t queue_num; + uint32_t idx; + uint32_t size; + uint8_t data[128]; +}; + +struct ch_mem_range { + uint32_t cmd; + uint32_t mem_id; + uint32_t addr; + uint32_t len; + uint32_t version; + uint8_t buf[0]; +}; + +struct ch_qset_params { + uint32_t cmd; + uint32_t qset_idx; + int32_t txq_size[3]; + int32_t rspq_size; + int32_t fl_size[2]; + int32_t intr_lat; + int32_t polling; + int32_t cong_thres; +}; + +struct ch_pktsched_params { + uint32_t cmd; + uint8_t sched; + uint8_t idx; + uint8_t min; + uint8_t max; + uint8_t binding; +}; + +#ifndef TCB_SIZE +# define TCB_SIZE 128 +#endif + +/* TCB size in 32-bit words */ +#define TCB_WORDS (TCB_SIZE / 4) + +enum { MEM_CM, MEM_PMRX, MEM_PMTX }; /* ch_mem_range.mem_id values */ + +struct ch_mtus { + uint32_t cmd; + uint32_t nmtus; + uint16_t mtus[NMTUS]; +}; + +struct ch_pm { + uint32_t cmd; + uint32_t tx_pg_sz; + uint32_t tx_num_pg; + uint32_t rx_pg_sz; + uint32_t rx_num_pg; + uint32_t pm_total; +}; + +struct ch_tcam { + uint32_t cmd; + uint32_t tcam_size; + uint32_t nservers; + uint32_t nroutes; + uint32_t nfilters; +}; + +struct ch_tcb { + uint32_t cmd; + uint32_t tcb_index; + uint32_t tcb_data[TCB_WORDS]; +}; + +struct ch_tcam_word { + uint32_t cmd; + uint32_t addr; + uint32_t buf[3]; +}; + +struct ch_trace { + uint32_t cmd; + uint32_t sip; + uint32_t sip_mask; + uint32_t dip; + uint32_t dip_mask; + uint16_t sport; + uint16_t sport_mask; + uint16_t dport; + uint16_t dport_mask; + uint32_t vlan:12; + uint32_t vlan_mask:12; + uint32_t intf:4; + uint32_t intf_mask:4; + uint8_t proto; + uint8_t proto_mask; + uint8_t invert_match:1; + uint8_t config_tx:1; + uint8_t config_rx:1; + uint8_t trace_tx:1; + uint8_t trace_rx:1; +}; + +#define SIOCCHIOCTL SIOCDEVPRIVATE + +#endif diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c new file mode 100644 index 000000000000..dfa035a1ad45 --- /dev/null +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -0,0 +1,2515 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "cxgb3_ioctl.h" +#include "regs.h" +#include "cxgb3_offload.h" +#include "version.h" + +#include "cxgb3_ctl_defs.h" +#include "t3_cpl.h" +#include "firmware_exports.h" + +enum { + MAX_TXQ_ENTRIES = 16384, + MAX_CTRL_TXQ_ENTRIES = 1024, + MAX_RSPQ_ENTRIES = 16384, + MAX_RX_BUFFERS = 16384, + MAX_RX_JUMBO_BUFFERS = 16384, + MIN_TXQ_ENTRIES = 4, + MIN_CTRL_TXQ_ENTRIES = 4, + MIN_RSPQ_ENTRIES = 32, + MIN_FL_ENTRIES = 32 +}; + +#define PORT_MASK ((1 << MAX_NPORTS) - 1) + +#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ + NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\ + NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) + +#define EEPROM_MAGIC 0x38E2F10C + +#define to_net_dev(class) container_of(class, struct net_device, class_dev) + +#define CH_DEVICE(devid, ssid, idx) \ + { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx } + +static const struct pci_device_id cxgb3_pci_tbl[] = { + CH_DEVICE(0x20, 1, 0), /* PE9000 */ + CH_DEVICE(0x21, 1, 1), /* T302E */ + CH_DEVICE(0x22, 1, 2), /* T310E */ + CH_DEVICE(0x23, 1, 3), /* T320X */ + CH_DEVICE(0x24, 1, 1), /* T302X */ + CH_DEVICE(0x25, 1, 3), /* T320E */ + CH_DEVICE(0x26, 1, 2), /* T310X */ + CH_DEVICE(0x30, 1, 2), /* T3B10 */ + CH_DEVICE(0x31, 1, 3), /* T3B20 */ + CH_DEVICE(0x32, 1, 1), /* T3B02 */ + {0,} +}; + +MODULE_DESCRIPTION(DRV_DESC); +MODULE_AUTHOR("Chelsio Communications"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRV_VERSION); +MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl); + +static int dflt_msg_enable = DFLT_MSG_ENABLE; + +module_param(dflt_msg_enable, int, 0644); +MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap"); + +/* + * The driver uses the best interrupt scheme available on a platform in the + * order MSI-X, MSI, legacy pin interrupts. This parameter determines which + * of these schemes the driver may consider as follows: + * + * msi = 2: choose from among all three options + * msi = 1: only consider MSI and pin interrupts + * msi = 0: force pin interrupts + */ +static int msi = 2; + +module_param(msi, int, 0644); +MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X"); + +/* + * The driver enables offload as a default. + * To disable it, use ofld_disable = 1. + */ + +static int ofld_disable = 0; + +module_param(ofld_disable, int, 0644); +MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not"); + +/* + * We have work elements that we need to cancel when an interface is taken + * down. Normally the work elements would be executed by keventd but that + * can deadlock because of linkwatch. If our close method takes the rtnl + * lock and linkwatch is ahead of our work elements in keventd, linkwatch + * will block keventd as it needs the rtnl lock, and we'll deadlock waiting + * for our work to complete. Get our own work queue to solve this. + */ +static struct workqueue_struct *cxgb3_wq; + +/** + * link_report - show link status and link speed/duplex + * @p: the port whose settings are to be reported + * + * Shows the link status, speed, and duplex of a port. + */ +static void link_report(struct net_device *dev) +{ + if (!netif_carrier_ok(dev)) + printk(KERN_INFO "%s: link down\n", dev->name); + else { + const char *s = "10Mbps"; + const struct port_info *p = netdev_priv(dev); + + switch (p->link_config.speed) { + case SPEED_10000: + s = "10Gbps"; + break; + case SPEED_1000: + s = "1000Mbps"; + break; + case SPEED_100: + s = "100Mbps"; + break; + } + + printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s, + p->link_config.duplex == DUPLEX_FULL ? "full" : "half"); + } +} + +/** + * t3_os_link_changed - handle link status changes + * @adapter: the adapter associated with the link change + * @port_id: the port index whose limk status has changed + * @link_stat: the new status of the link + * @speed: the new speed setting + * @duplex: the new duplex setting + * @pause: the new flow-control setting + * + * This is the OS-dependent handler for link status changes. The OS + * neutral handler takes care of most of the processing for these events, + * then calls this handler for any OS-specific processing. + */ +void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat, + int speed, int duplex, int pause) +{ + struct net_device *dev = adapter->port[port_id]; + + /* Skip changes from disabled ports. */ + if (!netif_running(dev)) + return; + + if (link_stat != netif_carrier_ok(dev)) { + if (link_stat) + netif_carrier_on(dev); + else + netif_carrier_off(dev); + link_report(dev); + } +} + +static void cxgb_set_rxmode(struct net_device *dev) +{ + struct t3_rx_mode rm; + struct port_info *pi = netdev_priv(dev); + + init_rx_mode(&rm, dev, dev->mc_list); + t3_mac_set_rx_mode(&pi->mac, &rm); +} + +/** + * link_start - enable a port + * @dev: the device to enable + * + * Performs the MAC and PHY actions needed to enable a port. + */ +static void link_start(struct net_device *dev) +{ + struct t3_rx_mode rm; + struct port_info *pi = netdev_priv(dev); + struct cmac *mac = &pi->mac; + + init_rx_mode(&rm, dev, dev->mc_list); + t3_mac_reset(mac); + t3_mac_set_mtu(mac, dev->mtu); + t3_mac_set_address(mac, 0, dev->dev_addr); + t3_mac_set_rx_mode(mac, &rm); + t3_link_start(&pi->phy, mac, &pi->link_config); + t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); +} + +static inline void cxgb_disable_msi(struct adapter *adapter) +{ + if (adapter->flags & USING_MSIX) { + pci_disable_msix(adapter->pdev); + adapter->flags &= ~USING_MSIX; + } else if (adapter->flags & USING_MSI) { + pci_disable_msi(adapter->pdev); + adapter->flags &= ~USING_MSI; + } +} + +/* + * Interrupt handler for asynchronous events used with MSI-X. + */ +static irqreturn_t t3_async_intr_handler(int irq, void *cookie) +{ + t3_slow_intr_handler(cookie); + return IRQ_HANDLED; +} + +/* + * Name the MSI-X interrupts. + */ +static void name_msix_vecs(struct adapter *adap) +{ + int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1; + + snprintf(adap->msix_info[0].desc, n, "%s", adap->name); + adap->msix_info[0].desc[n] = 0; + + for_each_port(adap, j) { + struct net_device *d = adap->port[j]; + const struct port_info *pi = netdev_priv(d); + + for (i = 0; i < pi->nqsets; i++, msi_idx++) { + snprintf(adap->msix_info[msi_idx].desc, n, + "%s (queue %d)", d->name, i); + adap->msix_info[msi_idx].desc[n] = 0; + } + } +} + +static int request_msix_data_irqs(struct adapter *adap) +{ + int i, j, err, qidx = 0; + + for_each_port(adap, i) { + int nqsets = adap2pinfo(adap, i)->nqsets; + + for (j = 0; j < nqsets; ++j) { + err = request_irq(adap->msix_info[qidx + 1].vec, + t3_intr_handler(adap, + adap->sge.qs[qidx]. + rspq.polling), 0, + adap->msix_info[qidx + 1].desc, + &adap->sge.qs[qidx]); + if (err) { + while (--qidx >= 0) + free_irq(adap->msix_info[qidx + 1].vec, + &adap->sge.qs[qidx]); + return err; + } + qidx++; + } + } + return 0; +} + +/** + * setup_rss - configure RSS + * @adap: the adapter + * + * Sets up RSS to distribute packets to multiple receive queues. We + * configure the RSS CPU lookup table to distribute to the number of HW + * receive queues, and the response queue lookup table to narrow that + * down to the response queues actually configured for each port. + * We always configure the RSS mapping for two ports since the mapping + * table has plenty of entries. + */ +static void setup_rss(struct adapter *adap) +{ + int i; + unsigned int nq0 = adap2pinfo(adap, 0)->nqsets; + unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1; + u8 cpus[SGE_QSETS + 1]; + u16 rspq_map[RSS_TABLE_SIZE]; + + for (i = 0; i < SGE_QSETS; ++i) + cpus[i] = i; + cpus[SGE_QSETS] = 0xff; /* terminator */ + + for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) { + rspq_map[i] = i % nq0; + rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0; + } + + t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN | + F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | + V_RRCPLCPUSIZE(6), cpus, rspq_map); +} + +/* + * If we have multiple receive queues per port serviced by NAPI we need one + * netdevice per queue as NAPI operates on netdevices. We already have one + * netdevice, namely the one associated with the interface, so we use dummy + * ones for any additional queues. Note that these netdevices exist purely + * so that NAPI has something to work with, they do not represent network + * ports and are not registered. + */ +static int init_dummy_netdevs(struct adapter *adap) +{ + int i, j, dummy_idx = 0; + struct net_device *nd; + + for_each_port(adap, i) { + struct net_device *dev = adap->port[i]; + const struct port_info *pi = netdev_priv(dev); + + for (j = 0; j < pi->nqsets - 1; j++) { + if (!adap->dummy_netdev[dummy_idx]) { + nd = alloc_netdev(0, "", ether_setup); + if (!nd) + goto free_all; + + nd->priv = adap; + nd->weight = 64; + set_bit(__LINK_STATE_START, &nd->state); + adap->dummy_netdev[dummy_idx] = nd; + } + strcpy(adap->dummy_netdev[dummy_idx]->name, dev->name); + dummy_idx++; + } + } + return 0; + +free_all: + while (--dummy_idx >= 0) { + free_netdev(adap->dummy_netdev[dummy_idx]); + adap->dummy_netdev[dummy_idx] = NULL; + } + return -ENOMEM; +} + +/* + * Wait until all NAPI handlers are descheduled. This includes the handlers of + * both netdevices representing interfaces and the dummy ones for the extra + * queues. + */ +static void quiesce_rx(struct adapter *adap) +{ + int i; + struct net_device *dev; + + for_each_port(adap, i) { + dev = adap->port[i]; + while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) + msleep(1); + } + + for (i = 0; i < ARRAY_SIZE(adap->dummy_netdev); i++) { + dev = adap->dummy_netdev[i]; + if (dev) + while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) + msleep(1); + } +} + +/** + * setup_sge_qsets - configure SGE Tx/Rx/response queues + * @adap: the adapter + * + * Determines how many sets of SGE queues to use and initializes them. + * We support multiple queue sets per port if we have MSI-X, otherwise + * just one queue set per port. + */ +static int setup_sge_qsets(struct adapter *adap) +{ + int i, j, err, irq_idx = 0, qset_idx = 0, dummy_dev_idx = 0; + unsigned int ntxq = is_offload(adap) ? SGE_TXQ_PER_SET : 1; + + if (adap->params.rev > 0 && !(adap->flags & USING_MSI)) + irq_idx = -1; + + for_each_port(adap, i) { + struct net_device *dev = adap->port[i]; + const struct port_info *pi = netdev_priv(dev); + + for (j = 0; j < pi->nqsets; ++j, ++qset_idx) { + err = t3_sge_alloc_qset(adap, qset_idx, 1, + (adap->flags & USING_MSIX) ? qset_idx + 1 : + irq_idx, + &adap->params.sge.qset[qset_idx], ntxq, + j == 0 ? dev : + adap-> dummy_netdev[dummy_dev_idx++]); + if (err) { + t3_free_sge_resources(adap); + return err; + } + } + } + + return 0; +} + +static ssize_t attr_show(struct class_device *cd, char *buf, + ssize_t(*format) (struct adapter *, char *)) +{ + ssize_t len; + struct adapter *adap = to_net_dev(cd)->priv; + + /* Synchronize with ioctls that may shut down the device */ + rtnl_lock(); + len = (*format) (adap, buf); + rtnl_unlock(); + return len; +} + +static ssize_t attr_store(struct class_device *cd, const char *buf, size_t len, + ssize_t(*set) (struct adapter *, unsigned int), + unsigned int min_val, unsigned int max_val) +{ + char *endp; + ssize_t ret; + unsigned int val; + struct adapter *adap = to_net_dev(cd)->priv; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + val = simple_strtoul(buf, &endp, 0); + if (endp == buf || val < min_val || val > max_val) + return -EINVAL; + + rtnl_lock(); + ret = (*set) (adap, val); + if (!ret) + ret = len; + rtnl_unlock(); + return ret; +} + +#define CXGB3_SHOW(name, val_expr) \ +static ssize_t format_##name(struct adapter *adap, char *buf) \ +{ \ + return sprintf(buf, "%u\n", val_expr); \ +} \ +static ssize_t show_##name(struct class_device *cd, char *buf) \ +{ \ + return attr_show(cd, buf, format_##name); \ +} + +static ssize_t set_nfilters(struct adapter *adap, unsigned int val) +{ + if (adap->flags & FULL_INIT_DONE) + return -EBUSY; + if (val && adap->params.rev == 0) + return -EINVAL; + if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers) + return -EINVAL; + adap->params.mc5.nfilters = val; + return 0; +} + +static ssize_t store_nfilters(struct class_device *cd, const char *buf, + size_t len) +{ + return attr_store(cd, buf, len, set_nfilters, 0, ~0); +} + +static ssize_t set_nservers(struct adapter *adap, unsigned int val) +{ + if (adap->flags & FULL_INIT_DONE) + return -EBUSY; + if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters) + return -EINVAL; + adap->params.mc5.nservers = val; + return 0; +} + +static ssize_t store_nservers(struct class_device *cd, const char *buf, + size_t len) +{ + return attr_store(cd, buf, len, set_nservers, 0, ~0); +} + +#define CXGB3_ATTR_R(name, val_expr) \ +CXGB3_SHOW(name, val_expr) \ +static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) + +#define CXGB3_ATTR_RW(name, val_expr, store_method) \ +CXGB3_SHOW(name, val_expr) \ +static CLASS_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method) + +CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5)); +CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters); +CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers); + +static struct attribute *cxgb3_attrs[] = { + &class_device_attr_cam_size.attr, + &class_device_attr_nfilters.attr, + &class_device_attr_nservers.attr, + NULL +}; + +static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs }; + +static ssize_t tm_attr_show(struct class_device *cd, char *buf, int sched) +{ + ssize_t len; + unsigned int v, addr, bpt, cpt; + struct adapter *adap = to_net_dev(cd)->priv; + + addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2; + rtnl_lock(); + t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr); + v = t3_read_reg(adap, A_TP_TM_PIO_DATA); + if (sched & 1) + v >>= 16; + bpt = (v >> 8) & 0xff; + cpt = v & 0xff; + if (!cpt) + len = sprintf(buf, "disabled\n"); + else { + v = (adap->params.vpd.cclk * 1000) / cpt; + len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125); + } + rtnl_unlock(); + return len; +} + +static ssize_t tm_attr_store(struct class_device *cd, const char *buf, + size_t len, int sched) +{ + char *endp; + ssize_t ret; + unsigned int val; + struct adapter *adap = to_net_dev(cd)->priv; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + val = simple_strtoul(buf, &endp, 0); + if (endp == buf || val > 10000000) + return -EINVAL; + + rtnl_lock(); + ret = t3_config_sched(adap, val, sched); + if (!ret) + ret = len; + rtnl_unlock(); + return ret; +} + +#define TM_ATTR(name, sched) \ +static ssize_t show_##name(struct class_device *cd, char *buf) \ +{ \ + return tm_attr_show(cd, buf, sched); \ +} \ +static ssize_t store_##name(struct class_device *cd, const char *buf, size_t len) \ +{ \ + return tm_attr_store(cd, buf, len, sched); \ +} \ +static CLASS_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name) + +TM_ATTR(sched0, 0); +TM_ATTR(sched1, 1); +TM_ATTR(sched2, 2); +TM_ATTR(sched3, 3); +TM_ATTR(sched4, 4); +TM_ATTR(sched5, 5); +TM_ATTR(sched6, 6); +TM_ATTR(sched7, 7); + +static struct attribute *offload_attrs[] = { + &class_device_attr_sched0.attr, + &class_device_attr_sched1.attr, + &class_device_attr_sched2.attr, + &class_device_attr_sched3.attr, + &class_device_attr_sched4.attr, + &class_device_attr_sched5.attr, + &class_device_attr_sched6.attr, + &class_device_attr_sched7.attr, + NULL +}; + +static struct attribute_group offload_attr_group = {.attrs = offload_attrs }; + +/* + * Sends an sk_buff to an offload queue driver + * after dealing with any active network taps. + */ +static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb) +{ + int ret; + + local_bh_disable(); + ret = t3_offload_tx(tdev, skb); + local_bh_enable(); + return ret; +} + +static int write_smt_entry(struct adapter *adapter, int idx) +{ + struct cpl_smt_write_req *req; + struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL); + + if (!skb) + return -ENOMEM; + + req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx)); + req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */ + req->iff = idx; + memset(req->src_mac1, 0, sizeof(req->src_mac1)); + memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN); + skb->priority = 1; + offload_tx(&adapter->tdev, skb); + return 0; +} + +static int init_smt(struct adapter *adapter) +{ + int i; + + for_each_port(adapter, i) + write_smt_entry(adapter, i); + return 0; +} + +static void init_port_mtus(struct adapter *adapter) +{ + unsigned int mtus = adapter->port[0]->mtu; + + if (adapter->port[1]) + mtus |= adapter->port[1]->mtu << 16; + t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus); +} + +static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, + int hi, int port) +{ + struct sk_buff *skb; + struct mngt_pktsched_wr *req; + + skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); + req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; + req->sched = sched; + req->idx = qidx; + req->min = lo; + req->max = hi; + req->binding = port; + t3_mgmt_tx(adap, skb); +} + +static void bind_qsets(struct adapter *adap) +{ + int i, j; + + for_each_port(adap, i) { + const struct port_info *pi = adap2pinfo(adap, i); + + for (j = 0; j < pi->nqsets; ++j) + send_pktsched_cmd(adap, 1, pi->first_qset + j, -1, + -1, i); + } +} + +/** + * cxgb_up - enable the adapter + * @adapter: adapter being enabled + * + * Called when the first port is enabled, this function performs the + * actions necessary to make an adapter operational, such as completing + * the initialization of HW modules, and enabling interrupts. + * + * Must be called with the rtnl lock held. + */ +static int cxgb_up(struct adapter *adap) +{ + int err = 0; + + if (!(adap->flags & FULL_INIT_DONE)) { + err = t3_check_fw_version(adap); + if (err) + goto out; + + err = init_dummy_netdevs(adap); + if (err) + goto out; + + err = t3_init_hw(adap, 0); + if (err) + goto out; + + err = setup_sge_qsets(adap); + if (err) + goto out; + + setup_rss(adap); + adap->flags |= FULL_INIT_DONE; + } + + t3_intr_clear(adap); + + if (adap->flags & USING_MSIX) { + name_msix_vecs(adap); + err = request_irq(adap->msix_info[0].vec, + t3_async_intr_handler, 0, + adap->msix_info[0].desc, adap); + if (err) + goto irq_err; + + if (request_msix_data_irqs(adap)) { + free_irq(adap->msix_info[0].vec, adap); + goto irq_err; + } + } else if ((err = request_irq(adap->pdev->irq, + t3_intr_handler(adap, + adap->sge.qs[0].rspq. + polling), + (adap->flags & USING_MSI) ? 0 : SA_SHIRQ, + adap->name, adap))) + goto irq_err; + + t3_sge_start(adap); + t3_intr_enable(adap); + + if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX) + bind_qsets(adap); + adap->flags |= QUEUES_BOUND; + +out: + return err; +irq_err: + CH_ERR(adap, "request_irq failed, err %d\n", err); + goto out; +} + +/* + * Release resources when all the ports and offloading have been stopped. + */ +static void cxgb_down(struct adapter *adapter) +{ + t3_sge_stop(adapter); + spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */ + t3_intr_disable(adapter); + spin_unlock_irq(&adapter->work_lock); + + if (adapter->flags & USING_MSIX) { + int i, n = 0; + + free_irq(adapter->msix_info[0].vec, adapter); + for_each_port(adapter, i) + n += adap2pinfo(adapter, i)->nqsets; + + for (i = 0; i < n; ++i) + free_irq(adapter->msix_info[i + 1].vec, + &adapter->sge.qs[i]); + } else + free_irq(adapter->pdev->irq, adapter); + + flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */ + quiesce_rx(adapter); +} + +static void schedule_chk_task(struct adapter *adap) +{ + unsigned int timeo; + + timeo = adap->params.linkpoll_period ? + (HZ * adap->params.linkpoll_period) / 10 : + adap->params.stats_update_period * HZ; + if (timeo) + queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo); +} + +static int offload_open(struct net_device *dev) +{ + struct adapter *adapter = dev->priv; + struct t3cdev *tdev = T3CDEV(dev); + int adap_up = adapter->open_device_map & PORT_MASK; + int err = 0; + + if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) + return 0; + + if (!adap_up && (err = cxgb_up(adapter)) < 0) + return err; + + t3_tp_set_offload_mode(adapter, 1); + tdev->lldev = adapter->port[0]; + err = cxgb3_offload_activate(adapter); + if (err) + goto out; + + init_port_mtus(adapter); + t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd, + adapter->params.b_wnd, + adapter->params.rev == 0 ? + adapter->port[0]->mtu : 0xffff); + init_smt(adapter); + + /* Never mind if the next step fails */ + sysfs_create_group(&tdev->lldev->class_dev.kobj, &offload_attr_group); + + /* Call back all registered clients */ + cxgb3_add_clients(tdev); + +out: + /* restore them in case the offload module has changed them */ + if (err) { + t3_tp_set_offload_mode(adapter, 0); + clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); + cxgb3_set_dummy_ops(tdev); + } + return err; +} + +static int offload_close(struct t3cdev *tdev) +{ + struct adapter *adapter = tdev2adap(tdev); + + if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) + return 0; + + /* Call back all registered clients */ + cxgb3_remove_clients(tdev); + + sysfs_remove_group(&tdev->lldev->class_dev.kobj, &offload_attr_group); + + tdev->lldev = NULL; + cxgb3_set_dummy_ops(tdev); + t3_tp_set_offload_mode(adapter, 0); + clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map); + + if (!adapter->open_device_map) + cxgb_down(adapter); + + cxgb3_offload_deactivate(adapter); + return 0; +} + +static int cxgb_open(struct net_device *dev) +{ + int err; + struct adapter *adapter = dev->priv; + struct port_info *pi = netdev_priv(dev); + int other_ports = adapter->open_device_map & PORT_MASK; + + if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) + return err; + + set_bit(pi->port_id, &adapter->open_device_map); + if (!ofld_disable) { + err = offload_open(dev); + if (err) + printk(KERN_WARNING + "Could not initialize offload capabilities\n"); + } + + link_start(dev); + t3_port_intr_enable(adapter, pi->port_id); + netif_start_queue(dev); + if (!other_ports) + schedule_chk_task(adapter); + + return 0; +} + +static int cxgb_close(struct net_device *dev) +{ + struct adapter *adapter = dev->priv; + struct port_info *p = netdev_priv(dev); + + t3_port_intr_disable(adapter, p->port_id); + netif_stop_queue(dev); + p->phy.ops->power_down(&p->phy, 1); + netif_carrier_off(dev); + t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); + + spin_lock(&adapter->work_lock); /* sync with update task */ + clear_bit(p->port_id, &adapter->open_device_map); + spin_unlock(&adapter->work_lock); + + if (!(adapter->open_device_map & PORT_MASK)) + cancel_rearming_delayed_workqueue(cxgb3_wq, + &adapter->adap_check_task); + + if (!adapter->open_device_map) + cxgb_down(adapter); + + return 0; +} + +static struct net_device_stats *cxgb_get_stats(struct net_device *dev) +{ + struct adapter *adapter = dev->priv; + struct port_info *p = netdev_priv(dev); + struct net_device_stats *ns = &p->netstats; + const struct mac_stats *pstats; + + spin_lock(&adapter->stats_lock); + pstats = t3_mac_update_stats(&p->mac); + spin_unlock(&adapter->stats_lock); + + ns->tx_bytes = pstats->tx_octets; + ns->tx_packets = pstats->tx_frames; + ns->rx_bytes = pstats->rx_octets; + ns->rx_packets = pstats->rx_frames; + ns->multicast = pstats->rx_mcast_frames; + + ns->tx_errors = pstats->tx_underrun; + ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs + + pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short + + pstats->rx_fifo_ovfl; + + /* detailed rx_errors */ + ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long; + ns->rx_over_errors = 0; + ns->rx_crc_errors = pstats->rx_fcs_errs; + ns->rx_frame_errors = pstats->rx_symbol_errs; + ns->rx_fifo_errors = pstats->rx_fifo_ovfl; + ns->rx_missed_errors = pstats->rx_cong_drops; + + /* detailed tx_errors */ + ns->tx_aborted_errors = 0; + ns->tx_carrier_errors = 0; + ns->tx_fifo_errors = pstats->tx_underrun; + ns->tx_heartbeat_errors = 0; + ns->tx_window_errors = 0; + return ns; +} + +static u32 get_msglevel(struct net_device *dev) +{ + struct adapter *adapter = dev->priv; + + return adapter->msg_enable; +} + +static void set_msglevel(struct net_device *dev, u32 val) +{ + struct adapter *adapter = dev->priv; + + adapter->msg_enable = val; +} + +static char stats_strings[][ETH_GSTRING_LEN] = { + "TxOctetsOK ", + "TxFramesOK ", + "TxMulticastFramesOK", + "TxBroadcastFramesOK", + "TxPauseFrames ", + "TxUnderrun ", + "TxExtUnderrun ", + + "TxFrames64 ", + "TxFrames65To127 ", + "TxFrames128To255 ", + "TxFrames256To511 ", + "TxFrames512To1023 ", + "TxFrames1024To1518 ", + "TxFrames1519ToMax ", + + "RxOctetsOK ", + "RxFramesOK ", + "RxMulticastFramesOK", + "RxBroadcastFramesOK", + "RxPauseFrames ", + "RxFCSErrors ", + "RxSymbolErrors ", + "RxShortErrors ", + "RxJabberErrors ", + "RxLengthErrors ", + "RxFIFOoverflow ", + + "RxFrames64 ", + "RxFrames65To127 ", + "RxFrames128To255 ", + "RxFrames256To511 ", + "RxFrames512To1023 ", + "RxFrames1024To1518 ", + "RxFrames1519ToMax ", + + "PhyFIFOErrors ", + "TSO ", + "VLANextractions ", + "VLANinsertions ", + "TxCsumOffload ", + "RxCsumGood ", + "RxDrops " +}; + +static int get_stats_count(struct net_device *dev) +{ + return ARRAY_SIZE(stats_strings); +} + +#define T3_REGMAP_SIZE (3 * 1024) + +static int get_regs_len(struct net_device *dev) +{ + return T3_REGMAP_SIZE; +} + +static int get_eeprom_len(struct net_device *dev) +{ + return EEPROMSIZE; +} + +static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + u32 fw_vers = 0; + struct adapter *adapter = dev->priv; + + t3_get_fw_version(adapter, &fw_vers); + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->bus_info, pci_name(adapter->pdev)); + if (!fw_vers) + strcpy(info->fw_version, "N/A"); + else { + snprintf(info->fw_version, sizeof(info->fw_version), + "%s %u.%u.%u", + G_FW_VERSION_TYPE(fw_vers) ? "T" : "N", + G_FW_VERSION_MAJOR(fw_vers), + G_FW_VERSION_MINOR(fw_vers), + G_FW_VERSION_MICRO(fw_vers)); + } +} + +static void get_strings(struct net_device *dev, u32 stringset, u8 * data) +{ + if (stringset == ETH_SS_STATS) + memcpy(data, stats_strings, sizeof(stats_strings)); +} + +static unsigned long collect_sge_port_stats(struct adapter *adapter, + struct port_info *p, int idx) +{ + int i; + unsigned long tot = 0; + + for (i = 0; i < p->nqsets; ++i) + tot += adapter->sge.qs[i + p->first_qset].port_stats[idx]; + return tot; +} + +static void get_stats(struct net_device *dev, struct ethtool_stats *stats, + u64 *data) +{ + struct adapter *adapter = dev->priv; + struct port_info *pi = netdev_priv(dev); + const struct mac_stats *s; + + spin_lock(&adapter->stats_lock); + s = t3_mac_update_stats(&pi->mac); + spin_unlock(&adapter->stats_lock); + + *data++ = s->tx_octets; + *data++ = s->tx_frames; + *data++ = s->tx_mcast_frames; + *data++ = s->tx_bcast_frames; + *data++ = s->tx_pause; + *data++ = s->tx_underrun; + *data++ = s->tx_fifo_urun; + + *data++ = s->tx_frames_64; + *data++ = s->tx_frames_65_127; + *data++ = s->tx_frames_128_255; + *data++ = s->tx_frames_256_511; + *data++ = s->tx_frames_512_1023; + *data++ = s->tx_frames_1024_1518; + *data++ = s->tx_frames_1519_max; + + *data++ = s->rx_octets; + *data++ = s->rx_frames; + *data++ = s->rx_mcast_frames; + *data++ = s->rx_bcast_frames; + *data++ = s->rx_pause; + *data++ = s->rx_fcs_errs; + *data++ = s->rx_symbol_errs; + *data++ = s->rx_short; + *data++ = s->rx_jabber; + *data++ = s->rx_too_long; + *data++ = s->rx_fifo_ovfl; + + *data++ = s->rx_frames_64; + *data++ = s->rx_frames_65_127; + *data++ = s->rx_frames_128_255; + *data++ = s->rx_frames_256_511; + *data++ = s->rx_frames_512_1023; + *data++ = s->rx_frames_1024_1518; + *data++ = s->rx_frames_1519_max; + + *data++ = pi->phy.fifo_errors; + + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM); + *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD); + *data++ = s->rx_cong_drops; +} + +static inline void reg_block_dump(struct adapter *ap, void *buf, + unsigned int start, unsigned int end) +{ + u32 *p = buf + start; + + for (; start <= end; start += sizeof(u32)) + *p++ = t3_read_reg(ap, start); +} + +static void get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *buf) +{ + struct adapter *ap = dev->priv; + + /* + * Version scheme: + * bits 0..9: chip version + * bits 10..15: chip revision + * bit 31: set for PCIe cards + */ + regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31); + + /* + * We skip the MAC statistics registers because they are clear-on-read. + * Also reading multi-register stats would need to synchronize with the + * periodic mac stats accumulation. Hard to justify the complexity. + */ + memset(buf, 0, T3_REGMAP_SIZE); + reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN); + reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT); + reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE); + reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA); + reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3); + reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0, + XGM_REG(A_XGM_SERDES_STAT3, 1)); + reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1), + XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1)); +} + +static int restart_autoneg(struct net_device *dev) +{ + struct port_info *p = netdev_priv(dev); + + if (!netif_running(dev)) + return -EAGAIN; + if (p->link_config.autoneg != AUTONEG_ENABLE) + return -EINVAL; + p->phy.ops->autoneg_restart(&p->phy); + return 0; +} + +static int cxgb3_phys_id(struct net_device *dev, u32 data) +{ + int i; + struct adapter *adapter = dev->priv; + + if (data == 0) + data = 2; + + for (i = 0; i < data * 2; i++) { + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, + (i & 1) ? F_GPIO0_OUT_VAL : 0); + if (msleep_interruptible(500)) + break; + } + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, + F_GPIO0_OUT_VAL); + return 0; +} + +static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct port_info *p = netdev_priv(dev); + + cmd->supported = p->link_config.supported; + cmd->advertising = p->link_config.advertising; + + if (netif_carrier_ok(dev)) { + cmd->speed = p->link_config.speed; + cmd->duplex = p->link_config.duplex; + } else { + cmd->speed = -1; + cmd->duplex = -1; + } + + cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; + cmd->phy_address = p->phy.addr; + cmd->transceiver = XCVR_EXTERNAL; + cmd->autoneg = p->link_config.autoneg; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static int speed_duplex_to_caps(int speed, int duplex) +{ + int cap = 0; + + switch (speed) { + case SPEED_10: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_10baseT_Full; + else + cap = SUPPORTED_10baseT_Half; + break; + case SPEED_100: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_100baseT_Full; + else + cap = SUPPORTED_100baseT_Half; + break; + case SPEED_1000: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_1000baseT_Full; + else + cap = SUPPORTED_1000baseT_Half; + break; + case SPEED_10000: + if (duplex == DUPLEX_FULL) + cap = SUPPORTED_10000baseT_Full; + } + return cap; +} + +#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \ + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \ + ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \ + ADVERTISED_10000baseT_Full) + +static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct port_info *p = netdev_priv(dev); + struct link_config *lc = &p->link_config; + + if (!(lc->supported & SUPPORTED_Autoneg)) + return -EOPNOTSUPP; /* can't change speed/duplex */ + + if (cmd->autoneg == AUTONEG_DISABLE) { + int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex); + + if (!(lc->supported & cap) || cmd->speed == SPEED_1000) + return -EINVAL; + lc->requested_speed = cmd->speed; + lc->requested_duplex = cmd->duplex; + lc->advertising = 0; + } else { + cmd->advertising &= ADVERTISED_MASK; + cmd->advertising &= lc->supported; + if (!cmd->advertising) + return -EINVAL; + lc->requested_speed = SPEED_INVALID; + lc->requested_duplex = DUPLEX_INVALID; + lc->advertising = cmd->advertising | ADVERTISED_Autoneg; + } + lc->autoneg = cmd->autoneg; + if (netif_running(dev)) + t3_link_start(&p->phy, &p->mac, lc); + return 0; +} + +static void get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct port_info *p = netdev_priv(dev); + + epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0; + epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0; + epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0; +} + +static int set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct port_info *p = netdev_priv(dev); + struct link_config *lc = &p->link_config; + + if (epause->autoneg == AUTONEG_DISABLE) + lc->requested_fc = 0; + else if (lc->supported & SUPPORTED_Autoneg) + lc->requested_fc = PAUSE_AUTONEG; + else + return -EINVAL; + + if (epause->rx_pause) + lc->requested_fc |= PAUSE_RX; + if (epause->tx_pause) + lc->requested_fc |= PAUSE_TX; + if (lc->autoneg == AUTONEG_ENABLE) { + if (netif_running(dev)) + t3_link_start(&p->phy, &p->mac, lc); + } else { + lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + if (netif_running(dev)) + t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc); + } + return 0; +} + +static u32 get_rx_csum(struct net_device *dev) +{ + struct port_info *p = netdev_priv(dev); + + return p->rx_csum_offload; +} + +static int set_rx_csum(struct net_device *dev, u32 data) +{ + struct port_info *p = netdev_priv(dev); + + p->rx_csum_offload = data; + return 0; +} + +static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + struct adapter *adapter = dev->priv; + + e->rx_max_pending = MAX_RX_BUFFERS; + e->rx_mini_max_pending = 0; + e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS; + e->tx_max_pending = MAX_TXQ_ENTRIES; + + e->rx_pending = adapter->params.sge.qset[0].fl_size; + e->rx_mini_pending = adapter->params.sge.qset[0].rspq_size; + e->rx_jumbo_pending = adapter->params.sge.qset[0].jumbo_size; + e->tx_pending = adapter->params.sge.qset[0].txq_size[0]; +} + +static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) +{ + int i; + struct adapter *adapter = dev->priv; + + if (e->rx_pending > MAX_RX_BUFFERS || + e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS || + e->tx_pending > MAX_TXQ_ENTRIES || + e->rx_mini_pending > MAX_RSPQ_ENTRIES || + e->rx_mini_pending < MIN_RSPQ_ENTRIES || + e->rx_pending < MIN_FL_ENTRIES || + e->rx_jumbo_pending < MIN_FL_ENTRIES || + e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES) + return -EINVAL; + + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + + for (i = 0; i < SGE_QSETS; ++i) { + struct qset_params *q = &adapter->params.sge.qset[i]; + + q->rspq_size = e->rx_mini_pending; + q->fl_size = e->rx_pending; + q->jumbo_size = e->rx_jumbo_pending; + q->txq_size[0] = e->tx_pending; + q->txq_size[1] = e->tx_pending; + q->txq_size[2] = e->tx_pending; + } + return 0; +} + +static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + struct adapter *adapter = dev->priv; + struct qset_params *qsp = &adapter->params.sge.qset[0]; + struct sge_qset *qs = &adapter->sge.qs[0]; + + if (c->rx_coalesce_usecs * 10 > M_NEWTIMER) + return -EINVAL; + + qsp->coalesce_usecs = c->rx_coalesce_usecs; + t3_update_qset_coalesce(qs, qsp); + return 0; +} + +static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) +{ + struct adapter *adapter = dev->priv; + struct qset_params *q = adapter->params.sge.qset; + + c->rx_coalesce_usecs = q->coalesce_usecs; + return 0; +} + +static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, + u8 * data) +{ + int i, err = 0; + struct adapter *adapter = dev->priv; + + u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + e->magic = EEPROM_MAGIC; + for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) + err = t3_seeprom_read(adapter, i, (u32 *) & buf[i]); + + if (!err) + memcpy(data, buf + e->offset, e->len); + kfree(buf); + return err; +} + +static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, + u8 * data) +{ + u8 *buf; + int err = 0; + u32 aligned_offset, aligned_len, *p; + struct adapter *adapter = dev->priv; + + if (eeprom->magic != EEPROM_MAGIC) + return -EINVAL; + + aligned_offset = eeprom->offset & ~3; + aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3; + + if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) { + buf = kmalloc(aligned_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + err = t3_seeprom_read(adapter, aligned_offset, (u32 *) buf); + if (!err && aligned_len > 4) + err = t3_seeprom_read(adapter, + aligned_offset + aligned_len - 4, + (u32 *) & buf[aligned_len - 4]); + if (err) + goto out; + memcpy(buf + (eeprom->offset & 3), data, eeprom->len); + } else + buf = data; + + err = t3_seeprom_wp(adapter, 0); + if (err) + goto out; + + for (p = (u32 *) buf; !err && aligned_len; aligned_len -= 4, p++) { + err = t3_seeprom_write(adapter, aligned_offset, *p); + aligned_offset += 4; + } + + if (!err) + err = t3_seeprom_wp(adapter, 1); +out: + if (buf != data) + kfree(buf); + return err; +} + +static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + wol->supported = 0; + wol->wolopts = 0; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +static const struct ethtool_ops cxgb_ethtool_ops = { + .get_settings = get_settings, + .set_settings = set_settings, + .get_drvinfo = get_drvinfo, + .get_msglevel = get_msglevel, + .set_msglevel = set_msglevel, + .get_ringparam = get_sge_param, + .set_ringparam = set_sge_param, + .get_coalesce = get_coalesce, + .set_coalesce = set_coalesce, + .get_eeprom_len = get_eeprom_len, + .get_eeprom = get_eeprom, + .set_eeprom = set_eeprom, + .get_pauseparam = get_pauseparam, + .set_pauseparam = set_pauseparam, + .get_rx_csum = get_rx_csum, + .set_rx_csum = set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_link = ethtool_op_get_link, + .get_strings = get_strings, + .phys_id = cxgb3_phys_id, + .nway_reset = restart_autoneg, + .get_stats_count = get_stats_count, + .get_ethtool_stats = get_stats, + .get_regs_len = get_regs_len, + .get_regs = get_regs, + .get_wol = get_wol, + .get_tso = ethtool_op_get_tso, + .set_tso = ethtool_op_set_tso, + .get_perm_addr = ethtool_op_get_perm_addr +}; + +static int in_range(int val, int lo, int hi) +{ + return val < 0 || (val <= hi && val >= lo); +} + +static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) +{ + int ret; + u32 cmd; + struct adapter *adapter = dev->priv; + + if (copy_from_user(&cmd, useraddr, sizeof(cmd))) + return -EFAULT; + + switch (cmd) { + case CHELSIO_SETREG:{ + struct ch_reg edata; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + if ((edata.addr & 3) != 0 + || edata.addr >= adapter->mmio_len) + return -EINVAL; + writel(edata.val, adapter->regs + edata.addr); + break; + } + case CHELSIO_GETREG:{ + struct ch_reg edata; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + if ((edata.addr & 3) != 0 + || edata.addr >= adapter->mmio_len) + return -EINVAL; + edata.val = readl(adapter->regs + edata.addr); + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + break; + } + case CHELSIO_SET_QSET_PARAMS:{ + int i; + struct qset_params *q; + struct ch_qset_params t; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + if (t.qset_idx >= SGE_QSETS) + return -EINVAL; + if (!in_range(t.intr_lat, 0, M_NEWTIMER) || + !in_range(t.cong_thres, 0, 255) || + !in_range(t.txq_size[0], MIN_TXQ_ENTRIES, + MAX_TXQ_ENTRIES) || + !in_range(t.txq_size[1], MIN_TXQ_ENTRIES, + MAX_TXQ_ENTRIES) || + !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES, + MAX_CTRL_TXQ_ENTRIES) || + !in_range(t.fl_size[0], MIN_FL_ENTRIES, + MAX_RX_BUFFERS) + || !in_range(t.fl_size[1], MIN_FL_ENTRIES, + MAX_RX_JUMBO_BUFFERS) + || !in_range(t.rspq_size, MIN_RSPQ_ENTRIES, + MAX_RSPQ_ENTRIES)) + return -EINVAL; + if ((adapter->flags & FULL_INIT_DONE) && + (t.rspq_size >= 0 || t.fl_size[0] >= 0 || + t.fl_size[1] >= 0 || t.txq_size[0] >= 0 || + t.txq_size[1] >= 0 || t.txq_size[2] >= 0 || + t.polling >= 0 || t.cong_thres >= 0)) + return -EBUSY; + + q = &adapter->params.sge.qset[t.qset_idx]; + + if (t.rspq_size >= 0) + q->rspq_size = t.rspq_size; + if (t.fl_size[0] >= 0) + q->fl_size = t.fl_size[0]; + if (t.fl_size[1] >= 0) + q->jumbo_size = t.fl_size[1]; + if (t.txq_size[0] >= 0) + q->txq_size[0] = t.txq_size[0]; + if (t.txq_size[1] >= 0) + q->txq_size[1] = t.txq_size[1]; + if (t.txq_size[2] >= 0) + q->txq_size[2] = t.txq_size[2]; + if (t.cong_thres >= 0) + q->cong_thres = t.cong_thres; + if (t.intr_lat >= 0) { + struct sge_qset *qs = + &adapter->sge.qs[t.qset_idx]; + + q->coalesce_usecs = t.intr_lat; + t3_update_qset_coalesce(qs, q); + } + if (t.polling >= 0) { + if (adapter->flags & USING_MSIX) + q->polling = t.polling; + else { + /* No polling with INTx for T3A */ + if (adapter->params.rev == 0 && + !(adapter->flags & USING_MSI)) + t.polling = 0; + + for (i = 0; i < SGE_QSETS; i++) { + q = &adapter->params.sge. + qset[i]; + q->polling = t.polling; + } + } + } + break; + } + case CHELSIO_GET_QSET_PARAMS:{ + struct qset_params *q; + struct ch_qset_params t; + + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + if (t.qset_idx >= SGE_QSETS) + return -EINVAL; + + q = &adapter->params.sge.qset[t.qset_idx]; + t.rspq_size = q->rspq_size; + t.txq_size[0] = q->txq_size[0]; + t.txq_size[1] = q->txq_size[1]; + t.txq_size[2] = q->txq_size[2]; + t.fl_size[0] = q->fl_size; + t.fl_size[1] = q->jumbo_size; + t.polling = q->polling; + t.intr_lat = q->coalesce_usecs; + t.cong_thres = q->cong_thres; + + if (copy_to_user(useraddr, &t, sizeof(t))) + return -EFAULT; + break; + } + case CHELSIO_SET_QSET_NUM:{ + struct ch_reg edata; + struct port_info *pi = netdev_priv(dev); + unsigned int i, first_qset = 0, other_qsets = 0; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + if (edata.val < 1 || + (edata.val > 1 && !(adapter->flags & USING_MSIX))) + return -EINVAL; + + for_each_port(adapter, i) + if (adapter->port[i] && adapter->port[i] != dev) + other_qsets += adap2pinfo(adapter, i)->nqsets; + + if (edata.val + other_qsets > SGE_QSETS) + return -EINVAL; + + pi->nqsets = edata.val; + + for_each_port(adapter, i) + if (adapter->port[i]) { + pi = adap2pinfo(adapter, i); + pi->first_qset = first_qset; + first_qset += pi->nqsets; + } + break; + } + case CHELSIO_GET_QSET_NUM:{ + struct ch_reg edata; + struct port_info *pi = netdev_priv(dev); + + edata.cmd = CHELSIO_GET_QSET_NUM; + edata.val = pi->nqsets; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + break; + } + case CHELSIO_LOAD_FW:{ + u8 *fw_data; + struct ch_mem_range t; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + + fw_data = kmalloc(t.len, GFP_KERNEL); + if (!fw_data) + return -ENOMEM; + + if (copy_from_user + (fw_data, useraddr + sizeof(t), t.len)) { + kfree(fw_data); + return -EFAULT; + } + + ret = t3_load_fw(adapter, fw_data, t.len); + kfree(fw_data); + if (ret) + return ret; + break; + } + case CHELSIO_SETMTUTAB:{ + struct ch_mtus m; + int i; + + if (!is_offload(adapter)) + return -EOPNOTSUPP; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (offload_running(adapter)) + return -EBUSY; + if (copy_from_user(&m, useraddr, sizeof(m))) + return -EFAULT; + if (m.nmtus != NMTUS) + return -EINVAL; + if (m.mtus[0] < 81) /* accommodate SACK */ + return -EINVAL; + + /* MTUs must be in ascending order */ + for (i = 1; i < NMTUS; ++i) + if (m.mtus[i] < m.mtus[i - 1]) + return -EINVAL; + + memcpy(adapter->params.mtus, m.mtus, + sizeof(adapter->params.mtus)); + break; + } + case CHELSIO_GET_PM:{ + struct tp_params *p = &adapter->params.tp; + struct ch_pm m = {.cmd = CHELSIO_GET_PM }; + + if (!is_offload(adapter)) + return -EOPNOTSUPP; + m.tx_pg_sz = p->tx_pg_size; + m.tx_num_pg = p->tx_num_pgs; + m.rx_pg_sz = p->rx_pg_size; + m.rx_num_pg = p->rx_num_pgs; + m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan; + if (copy_to_user(useraddr, &m, sizeof(m))) + return -EFAULT; + break; + } + case CHELSIO_SET_PM:{ + struct ch_pm m; + struct tp_params *p = &adapter->params.tp; + + if (!is_offload(adapter)) + return -EOPNOTSUPP; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (adapter->flags & FULL_INIT_DONE) + return -EBUSY; + if (copy_from_user(&m, useraddr, sizeof(m))) + return -EFAULT; + if (!m.rx_pg_sz || (m.rx_pg_sz & (m.rx_pg_sz - 1)) || + !m.tx_pg_sz || (m.tx_pg_sz & (m.tx_pg_sz - 1))) + return -EINVAL; /* not power of 2 */ + if (!(m.rx_pg_sz & 0x14000)) + return -EINVAL; /* not 16KB or 64KB */ + if (!(m.tx_pg_sz & 0x1554000)) + return -EINVAL; + if (m.tx_num_pg == -1) + m.tx_num_pg = p->tx_num_pgs; + if (m.rx_num_pg == -1) + m.rx_num_pg = p->rx_num_pgs; + if (m.tx_num_pg % 24 || m.rx_num_pg % 24) + return -EINVAL; + if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size || + m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size) + return -EINVAL; + p->rx_pg_size = m.rx_pg_sz; + p->tx_pg_size = m.tx_pg_sz; + p->rx_num_pgs = m.rx_num_pg; + p->tx_num_pgs = m.tx_num_pg; + break; + } + case CHELSIO_GET_MEM:{ + struct ch_mem_range t; + struct mc7 *mem; + u64 buf[32]; + + if (!is_offload(adapter)) + return -EOPNOTSUPP; + if (!(adapter->flags & FULL_INIT_DONE)) + return -EIO; /* need the memory controllers */ + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + if ((t.addr & 7) || (t.len & 7)) + return -EINVAL; + if (t.mem_id == MEM_CM) + mem = &adapter->cm; + else if (t.mem_id == MEM_PMRX) + mem = &adapter->pmrx; + else if (t.mem_id == MEM_PMTX) + mem = &adapter->pmtx; + else + return -EINVAL; + + /* + * Version scheme: + * bits 0..9: chip version + * bits 10..15: chip revision + */ + t.version = 3 | (adapter->params.rev << 10); + if (copy_to_user(useraddr, &t, sizeof(t))) + return -EFAULT; + + /* + * Read 256 bytes at a time as len can be large and we don't + * want to use huge intermediate buffers. + */ + useraddr += sizeof(t); /* advance to start of buffer */ + while (t.len) { + unsigned int chunk = + min_t(unsigned int, t.len, sizeof(buf)); + + ret = + t3_mc7_bd_read(mem, t.addr / 8, chunk / 8, + buf); + if (ret) + return ret; + if (copy_to_user(useraddr, buf, chunk)) + return -EFAULT; + useraddr += chunk; + t.addr += chunk; + t.len -= chunk; + } + break; + } + case CHELSIO_SET_TRACE_FILTER:{ + struct ch_trace t; + const struct trace_params *tp; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!offload_running(adapter)) + return -EAGAIN; + if (copy_from_user(&t, useraddr, sizeof(t))) + return -EFAULT; + + tp = (const struct trace_params *)&t.sip; + if (t.config_tx) + t3_config_trace_filter(adapter, tp, 0, + t.invert_match, + t.trace_tx); + if (t.config_rx) + t3_config_trace_filter(adapter, tp, 1, + t.invert_match, + t.trace_rx); + break; + } + case CHELSIO_SET_PKTSCHED:{ + struct ch_pktsched_params p; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!adapter->open_device_map) + return -EAGAIN; /* uP and SGE must be running */ + if (copy_from_user(&p, useraddr, sizeof(p))) + return -EFAULT; + send_pktsched_cmd(adapter, p.sched, p.idx, p.min, p.max, + p.binding); + break; + + } + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + int ret, mmd; + struct adapter *adapter = dev->priv; + struct port_info *pi = netdev_priv(dev); + struct mii_ioctl_data *data = if_mii(req); + + switch (cmd) { + case SIOCGMIIPHY: + data->phy_id = pi->phy.addr; + /* FALLTHRU */ + case SIOCGMIIREG:{ + u32 val; + struct cphy *phy = &pi->phy; + + if (!phy->mdio_read) + return -EOPNOTSUPP; + if (is_10G(adapter)) { + mmd = data->phy_id >> 8; + if (!mmd) + mmd = MDIO_DEV_PCS; + else if (mmd > MDIO_DEV_XGXS) + return -EINVAL; + + ret = + phy->mdio_read(adapter, data->phy_id & 0x1f, + mmd, data->reg_num, &val); + } else + ret = + phy->mdio_read(adapter, data->phy_id & 0x1f, + 0, data->reg_num & 0x1f, + &val); + if (!ret) + data->val_out = val; + break; + } + case SIOCSMIIREG:{ + struct cphy *phy = &pi->phy; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!phy->mdio_write) + return -EOPNOTSUPP; + if (is_10G(adapter)) { + mmd = data->phy_id >> 8; + if (!mmd) + mmd = MDIO_DEV_PCS; + else if (mmd > MDIO_DEV_XGXS) + return -EINVAL; + + ret = + phy->mdio_write(adapter, + data->phy_id & 0x1f, mmd, + data->reg_num, + data->val_in); + } else + ret = + phy->mdio_write(adapter, + data->phy_id & 0x1f, 0, + data->reg_num & 0x1f, + data->val_in); + break; + } + case SIOCCHIOCTL: + return cxgb_extension_ioctl(dev, req->ifr_data); + default: + return -EOPNOTSUPP; + } + return ret; +} + +static int cxgb_change_mtu(struct net_device *dev, int new_mtu) +{ + int ret; + struct adapter *adapter = dev->priv; + struct port_info *pi = netdev_priv(dev); + + if (new_mtu < 81) /* accommodate SACK */ + return -EINVAL; + if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu))) + return ret; + dev->mtu = new_mtu; + init_port_mtus(adapter); + if (adapter->params.rev == 0 && offload_running(adapter)) + t3_load_mtus(adapter, adapter->params.mtus, + adapter->params.a_wnd, adapter->params.b_wnd, + adapter->port[0]->mtu); + return 0; +} + +static int cxgb_set_mac_addr(struct net_device *dev, void *p) +{ + struct adapter *adapter = dev->priv; + struct port_info *pi = netdev_priv(dev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + t3_mac_set_address(&pi->mac, 0, dev->dev_addr); + if (offload_running(adapter)) + write_smt_entry(adapter, pi->port_id); + return 0; +} + +/** + * t3_synchronize_rx - wait for current Rx processing on a port to complete + * @adap: the adapter + * @p: the port + * + * Ensures that current Rx processing on any of the queues associated with + * the given port completes before returning. We do this by acquiring and + * releasing the locks of the response queues associated with the port. + */ +static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p) +{ + int i; + + for (i = 0; i < p->nqsets; i++) { + struct sge_rspq *q = &adap->sge.qs[i + p->first_qset].rspq; + + spin_lock_irq(&q->lock); + spin_unlock_irq(&q->lock); + } +} + +static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp) +{ + struct adapter *adapter = dev->priv; + struct port_info *pi = netdev_priv(dev); + + pi->vlan_grp = grp; + if (adapter->params.rev > 0) + t3_set_vlan_accel(adapter, 1 << pi->port_id, grp != NULL); + else { + /* single control for all ports */ + unsigned int i, have_vlans = 0; + for_each_port(adapter, i) + have_vlans |= adap2pinfo(adapter, i)->vlan_grp != NULL; + + t3_set_vlan_accel(adapter, 1, have_vlans); + } + t3_synchronize_rx(adapter, pi); +} + +static void vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) +{ + /* nothing */ +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void cxgb_netpoll(struct net_device *dev) +{ + struct adapter *adapter = dev->priv; + struct sge_qset *qs = dev2qset(dev); + + t3_intr_handler(adapter, qs->rspq.polling) (adapter->pdev->irq, + adapter); +} +#endif + +/* + * Periodic accumulation of MAC statistics. + */ +static void mac_stats_update(struct adapter *adapter) +{ + int i; + + for_each_port(adapter, i) { + struct net_device *dev = adapter->port[i]; + struct port_info *p = netdev_priv(dev); + + if (netif_running(dev)) { + spin_lock(&adapter->stats_lock); + t3_mac_update_stats(&p->mac); + spin_unlock(&adapter->stats_lock); + } + } +} + +static void check_link_status(struct adapter *adapter) +{ + int i; + + for_each_port(adapter, i) { + struct net_device *dev = adapter->port[i]; + struct port_info *p = netdev_priv(dev); + + if (!(p->port_type->caps & SUPPORTED_IRQ) && netif_running(dev)) + t3_link_changed(adapter, i); + } +} + +static void t3_adap_check_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + adap_check_task.work); + const struct adapter_params *p = &adapter->params; + + adapter->check_task_cnt++; + + /* Check link status for PHYs without interrupts */ + if (p->linkpoll_period) + check_link_status(adapter); + + /* Accumulate MAC stats if needed */ + if (!p->linkpoll_period || + (adapter->check_task_cnt * p->linkpoll_period) / 10 >= + p->stats_update_period) { + mac_stats_update(adapter); + adapter->check_task_cnt = 0; + } + + /* Schedule the next check update if any port is active. */ + spin_lock(&adapter->work_lock); + if (adapter->open_device_map & PORT_MASK) + schedule_chk_task(adapter); + spin_unlock(&adapter->work_lock); +} + +/* + * Processes external (PHY) interrupts in process context. + */ +static void ext_intr_task(struct work_struct *work) +{ + struct adapter *adapter = container_of(work, struct adapter, + ext_intr_handler_task); + + t3_phy_intr_handler(adapter); + + /* Now reenable external interrupts */ + spin_lock_irq(&adapter->work_lock); + if (adapter->slow_intr_mask) { + adapter->slow_intr_mask |= F_T3DBG; + t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG); + t3_write_reg(adapter, A_PL_INT_ENABLE0, + adapter->slow_intr_mask); + } + spin_unlock_irq(&adapter->work_lock); +} + +/* + * Interrupt-context handler for external (PHY) interrupts. + */ +void t3_os_ext_intr_handler(struct adapter *adapter) +{ + /* + * Schedule a task to handle external interrupts as they may be slow + * and we use a mutex to protect MDIO registers. We disable PHY + * interrupts in the meantime and let the task reenable them when + * it's done. + */ + spin_lock(&adapter->work_lock); + if (adapter->slow_intr_mask) { + adapter->slow_intr_mask &= ~F_T3DBG; + t3_write_reg(adapter, A_PL_INT_ENABLE0, + adapter->slow_intr_mask); + queue_work(cxgb3_wq, &adapter->ext_intr_handler_task); + } + spin_unlock(&adapter->work_lock); +} + +void t3_fatal_err(struct adapter *adapter) +{ + unsigned int fw_status[4]; + + if (adapter->flags & FULL_INIT_DONE) { + t3_sge_stop(adapter); + t3_intr_disable(adapter); + } + CH_ALERT(adapter, "encountered fatal error, operation suspended\n"); + if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status)) + CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n", + fw_status[0], fw_status[1], + fw_status[2], fw_status[3]); + +} + +static int __devinit cxgb_enable_msix(struct adapter *adap) +{ + struct msix_entry entries[SGE_QSETS + 1]; + int i, err; + + for (i = 0; i < ARRAY_SIZE(entries); ++i) + entries[i].entry = i; + + err = pci_enable_msix(adap->pdev, entries, ARRAY_SIZE(entries)); + if (!err) { + for (i = 0; i < ARRAY_SIZE(entries); ++i) + adap->msix_info[i].vec = entries[i].vector; + } else if (err > 0) + dev_info(&adap->pdev->dev, + "only %d MSI-X vectors left, not using MSI-X\n", err); + return err; +} + +static void __devinit print_port_info(struct adapter *adap, + const struct adapter_info *ai) +{ + static const char *pci_variant[] = { + "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express" + }; + + int i; + char buf[80]; + + if (is_pcie(adap)) + snprintf(buf, sizeof(buf), "%s x%d", + pci_variant[adap->params.pci.variant], + adap->params.pci.width); + else + snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit", + pci_variant[adap->params.pci.variant], + adap->params.pci.speed, adap->params.pci.width); + + for_each_port(adap, i) { + struct net_device *dev = adap->port[i]; + const struct port_info *pi = netdev_priv(dev); + + if (!test_bit(i, &adap->registered_device_map)) + continue; + printk(KERN_INFO "%s: %s %s RNIC (rev %d) %s%s\n", + dev->name, ai->desc, pi->port_type->desc, + adap->params.rev, buf, + (adap->flags & USING_MSIX) ? " MSI-X" : + (adap->flags & USING_MSI) ? " MSI" : ""); + if (adap->name == dev->name && adap->params.vpd.mclk) + printk(KERN_INFO "%s: %uMB CM, %uMB PMTX, %uMB PMRX\n", + adap->name, t3_mc7_size(&adap->cm) >> 20, + t3_mc7_size(&adap->pmtx) >> 20, + t3_mc7_size(&adap->pmrx) >> 20); + } +} + +static int __devinit init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int version_printed; + + int i, err, pci_using_dac = 0; + unsigned long mmio_start, mmio_len; + const struct adapter_info *ai; + struct adapter *adapter = NULL; + struct port_info *pi; + + if (!version_printed) { + printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION); + ++version_printed; + } + + if (!cxgb3_wq) { + cxgb3_wq = create_singlethread_workqueue(DRV_NAME); + if (!cxgb3_wq) { + printk(KERN_ERR DRV_NAME + ": cannot initialize work queue\n"); + return -ENOMEM; + } + } + + err = pci_request_regions(pdev, DRV_NAME); + if (err) { + /* Just info, some other driver may have claimed the device. */ + dev_info(&pdev->dev, "cannot obtain PCI resources\n"); + return err; + } + + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "cannot enable PCI device\n"); + goto out_release_regions; + } + + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { + pci_using_dac = 1; + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (err) { + dev_err(&pdev->dev, "unable to obtain 64-bit DMA for " + "coherent allocations\n"); + goto out_disable_device; + } + } else if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) { + dev_err(&pdev->dev, "no usable DMA configuration\n"); + goto out_disable_device; + } + + pci_set_master(pdev); + + mmio_start = pci_resource_start(pdev, 0); + mmio_len = pci_resource_len(pdev, 0); + ai = t3_get_adapter_info(ent->driver_data); + + adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); + if (!adapter) { + err = -ENOMEM; + goto out_disable_device; + } + + adapter->regs = ioremap_nocache(mmio_start, mmio_len); + if (!adapter->regs) { + dev_err(&pdev->dev, "cannot map device registers\n"); + err = -ENOMEM; + goto out_free_adapter; + } + + adapter->pdev = pdev; + adapter->name = pci_name(pdev); + adapter->msg_enable = dflt_msg_enable; + adapter->mmio_len = mmio_len; + + mutex_init(&adapter->mdio_lock); + spin_lock_init(&adapter->work_lock); + spin_lock_init(&adapter->stats_lock); + + INIT_LIST_HEAD(&adapter->adapter_list); + INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task); + INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task); + + for (i = 0; i < ai->nports; ++i) { + struct net_device *netdev; + + netdev = alloc_etherdev(sizeof(struct port_info)); + if (!netdev) { + err = -ENOMEM; + goto out_free_dev; + } + + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &pdev->dev); + + adapter->port[i] = netdev; + pi = netdev_priv(netdev); + pi->rx_csum_offload = 1; + pi->nqsets = 1; + pi->first_qset = i; + pi->activity = 0; + pi->port_id = i; + netif_carrier_off(netdev); + netdev->irq = pdev->irq; + netdev->mem_start = mmio_start; + netdev->mem_end = mmio_start + mmio_len - 1; + netdev->priv = adapter; + netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; + netdev->features |= NETIF_F_LLTX; + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + netdev->vlan_rx_register = vlan_rx_register; + netdev->vlan_rx_kill_vid = vlan_rx_kill_vid; + + netdev->open = cxgb_open; + netdev->stop = cxgb_close; + netdev->hard_start_xmit = t3_eth_xmit; + netdev->get_stats = cxgb_get_stats; + netdev->set_multicast_list = cxgb_set_rxmode; + netdev->do_ioctl = cxgb_ioctl; + netdev->change_mtu = cxgb_change_mtu; + netdev->set_mac_address = cxgb_set_mac_addr; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = cxgb_netpoll; +#endif + netdev->weight = 64; + + SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); + } + + pci_set_drvdata(pdev, adapter->port[0]); + if (t3_prep_adapter(adapter, ai, 1) < 0) { + err = -ENODEV; + goto out_free_dev; + } + + /* + * The card is now ready to go. If any errors occur during device + * registration we do not fail the whole card but rather proceed only + * with the ports we manage to register successfully. However we must + * register at least one net device. + */ + for_each_port(adapter, i) { + err = register_netdev(adapter->port[i]); + if (err) + dev_warn(&pdev->dev, + "cannot register net device %s, skipping\n", + adapter->port[i]->name); + else { + /* + * Change the name we use for messages to the name of + * the first successfully registered interface. + */ + if (!adapter->registered_device_map) + adapter->name = adapter->port[i]->name; + + __set_bit(i, &adapter->registered_device_map); + } + } + if (!adapter->registered_device_map) { + dev_err(&pdev->dev, "could not register any net devices\n"); + goto out_free_dev; + } + + /* Driver's ready. Reflect it on LEDs */ + t3_led_ready(adapter); + + if (is_offload(adapter)) { + __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map); + cxgb3_adapter_ofld(adapter); + } + + /* See what interrupts we'll be using */ + if (msi > 1 && cxgb_enable_msix(adapter) == 0) + adapter->flags |= USING_MSIX; + else if (msi > 0 && pci_enable_msi(pdev) == 0) + adapter->flags |= USING_MSI; + + err = sysfs_create_group(&adapter->port[0]->class_dev.kobj, + &cxgb3_attr_group); + + print_port_info(adapter, ai); + return 0; + +out_free_dev: + iounmap(adapter->regs); + for (i = ai->nports - 1; i >= 0; --i) + if (adapter->port[i]) + free_netdev(adapter->port[i]); + +out_free_adapter: + kfree(adapter); + +out_disable_device: + pci_disable_device(pdev); +out_release_regions: + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + return err; +} + +static void __devexit remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + int i; + struct adapter *adapter = dev->priv; + + t3_sge_stop(adapter); + sysfs_remove_group(&adapter->port[0]->class_dev.kobj, + &cxgb3_attr_group); + + for_each_port(adapter, i) + if (test_bit(i, &adapter->registered_device_map)) + unregister_netdev(adapter->port[i]); + + if (is_offload(adapter)) { + cxgb3_adapter_unofld(adapter); + if (test_bit(OFFLOAD_DEVMAP_BIT, + &adapter->open_device_map)) + offload_close(&adapter->tdev); + } + + t3_free_sge_resources(adapter); + cxgb_disable_msi(adapter); + + for (i = 0; i < ARRAY_SIZE(adapter->dummy_netdev); i++) + if (adapter->dummy_netdev[i]) { + free_netdev(adapter->dummy_netdev[i]); + adapter->dummy_netdev[i] = NULL; + } + + for_each_port(adapter, i) + if (adapter->port[i]) + free_netdev(adapter->port[i]); + + iounmap(adapter->regs); + kfree(adapter); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } +} + +static struct pci_driver driver = { + .name = DRV_NAME, + .id_table = cxgb3_pci_tbl, + .probe = init_one, + .remove = __devexit_p(remove_one), +}; + +static int __init cxgb3_init_module(void) +{ + int ret; + + cxgb3_offload_init(); + + ret = pci_register_driver(&driver); + return ret; +} + +static void __exit cxgb3_cleanup_module(void) +{ + pci_unregister_driver(&driver); + if (cxgb3_wq) + destroy_workqueue(cxgb3_wq); +} + +module_init(cxgb3_init_module); +module_exit(cxgb3_cleanup_module); diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c new file mode 100644 index 000000000000..c3a02d613382 --- /dev/null +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -0,0 +1,1222 @@ +/* + * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "regs.h" +#include "cxgb3_ioctl.h" +#include "cxgb3_ctl_defs.h" +#include "cxgb3_defs.h" +#include "l2t.h" +#include "firmware_exports.h" +#include "cxgb3_offload.h" + +static LIST_HEAD(client_list); +static LIST_HEAD(ofld_dev_list); +static DEFINE_MUTEX(cxgb3_db_lock); + +static DEFINE_RWLOCK(adapter_list_lock); +static LIST_HEAD(adapter_list); + +static const unsigned int MAX_ATIDS = 64 * 1024; +static const unsigned int ATID_BASE = 0x100000; + +static inline int offload_activated(struct t3cdev *tdev) +{ + const struct adapter *adapter = tdev2adap(tdev); + + return (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)); +} + +/** + * cxgb3_register_client - register an offload client + * @client: the client + * + * Add the client to the client list, + * and call backs the client for each activated offload device + */ +void cxgb3_register_client(struct cxgb3_client *client) +{ + struct t3cdev *tdev; + + mutex_lock(&cxgb3_db_lock); + list_add_tail(&client->client_list, &client_list); + + if (client->add) { + list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) { + if (offload_activated(tdev)) + client->add(tdev); + } + } + mutex_unlock(&cxgb3_db_lock); +} + +EXPORT_SYMBOL(cxgb3_register_client); + +/** + * cxgb3_unregister_client - unregister an offload client + * @client: the client + * + * Remove the client to the client list, + * and call backs the client for each activated offload device. + */ +void cxgb3_unregister_client(struct cxgb3_client *client) +{ + struct t3cdev *tdev; + + mutex_lock(&cxgb3_db_lock); + list_del(&client->client_list); + + if (client->remove) { + list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) { + if (offload_activated(tdev)) + client->remove(tdev); + } + } + mutex_unlock(&cxgb3_db_lock); +} + +EXPORT_SYMBOL(cxgb3_unregister_client); + +/** + * cxgb3_add_clients - activate registered clients for an offload device + * @tdev: the offload device + * + * Call backs all registered clients once a offload device is activated + */ +void cxgb3_add_clients(struct t3cdev *tdev) +{ + struct cxgb3_client *client; + + mutex_lock(&cxgb3_db_lock); + list_for_each_entry(client, &client_list, client_list) { + if (client->add) + client->add(tdev); + } + mutex_unlock(&cxgb3_db_lock); +} + +/** + * cxgb3_remove_clients - deactivates registered clients + * for an offload device + * @tdev: the offload device + * + * Call backs all registered clients once a offload device is deactivated + */ +void cxgb3_remove_clients(struct t3cdev *tdev) +{ + struct cxgb3_client *client; + + mutex_lock(&cxgb3_db_lock); + list_for_each_entry(client, &client_list, client_list) { + if (client->remove) + client->remove(tdev); + } + mutex_unlock(&cxgb3_db_lock); +} + +static struct net_device *get_iff_from_mac(struct adapter *adapter, + const unsigned char *mac, + unsigned int vlan) +{ + int i; + + for_each_port(adapter, i) { + const struct vlan_group *grp; + struct net_device *dev = adapter->port[i]; + const struct port_info *p = netdev_priv(dev); + + if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) { + if (vlan && vlan != VLAN_VID_MASK) { + grp = p->vlan_grp; + dev = grp ? grp->vlan_devices[vlan] : NULL; + } else + while (dev->master) + dev = dev->master; + return dev; + } + } + return NULL; +} + +static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req, + void *data) +{ + int ret = 0; + struct ulp_iscsi_info *uiip = data; + + switch (req) { + case ULP_ISCSI_GET_PARAMS: + uiip->pdev = adapter->pdev; + uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT); + uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT); + uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK); + /* + * On tx, the iscsi pdu has to be <= tx page size and has to + * fit into the Tx PM FIFO. + */ + uiip->max_txsz = min(adapter->params.tp.tx_pg_size, + t3_read_reg(adapter, A_PM1_TX_CFG) >> 17); + /* on rx, the iscsi pdu has to be < rx page size and the + whole pdu + cpl headers has to fit into one sge buffer */ + uiip->max_rxsz = min_t(unsigned int, + adapter->params.tp.rx_pg_size, + (adapter->sge.qs[0].fl[1].buf_size - + sizeof(struct cpl_rx_data) * 2 - + sizeof(struct cpl_rx_data_ddp))); + break; + case ULP_ISCSI_SET_PARAMS: + t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask); + break; + default: + ret = -EOPNOTSUPP; + } + return ret; +} + +/* Response queue used for RDMA events. */ +#define ASYNC_NOTIF_RSPQ 0 + +static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data) +{ + int ret = 0; + + switch (req) { + case RDMA_GET_PARAMS:{ + struct rdma_info *req = data; + struct pci_dev *pdev = adapter->pdev; + + req->udbell_physbase = pci_resource_start(pdev, 2); + req->udbell_len = pci_resource_len(pdev, 2); + req->tpt_base = + t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT); + req->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT); + req->pbl_base = + t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT); + req->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT); + req->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT); + req->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT); + req->kdb_addr = adapter->regs + A_SG_KDOORBELL; + req->pdev = pdev; + break; + } + case RDMA_CQ_OP:{ + unsigned long flags; + struct rdma_cq_op *req = data; + + /* may be called in any context */ + spin_lock_irqsave(&adapter->sge.reg_lock, flags); + ret = t3_sge_cqcntxt_op(adapter, req->id, req->op, + req->credits); + spin_unlock_irqrestore(&adapter->sge.reg_lock, flags); + break; + } + case RDMA_GET_MEM:{ + struct ch_mem_range *t = data; + struct mc7 *mem; + + if ((t->addr & 7) || (t->len & 7)) + return -EINVAL; + if (t->mem_id == MEM_CM) + mem = &adapter->cm; + else if (t->mem_id == MEM_PMRX) + mem = &adapter->pmrx; + else if (t->mem_id == MEM_PMTX) + mem = &adapter->pmtx; + else + return -EINVAL; + + ret = + t3_mc7_bd_read(mem, t->addr / 8, t->len / 8, + (u64 *) t->buf); + if (ret) + return ret; + break; + } + case RDMA_CQ_SETUP:{ + struct rdma_cq_setup *req = data; + + spin_lock_irq(&adapter->sge.reg_lock); + ret = + t3_sge_init_cqcntxt(adapter, req->id, + req->base_addr, req->size, + ASYNC_NOTIF_RSPQ, + req->ovfl_mode, req->credits, + req->credit_thres); + spin_unlock_irq(&adapter->sge.reg_lock); + break; + } + case RDMA_CQ_DISABLE: + spin_lock_irq(&adapter->sge.reg_lock); + ret = t3_sge_disable_cqcntxt(adapter, *(unsigned int *)data); + spin_unlock_irq(&adapter->sge.reg_lock); + break; + case RDMA_CTRL_QP_SETUP:{ + struct rdma_ctrlqp_setup *req = data; + + spin_lock_irq(&adapter->sge.reg_lock); + ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0, + SGE_CNTXT_RDMA, + ASYNC_NOTIF_RSPQ, + req->base_addr, req->size, + FW_RI_TID_START, 1, 0); + spin_unlock_irq(&adapter->sge.reg_lock); + break; + } + default: + ret = -EOPNOTSUPP; + } + return ret; +} + +static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data) +{ + struct adapter *adapter = tdev2adap(tdev); + struct tid_range *tid; + struct mtutab *mtup; + struct iff_mac *iffmacp; + struct ddp_params *ddpp; + struct adap_ports *ports; + int i; + + switch (req) { + case GET_MAX_OUTSTANDING_WR: + *(unsigned int *)data = FW_WR_NUM; + break; + case GET_WR_LEN: + *(unsigned int *)data = WR_FLITS; + break; + case GET_TX_MAX_CHUNK: + *(unsigned int *)data = 1 << 20; /* 1MB */ + break; + case GET_TID_RANGE: + tid = data; + tid->num = t3_mc5_size(&adapter->mc5) - + adapter->params.mc5.nroutes - + adapter->params.mc5.nfilters - adapter->params.mc5.nservers; + tid->base = 0; + break; + case GET_STID_RANGE: + tid = data; + tid->num = adapter->params.mc5.nservers; + tid->base = t3_mc5_size(&adapter->mc5) - tid->num - + adapter->params.mc5.nfilters - adapter->params.mc5.nroutes; + break; + case GET_L2T_CAPACITY: + *(unsigned int *)data = 2048; + break; + case GET_MTUS: + mtup = data; + mtup->size = NMTUS; + mtup->mtus = adapter->params.mtus; + break; + case GET_IFF_FROM_MAC: + iffmacp = data; + iffmacp->dev = get_iff_from_mac(adapter, iffmacp->mac_addr, + iffmacp->vlan_tag & + VLAN_VID_MASK); + break; + case GET_DDP_PARAMS: + ddpp = data; + ddpp->llimit = t3_read_reg(adapter, A_ULPRX_TDDP_LLIMIT); + ddpp->ulimit = t3_read_reg(adapter, A_ULPRX_TDDP_ULIMIT); + ddpp->tag_mask = t3_read_reg(adapter, A_ULPRX_TDDP_TAGMASK); + break; + case GET_PORTS: + ports = data; + ports->nports = adapter->params.nports; + for_each_port(adapter, i) + ports->lldevs[i] = adapter->port[i]; + break; + case ULP_ISCSI_GET_PARAMS: + case ULP_ISCSI_SET_PARAMS: + if (!offload_running(adapter)) + return -EAGAIN; + return cxgb_ulp_iscsi_ctl(adapter, req, data); + case RDMA_GET_PARAMS: + case RDMA_CQ_OP: + case RDMA_CQ_SETUP: + case RDMA_CQ_DISABLE: + case RDMA_CTRL_QP_SETUP: + case RDMA_GET_MEM: + if (!offload_running(adapter)) + return -EAGAIN; + return cxgb_rdma_ctl(adapter, req, data); + default: + return -EOPNOTSUPP; + } + return 0; +} + +/* + * Dummy handler for Rx offload packets in case we get an offload packet before + * proper processing is setup. This complains and drops the packet as it isn't + * normal to get offload packets at this stage. + */ +static int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs, + int n) +{ + CH_ERR(tdev2adap(dev), "%d unexpected offload packets, first data %u\n", + n, ntohl(*(u32 *)skbs[0]->data)); + while (n--) + dev_kfree_skb_any(skbs[n]); + return 0; +} + +static void dummy_neigh_update(struct t3cdev *dev, struct neighbour *neigh) +{ +} + +void cxgb3_set_dummy_ops(struct t3cdev *dev) +{ + dev->recv = rx_offload_blackhole; + dev->neigh_update = dummy_neigh_update; +} + +/* + * Free an active-open TID. + */ +void *cxgb3_free_atid(struct t3cdev *tdev, int atid) +{ + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + union active_open_entry *p = atid2entry(t, atid); + void *ctx = p->t3c_tid.ctx; + + spin_lock_bh(&t->atid_lock); + p->next = t->afree; + t->afree = p; + t->atids_in_use--; + spin_unlock_bh(&t->atid_lock); + + return ctx; +} + +EXPORT_SYMBOL(cxgb3_free_atid); + +/* + * Free a server TID and return it to the free pool. + */ +void cxgb3_free_stid(struct t3cdev *tdev, int stid) +{ + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + union listen_entry *p = stid2entry(t, stid); + + spin_lock_bh(&t->stid_lock); + p->next = t->sfree; + t->sfree = p; + t->stids_in_use--; + spin_unlock_bh(&t->stid_lock); +} + +EXPORT_SYMBOL(cxgb3_free_stid); + +void cxgb3_insert_tid(struct t3cdev *tdev, struct cxgb3_client *client, + void *ctx, unsigned int tid) +{ + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + + t->tid_tab[tid].client = client; + t->tid_tab[tid].ctx = ctx; + atomic_inc(&t->tids_in_use); +} + +EXPORT_SYMBOL(cxgb3_insert_tid); + +/* + * Populate a TID_RELEASE WR. The skb must be already propely sized. + */ +static inline void mk_tid_release(struct sk_buff *skb, unsigned int tid) +{ + struct cpl_tid_release *req; + + skb->priority = CPL_PRIORITY_SETUP; + req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid)); +} + +static void t3_process_tid_release_list(struct work_struct *work) +{ + struct t3c_data *td = container_of(work, struct t3c_data, + tid_release_task); + struct sk_buff *skb; + struct t3cdev *tdev = td->dev; + + + spin_lock_bh(&td->tid_release_lock); + while (td->tid_release_list) { + struct t3c_tid_entry *p = td->tid_release_list; + + td->tid_release_list = (struct t3c_tid_entry *)p->ctx; + spin_unlock_bh(&td->tid_release_lock); + + skb = alloc_skb(sizeof(struct cpl_tid_release), + GFP_KERNEL | __GFP_NOFAIL); + mk_tid_release(skb, p - td->tid_maps.tid_tab); + cxgb3_ofld_send(tdev, skb); + p->ctx = NULL; + spin_lock_bh(&td->tid_release_lock); + } + spin_unlock_bh(&td->tid_release_lock); +} + +/* use ctx as a next pointer in the tid release list */ +void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid) +{ + struct t3c_data *td = T3C_DATA(tdev); + struct t3c_tid_entry *p = &td->tid_maps.tid_tab[tid]; + + spin_lock_bh(&td->tid_release_lock); + p->ctx = (void *)td->tid_release_list; + td->tid_release_list = p; + if (!p->ctx) + schedule_work(&td->tid_release_task); + spin_unlock_bh(&td->tid_release_lock); +} + +EXPORT_SYMBOL(cxgb3_queue_tid_release); + +/* + * Remove a tid from the TID table. A client may defer processing its last + * CPL message if it is locked at the time it arrives, and while the message + * sits in the client's backlog the TID may be reused for another connection. + * To handle this we atomically switch the TID association if it still points + * to the original client context. + */ +void cxgb3_remove_tid(struct t3cdev *tdev, void *ctx, unsigned int tid) +{ + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + + BUG_ON(tid >= t->ntids); + if (tdev->type == T3A) + (void)cmpxchg(&t->tid_tab[tid].ctx, ctx, NULL); + else { + struct sk_buff *skb; + + skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC); + if (likely(skb)) { + mk_tid_release(skb, tid); + cxgb3_ofld_send(tdev, skb); + t->tid_tab[tid].ctx = NULL; + } else + cxgb3_queue_tid_release(tdev, tid); + } + atomic_dec(&t->tids_in_use); +} + +EXPORT_SYMBOL(cxgb3_remove_tid); + +int cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client, + void *ctx) +{ + int atid = -1; + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + + spin_lock_bh(&t->atid_lock); + if (t->afree) { + union active_open_entry *p = t->afree; + + atid = (p - t->atid_tab) + t->atid_base; + t->afree = p->next; + p->t3c_tid.ctx = ctx; + p->t3c_tid.client = client; + t->atids_in_use++; + } + spin_unlock_bh(&t->atid_lock); + return atid; +} + +EXPORT_SYMBOL(cxgb3_alloc_atid); + +int cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client, + void *ctx) +{ + int stid = -1; + struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; + + spin_lock_bh(&t->stid_lock); + if (t->sfree) { + union listen_entry *p = t->sfree; + + stid = (p - t->stid_tab) + t->stid_base; + t->sfree = p->next; + p->t3c_tid.ctx = ctx; + p->t3c_tid.client = client; + t->stids_in_use++; + } + spin_unlock_bh(&t->stid_lock); + return stid; +} + +EXPORT_SYMBOL(cxgb3_alloc_stid); + +static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_smt_write_rpl *rpl = cplhdr(skb); + + if (rpl->status != CPL_ERR_NONE) + printk(KERN_ERR + "Unexpected SMT_WRITE_RPL status %u for entry %u\n", + rpl->status, GET_TID(rpl)); + + return CPL_RET_BUF_DONE; +} + +static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_l2t_write_rpl *rpl = cplhdr(skb); + + if (rpl->status != CPL_ERR_NONE) + printk(KERN_ERR + "Unexpected L2T_WRITE_RPL status %u for entry %u\n", + rpl->status, GET_TID(rpl)); + + return CPL_RET_BUF_DONE; +} + +static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_act_open_rpl *rpl = cplhdr(skb); + unsigned int atid = G_TID(ntohl(rpl->atid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid); + if (t3c_tid->ctx && t3c_tid->client && t3c_tid->client->handlers && + t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) { + return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb, + t3c_tid-> + ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, CPL_ACT_OPEN_RPL); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + union opcode_tid *p = cplhdr(skb); + unsigned int stid = G_TID(ntohl(p->opcode_tid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid); + if (t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[p->opcode]) { + return t3c_tid->client->handlers[p->opcode] (dev, skb, + t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, p->opcode); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + union opcode_tid *p = cplhdr(skb); + unsigned int hwtid = G_TID(ntohl(p->opcode_tid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); + if (t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[p->opcode]) { + return t3c_tid->client->handlers[p->opcode] + (dev, skb, t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, p->opcode); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_cr(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_pass_accept_req *req = cplhdr(skb); + unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid); + if (t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) { + return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ] + (dev, skb, t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, CPL_PASS_ACCEPT_REQ); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb) +{ + union opcode_tid *p = cplhdr(skb); + unsigned int hwtid = G_TID(ntohl(p->opcode_tid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); + if (t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[p->opcode]) { + return t3c_tid->client->handlers[p->opcode] + (dev, skb, t3c_tid->ctx); + } else { + struct cpl_abort_req_rss *req = cplhdr(skb); + struct cpl_abort_rpl *rpl; + + struct sk_buff *skb = + alloc_skb(sizeof(struct cpl_abort_rpl), GFP_ATOMIC); + if (!skb) { + printk("do_abort_req_rss: couldn't get skb!\n"); + goto out; + } + skb->priority = CPL_PRIORITY_DATA; + __skb_put(skb, sizeof(struct cpl_abort_rpl)); + rpl = cplhdr(skb); + rpl->wr.wr_hi = + htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); + rpl->wr.wr_lo = htonl(V_WR_TID(GET_TID(req))); + OPCODE_TID(rpl) = + htonl(MK_OPCODE_TID(CPL_ABORT_RPL, GET_TID(req))); + rpl->cmd = req->status; + cxgb3_ofld_send(dev, skb); +out: + return CPL_RET_BUF_DONE; + } +} + +static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_act_establish *req = cplhdr(skb); + unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid); + if (t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) { + return t3c_tid->client->handlers[CPL_ACT_ESTABLISH] + (dev, skb, t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, CPL_PASS_ACCEPT_REQ); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int do_set_tcb_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_set_tcb_rpl *rpl = cplhdr(skb); + + if (rpl->status != CPL_ERR_NONE) + printk(KERN_ERR + "Unexpected SET_TCB_RPL status %u for tid %u\n", + rpl->status, GET_TID(rpl)); + return CPL_RET_BUF_DONE; +} + +static int do_trace(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_trace_pkt *p = cplhdr(skb); + + skb->protocol = 0xffff; + skb->dev = dev->lldev; + skb_pull(skb, sizeof(*p)); + skb->mac.raw = skb->data; + netif_receive_skb(skb); + return 0; +} + +static int do_term(struct t3cdev *dev, struct sk_buff *skb) +{ + unsigned int hwtid = ntohl(skb->priority) >> 8 & 0xfffff; + unsigned int opcode = G_OPCODE(ntohl(skb->csum)); + struct t3c_tid_entry *t3c_tid; + + t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); + if (t3c_tid->ctx && t3c_tid->client->handlers && + t3c_tid->client->handlers[opcode]) { + return t3c_tid->client->handlers[opcode] (dev, skb, + t3c_tid->ctx); + } else { + printk(KERN_ERR "%s: received clientless CPL command 0x%x\n", + dev->name, opcode); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; + } +} + +static int nb_callback(struct notifier_block *self, unsigned long event, + void *ctx) +{ + switch (event) { + case (NETEVENT_NEIGH_UPDATE):{ + cxgb_neigh_update((struct neighbour *)ctx); + break; + } + case (NETEVENT_PMTU_UPDATE): + break; + case (NETEVENT_REDIRECT):{ + struct netevent_redirect *nr = ctx; + cxgb_redirect(nr->old, nr->new); + cxgb_neigh_update(nr->new->neighbour); + break; + } + default: + break; + } + return 0; +} + +static struct notifier_block nb = { + .notifier_call = nb_callback +}; + +/* + * Process a received packet with an unknown/unexpected CPL opcode. + */ +static int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb) +{ + printk(KERN_ERR "%s: received bad CPL command 0x%x\n", dev->name, + *skb->data); + return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG; +} + +/* + * Handlers for each CPL opcode + */ +static cpl_handler_func cpl_handlers[NUM_CPL_CMDS]; + +/* + * Add a new handler to the CPL dispatch table. A NULL handler may be supplied + * to unregister an existing handler. + */ +void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h) +{ + if (opcode < NUM_CPL_CMDS) + cpl_handlers[opcode] = h ? h : do_bad_cpl; + else + printk(KERN_ERR "T3C: handler registration for " + "opcode %x failed\n", opcode); +} + +EXPORT_SYMBOL(t3_register_cpl_handler); + +/* + * T3CDEV's receive method. + */ +int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n) +{ + while (n--) { + struct sk_buff *skb = *skbs++; + unsigned int opcode = G_OPCODE(ntohl(skb->csum)); + int ret = cpl_handlers[opcode] (dev, skb); + +#if VALIDATE_TID + if (ret & CPL_RET_UNKNOWN_TID) { + union opcode_tid *p = cplhdr(skb); + + printk(KERN_ERR "%s: CPL message (opcode %u) had " + "unknown TID %u\n", dev->name, opcode, + G_TID(ntohl(p->opcode_tid))); + } +#endif + if (ret & CPL_RET_BUF_DONE) + kfree_skb(skb); + } + return 0; +} + +/* + * Sends an sk_buff to a T3C driver after dealing with any active network taps. + */ +int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb) +{ + int r; + + local_bh_disable(); + r = dev->send(dev, skb); + local_bh_enable(); + return r; +} + +EXPORT_SYMBOL(cxgb3_ofld_send); + +static int is_offloading(struct net_device *dev) +{ + struct adapter *adapter; + int i; + + read_lock_bh(&adapter_list_lock); + list_for_each_entry(adapter, &adapter_list, adapter_list) { + for_each_port(adapter, i) { + if (dev == adapter->port[i]) { + read_unlock_bh(&adapter_list_lock); + return 1; + } + } + } + read_unlock_bh(&adapter_list_lock); + return 0; +} + +void cxgb_neigh_update(struct neighbour *neigh) +{ + struct net_device *dev = neigh->dev; + + if (dev && (is_offloading(dev))) { + struct t3cdev *tdev = T3CDEV(dev); + + BUG_ON(!tdev); + t3_l2t_update(tdev, neigh); + } +} + +static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e) +{ + struct sk_buff *skb; + struct cpl_set_tcb_field *req; + + skb = alloc_skb(sizeof(*req), GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "%s: cannot allocate skb!\n", __FUNCTION__); + return; + } + skb->priority = CPL_PRIORITY_CONTROL; + req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); + req->reply = 0; + req->cpu_idx = 0; + req->word = htons(W_TCB_L2T_IX); + req->mask = cpu_to_be64(V_TCB_L2T_IX(M_TCB_L2T_IX)); + req->val = cpu_to_be64(V_TCB_L2T_IX(e->idx)); + tdev->send(tdev, skb); +} + +void cxgb_redirect(struct dst_entry *old, struct dst_entry *new) +{ + struct net_device *olddev, *newdev; + struct tid_info *ti; + struct t3cdev *tdev; + u32 tid; + int update_tcb; + struct l2t_entry *e; + struct t3c_tid_entry *te; + + olddev = old->neighbour->dev; + newdev = new->neighbour->dev; + if (!is_offloading(olddev)) + return; + if (!is_offloading(newdev)) { + printk(KERN_WARNING "%s: Redirect to non-offload" + "device ignored.\n", __FUNCTION__); + return; + } + tdev = T3CDEV(olddev); + BUG_ON(!tdev); + if (tdev != T3CDEV(newdev)) { + printk(KERN_WARNING "%s: Redirect to different " + "offload device ignored.\n", __FUNCTION__); + return; + } + + /* Add new L2T entry */ + e = t3_l2t_get(tdev, new->neighbour, newdev); + if (!e) { + printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n", + __FUNCTION__); + return; + } + + /* Walk tid table and notify clients of dst change. */ + ti = &(T3C_DATA(tdev))->tid_maps; + for (tid = 0; tid < ti->ntids; tid++) { + te = lookup_tid(ti, tid); + BUG_ON(!te); + if (te->ctx && te->client && te->client->redirect) { + update_tcb = te->client->redirect(te->ctx, old, new, e); + if (update_tcb) { + l2t_hold(L2DATA(tdev), e); + set_l2t_ix(tdev, tid, e); + } + } + } + l2t_release(L2DATA(tdev), e); +} + +/* + * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc. + * The allocated memory is cleared. + */ +void *cxgb_alloc_mem(unsigned long size) +{ + void *p = kmalloc(size, GFP_KERNEL); + + if (!p) + p = vmalloc(size); + if (p) + memset(p, 0, size); + return p; +} + +/* + * Free memory allocated through t3_alloc_mem(). + */ +void cxgb_free_mem(void *addr) +{ + unsigned long p = (unsigned long)addr; + + if (p >= VMALLOC_START && p < VMALLOC_END) + vfree(addr); + else + kfree(addr); +} + +/* + * Allocate and initialize the TID tables. Returns 0 on success. + */ +static int init_tid_tabs(struct tid_info *t, unsigned int ntids, + unsigned int natids, unsigned int nstids, + unsigned int atid_base, unsigned int stid_base) +{ + unsigned long size = ntids * sizeof(*t->tid_tab) + + natids * sizeof(*t->atid_tab) + nstids * sizeof(*t->stid_tab); + + t->tid_tab = cxgb_alloc_mem(size); + if (!t->tid_tab) + return -ENOMEM; + + t->stid_tab = (union listen_entry *)&t->tid_tab[ntids]; + t->atid_tab = (union active_open_entry *)&t->stid_tab[nstids]; + t->ntids = ntids; + t->nstids = nstids; + t->stid_base = stid_base; + t->sfree = NULL; + t->natids = natids; + t->atid_base = atid_base; + t->afree = NULL; + t->stids_in_use = t->atids_in_use = 0; + atomic_set(&t->tids_in_use, 0); + spin_lock_init(&t->stid_lock); + spin_lock_init(&t->atid_lock); + + /* + * Setup the free lists for stid_tab and atid_tab. + */ + if (nstids) { + while (--nstids) + t->stid_tab[nstids - 1].next = &t->stid_tab[nstids]; + t->sfree = t->stid_tab; + } + if (natids) { + while (--natids) + t->atid_tab[natids - 1].next = &t->atid_tab[natids]; + t->afree = t->atid_tab; + } + return 0; +} + +static void free_tid_maps(struct tid_info *t) +{ + cxgb_free_mem(t->tid_tab); +} + +static inline void add_adapter(struct adapter *adap) +{ + write_lock_bh(&adapter_list_lock); + list_add_tail(&adap->adapter_list, &adapter_list); + write_unlock_bh(&adapter_list_lock); +} + +static inline void remove_adapter(struct adapter *adap) +{ + write_lock_bh(&adapter_list_lock); + list_del(&adap->adapter_list); + write_unlock_bh(&adapter_list_lock); +} + +int cxgb3_offload_activate(struct adapter *adapter) +{ + struct t3cdev *dev = &adapter->tdev; + int natids, err; + struct t3c_data *t; + struct tid_range stid_range, tid_range; + struct mtutab mtutab; + unsigned int l2t_capacity; + + t = kcalloc(1, sizeof(*t), GFP_KERNEL); + if (!t) + return -ENOMEM; + + err = -EOPNOTSUPP; + if (dev->ctl(dev, GET_TX_MAX_CHUNK, &t->tx_max_chunk) < 0 || + dev->ctl(dev, GET_MAX_OUTSTANDING_WR, &t->max_wrs) < 0 || + dev->ctl(dev, GET_L2T_CAPACITY, &l2t_capacity) < 0 || + dev->ctl(dev, GET_MTUS, &mtutab) < 0 || + dev->ctl(dev, GET_TID_RANGE, &tid_range) < 0 || + dev->ctl(dev, GET_STID_RANGE, &stid_range) < 0) + goto out_free; + + err = -ENOMEM; + L2DATA(dev) = t3_init_l2t(l2t_capacity); + if (!L2DATA(dev)) + goto out_free; + + natids = min(tid_range.num / 2, MAX_ATIDS); + err = init_tid_tabs(&t->tid_maps, tid_range.num, natids, + stid_range.num, ATID_BASE, stid_range.base); + if (err) + goto out_free_l2t; + + t->mtus = mtutab.mtus; + t->nmtus = mtutab.size; + + INIT_WORK(&t->tid_release_task, t3_process_tid_release_list); + spin_lock_init(&t->tid_release_lock); + INIT_LIST_HEAD(&t->list_node); + t->dev = dev; + + T3C_DATA(dev) = t; + dev->recv = process_rx; + dev->neigh_update = t3_l2t_update; + + /* Register netevent handler once */ + if (list_empty(&adapter_list)) + register_netevent_notifier(&nb); + + add_adapter(adapter); + return 0; + +out_free_l2t: + t3_free_l2t(L2DATA(dev)); + L2DATA(dev) = NULL; +out_free: + kfree(t); + return err; +} + +void cxgb3_offload_deactivate(struct adapter *adapter) +{ + struct t3cdev *tdev = &adapter->tdev; + struct t3c_data *t = T3C_DATA(tdev); + + remove_adapter(adapter); + if (list_empty(&adapter_list)) + unregister_netevent_notifier(&nb); + + free_tid_maps(&t->tid_maps); + T3C_DATA(tdev) = NULL; + t3_free_l2t(L2DATA(tdev)); + L2DATA(tdev) = NULL; + kfree(t); +} + +static inline void register_tdev(struct t3cdev *tdev) +{ + static int unit; + + mutex_lock(&cxgb3_db_lock); + snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++); + list_add_tail(&tdev->ofld_dev_list, &ofld_dev_list); + mutex_unlock(&cxgb3_db_lock); +} + +static inline void unregister_tdev(struct t3cdev *tdev) +{ + mutex_lock(&cxgb3_db_lock); + list_del(&tdev->ofld_dev_list); + mutex_unlock(&cxgb3_db_lock); +} + +void __devinit cxgb3_adapter_ofld(struct adapter *adapter) +{ + struct t3cdev *tdev = &adapter->tdev; + + INIT_LIST_HEAD(&tdev->ofld_dev_list); + + cxgb3_set_dummy_ops(tdev); + tdev->send = t3_offload_tx; + tdev->ctl = cxgb_offload_ctl; + tdev->type = adapter->params.rev == 0 ? T3A : T3B; + + register_tdev(tdev); +} + +void __devexit cxgb3_adapter_unofld(struct adapter *adapter) +{ + struct t3cdev *tdev = &adapter->tdev; + + tdev->recv = NULL; + tdev->neigh_update = NULL; + + unregister_tdev(tdev); +} + +void __init cxgb3_offload_init(void) +{ + int i; + + for (i = 0; i < NUM_CPL_CMDS; ++i) + cpl_handlers[i] = do_bad_cpl; + + t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl); + t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl); + t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl); + t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl); + t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr); + t3_register_cpl_handler(CPL_PASS_ESTABLISH, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ABORT_RPL_RSS, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ABORT_RPL, do_hwtid_rpl); + t3_register_cpl_handler(CPL_RX_URG_NOTIFY, do_hwtid_rpl); + t3_register_cpl_handler(CPL_RX_DATA, do_hwtid_rpl); + t3_register_cpl_handler(CPL_TX_DATA_ACK, do_hwtid_rpl); + t3_register_cpl_handler(CPL_TX_DMA_ACK, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ACT_OPEN_RPL, do_act_open_rpl); + t3_register_cpl_handler(CPL_PEER_CLOSE, do_hwtid_rpl); + t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss); + t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish); + t3_register_cpl_handler(CPL_SET_TCB_RPL, do_set_tcb_rpl); + t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term); + t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl); + t3_register_cpl_handler(CPL_TRACE_PKT, do_trace); + t3_register_cpl_handler(CPL_RX_DATA_DDP, do_hwtid_rpl); + t3_register_cpl_handler(CPL_RX_DDP_COMPLETE, do_hwtid_rpl); + t3_register_cpl_handler(CPL_ISCSI_HDR, do_hwtid_rpl); +} diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h new file mode 100644 index 000000000000..0e6beb69ba17 --- /dev/null +++ b/drivers/net/cxgb3/cxgb3_offload.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _CXGB3_OFFLOAD_H +#define _CXGB3_OFFLOAD_H + +#include +#include + +#include "l2t.h" + +#include "t3cdev.h" +#include "t3_cpl.h" + +struct adapter; + +void cxgb3_offload_init(void); + +void cxgb3_adapter_ofld(struct adapter *adapter); +void cxgb3_adapter_unofld(struct adapter *adapter); +int cxgb3_offload_activate(struct adapter *adapter); +void cxgb3_offload_deactivate(struct adapter *adapter); + +void cxgb3_set_dummy_ops(struct t3cdev *dev); + +/* + * Client registration. Users of T3 driver must register themselves. + * The T3 driver will call the add function of every client for each T3 + * adapter activated, passing up the t3cdev ptr. Each client fills out an + * array of callback functions to process CPL messages. + */ + +void cxgb3_register_client(struct cxgb3_client *client); +void cxgb3_unregister_client(struct cxgb3_client *client); +void cxgb3_add_clients(struct t3cdev *tdev); +void cxgb3_remove_clients(struct t3cdev *tdev); + +typedef int (*cxgb3_cpl_handler_func)(struct t3cdev *dev, + struct sk_buff *skb, void *ctx); + +struct cxgb3_client { + char *name; + void (*add) (struct t3cdev *); + void (*remove) (struct t3cdev *); + cxgb3_cpl_handler_func *handlers; + int (*redirect)(void *ctx, struct dst_entry *old, + struct dst_entry *new, struct l2t_entry *l2t); + struct list_head client_list; +}; + +/* + * TID allocation services. + */ +int cxgb3_alloc_atid(struct t3cdev *dev, struct cxgb3_client *client, + void *ctx); +int cxgb3_alloc_stid(struct t3cdev *dev, struct cxgb3_client *client, + void *ctx); +void *cxgb3_free_atid(struct t3cdev *dev, int atid); +void cxgb3_free_stid(struct t3cdev *dev, int stid); +void cxgb3_insert_tid(struct t3cdev *dev, struct cxgb3_client *client, + void *ctx, unsigned int tid); +void cxgb3_queue_tid_release(struct t3cdev *dev, unsigned int tid); +void cxgb3_remove_tid(struct t3cdev *dev, void *ctx, unsigned int tid); + +struct t3c_tid_entry { + struct cxgb3_client *client; + void *ctx; +}; + +/* CPL message priority levels */ +enum { + CPL_PRIORITY_DATA = 0, /* data messages */ + CPL_PRIORITY_SETUP = 1, /* connection setup messages */ + CPL_PRIORITY_TEARDOWN = 0, /* connection teardown messages */ + CPL_PRIORITY_LISTEN = 1, /* listen start/stop messages */ + CPL_PRIORITY_ACK = 1, /* RX ACK messages */ + CPL_PRIORITY_CONTROL = 1 /* offload control messages */ +}; + +/* Flags for return value of CPL message handlers */ +enum { + CPL_RET_BUF_DONE = 1, /* buffer processing done, buffer may be freed */ + CPL_RET_BAD_MSG = 2, /* bad CPL message (e.g., unknown opcode) */ + CPL_RET_UNKNOWN_TID = 4 /* unexpected unknown TID */ +}; + +typedef int (*cpl_handler_func)(struct t3cdev *dev, struct sk_buff *skb); + +/* + * Returns a pointer to the first byte of the CPL header in an sk_buff that + * contains a CPL message. + */ +static inline void *cplhdr(struct sk_buff *skb) +{ + return skb->data; +} + +void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h); + +union listen_entry { + struct t3c_tid_entry t3c_tid; + union listen_entry *next; +}; + +union active_open_entry { + struct t3c_tid_entry t3c_tid; + union active_open_entry *next; +}; + +/* + * Holds the size, base address, free list start, etc of the TID, server TID, + * and active-open TID tables for a offload device. + * The tables themselves are allocated dynamically. + */ +struct tid_info { + struct t3c_tid_entry *tid_tab; + unsigned int ntids; + atomic_t tids_in_use; + + union listen_entry *stid_tab; + unsigned int nstids; + unsigned int stid_base; + + union active_open_entry *atid_tab; + unsigned int natids; + unsigned int atid_base; + + /* + * The following members are accessed R/W so we put them in their own + * cache lines. + * + * XXX We could combine the atid fields above with the lock here since + * atids are use once (unlike other tids). OTOH the above fields are + * usually in cache due to tid_tab. + */ + spinlock_t atid_lock ____cacheline_aligned_in_smp; + union active_open_entry *afree; + unsigned int atids_in_use; + + spinlock_t stid_lock ____cacheline_aligned; + union listen_entry *sfree; + unsigned int stids_in_use; +}; + +struct t3c_data { + struct list_head list_node; + struct t3cdev *dev; + unsigned int tx_max_chunk; /* max payload for TX_DATA */ + unsigned int max_wrs; /* max in-flight WRs per connection */ + unsigned int nmtus; + const unsigned short *mtus; + struct tid_info tid_maps; + + struct t3c_tid_entry *tid_release_list; + spinlock_t tid_release_lock; + struct work_struct tid_release_task; +}; + +/* + * t3cdev -> t3c_data accessor + */ +#define T3C_DATA(dev) (*(struct t3c_data **)&(dev)->l4opt) + +#endif diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h new file mode 100644 index 000000000000..6a835f6a262a --- /dev/null +++ b/drivers/net/cxgb3/firmware_exports.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _FIRMWARE_EXPORTS_H_ +#define _FIRMWARE_EXPORTS_H_ + +/* WR OPCODES supported by the firmware. + */ +#define FW_WROPCODE_FORWARD 0x01 +#define FW_WROPCODE_BYPASS 0x05 + +#define FW_WROPCODE_TUNNEL_TX_PKT 0x03 + +#define FW_WROPOCDE_ULPTX_DATA_SGL 0x00 +#define FW_WROPCODE_ULPTX_MEM_READ 0x02 +#define FW_WROPCODE_ULPTX_PKT 0x04 +#define FW_WROPCODE_ULPTX_INVALIDATE 0x06 + +#define FW_WROPCODE_TUNNEL_RX_PKT 0x07 + +#define FW_WROPCODE_OFLD_GETTCB_RPL 0x08 +#define FW_WROPCODE_OFLD_CLOSE_CON 0x09 +#define FW_WROPCODE_OFLD_TP_ABORT_CON_REQ 0x0A +#define FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL 0x0F +#define FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ 0x0B +#define FW_WROPCODE_OFLD_TP_ABORT_CON_RPL 0x0C +#define FW_WROPCODE_OFLD_TX_DATA 0x0D +#define FW_WROPCODE_OFLD_TX_DATA_ACK 0x0E + +#define FW_WROPCODE_RI_RDMA_INIT 0x10 +#define FW_WROPCODE_RI_RDMA_WRITE 0x11 +#define FW_WROPCODE_RI_RDMA_READ_REQ 0x12 +#define FW_WROPCODE_RI_RDMA_READ_RESP 0x13 +#define FW_WROPCODE_RI_SEND 0x14 +#define FW_WROPCODE_RI_TERMINATE 0x15 +#define FW_WROPCODE_RI_RDMA_READ 0x16 +#define FW_WROPCODE_RI_RECEIVE 0x17 +#define FW_WROPCODE_RI_BIND_MW 0x18 +#define FW_WROPCODE_RI_FASTREGISTER_MR 0x19 +#define FW_WROPCODE_RI_LOCAL_INV 0x1A +#define FW_WROPCODE_RI_MODIFY_QP 0x1B +#define FW_WROPCODE_RI_BYPASS 0x1C + +#define FW_WROPOCDE_RSVD 0x1E + +#define FW_WROPCODE_SGE_EGRESSCONTEXT_RR 0x1F + +#define FW_WROPCODE_MNGT 0x1D +#define FW_MNGTOPCODE_PKTSCHED_SET 0x00 + +/* Maximum size of a WR sent from the host, limited by the SGE. + * + * Note: WR coming from ULP or TP are only limited by CIM. + */ +#define FW_WR_SIZE 128 + +/* Maximum number of outstanding WRs sent from the host. Value must be + * programmed in the CTRL/TUNNEL/QP SGE Egress Context and used by + * offload modules to limit the number of WRs per connection. + */ +#define FW_T3_WR_NUM 16 +#define FW_N3_WR_NUM 7 + +#ifndef N3 +# define FW_WR_NUM FW_T3_WR_NUM +#else +# define FW_WR_NUM FW_N3_WR_NUM +#endif + +/* FW_TUNNEL_NUM corresponds to the number of supported TUNNEL Queues. These + * queues must start at SGE Egress Context FW_TUNNEL_SGEEC_START and must + * start at 'TID' (or 'uP Token') FW_TUNNEL_TID_START. + * + * Ingress Traffic (e.g. DMA completion credit) for TUNNEL Queue[i] is sent + * to RESP Queue[i]. + */ +#define FW_TUNNEL_NUM 8 +#define FW_TUNNEL_SGEEC_START 8 +#define FW_TUNNEL_TID_START 65544 + +/* FW_CTRL_NUM corresponds to the number of supported CTRL Queues. These queues + * must start at SGE Egress Context FW_CTRL_SGEEC_START and must start at 'TID' + * (or 'uP Token') FW_CTRL_TID_START. + * + * Ingress Traffic for CTRL Queue[i] is sent to RESP Queue[i]. + */ +#define FW_CTRL_NUM 8 +#define FW_CTRL_SGEEC_START 65528 +#define FW_CTRL_TID_START 65536 + +/* FW_OFLD_NUM corresponds to the number of supported OFFLOAD Queues. These + * queues must start at SGE Egress Context FW_OFLD_SGEEC_START. + * + * Note: the 'uP Token' in the SGE Egress Context fields is irrelevant for + * OFFLOAD Queues, as the host is responsible for providing the correct TID in + * every WR. + * + * Ingress Trafffic for OFFLOAD Queue[i] is sent to RESP Queue[i]. + */ +#define FW_OFLD_NUM 8 +#define FW_OFLD_SGEEC_START 0 + +/* + * + */ +#define FW_RI_NUM 1 +#define FW_RI_SGEEC_START 65527 +#define FW_RI_TID_START 65552 + +/* + * The RX_PKT_TID + */ +#define FW_RX_PKT_NUM 1 +#define FW_RX_PKT_TID_START 65553 + +/* FW_WRC_NUM corresponds to the number of Work Request Context that supported + * by the firmware. + */ +#define FW_WRC_NUM \ + (65536 + FW_TUNNEL_NUM + FW_CTRL_NUM + FW_RI_NUM + FW_RX_PKT_NUM) + +/* + * FW type and version. + */ +#define S_FW_VERSION_TYPE 28 +#define M_FW_VERSION_TYPE 0xF +#define V_FW_VERSION_TYPE(x) ((x) << S_FW_VERSION_TYPE) +#define G_FW_VERSION_TYPE(x) \ + (((x) >> S_FW_VERSION_TYPE) & M_FW_VERSION_TYPE) + +#define S_FW_VERSION_MAJOR 16 +#define M_FW_VERSION_MAJOR 0xFFF +#define V_FW_VERSION_MAJOR(x) ((x) << S_FW_VERSION_MAJOR) +#define G_FW_VERSION_MAJOR(x) \ + (((x) >> S_FW_VERSION_MAJOR) & M_FW_VERSION_MAJOR) + +#define S_FW_VERSION_MINOR 8 +#define M_FW_VERSION_MINOR 0xFF +#define V_FW_VERSION_MINOR(x) ((x) << S_FW_VERSION_MINOR) +#define G_FW_VERSION_MINOR(x) \ + (((x) >> S_FW_VERSION_MINOR) & M_FW_VERSION_MINOR) + +#define S_FW_VERSION_MICRO 0 +#define M_FW_VERSION_MICRO 0xFF +#define V_FW_VERSION_MICRO(x) ((x) << S_FW_VERSION_MICRO) +#define G_FW_VERSION_MICRO(x) \ + (((x) >> S_FW_VERSION_MICRO) & M_FW_VERSION_MICRO) + +#endif /* _FIRMWARE_EXPORTS_H_ */ diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c new file mode 100644 index 000000000000..3c0cb8557058 --- /dev/null +++ b/drivers/net/cxgb3/l2t.c @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "t3cdev.h" +#include "cxgb3_defs.h" +#include "l2t.h" +#include "t3_cpl.h" +#include "firmware_exports.h" + +#define VLAN_NONE 0xfff + +/* + * Module locking notes: There is a RW lock protecting the L2 table as a + * whole plus a spinlock per L2T entry. Entry lookups and allocations happen + * under the protection of the table lock, individual entry changes happen + * while holding that entry's spinlock. The table lock nests outside the + * entry locks. Allocations of new entries take the table lock as writers so + * no other lookups can happen while allocating new entries. Entry updates + * take the table lock as readers so multiple entries can be updated in + * parallel. An L2T entry can be dropped by decrementing its reference count + * and therefore can happen in parallel with entry allocation but no entry + * can change state or increment its ref count during allocation as both of + * these perform lookups. + */ + +static inline unsigned int vlan_prio(const struct l2t_entry *e) +{ + return e->vlan >> 13; +} + +static inline unsigned int arp_hash(u32 key, int ifindex, + const struct l2t_data *d) +{ + return jhash_2words(key, ifindex, 0) & (d->nentries - 1); +} + +static inline void neigh_replace(struct l2t_entry *e, struct neighbour *n) +{ + neigh_hold(n); + if (e->neigh) + neigh_release(e->neigh); + e->neigh = n; +} + +/* + * Set up an L2T entry and send any packets waiting in the arp queue. The + * supplied skb is used for the CPL_L2T_WRITE_REQ. Must be called with the + * entry locked. + */ +static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb, + struct l2t_entry *e) +{ + struct cpl_l2t_write_req *req; + + if (!skb) { + skb = alloc_skb(sizeof(*req), GFP_ATOMIC); + if (!skb) + return -ENOMEM; + } + + req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx)); + req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) | + V_L2T_W_VLAN(e->vlan & VLAN_VID_MASK) | + V_L2T_W_PRIO(vlan_prio(e))); + memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac)); + memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); + skb->priority = CPL_PRIORITY_CONTROL; + cxgb3_ofld_send(dev, skb); + while (e->arpq_head) { + skb = e->arpq_head; + e->arpq_head = skb->next; + skb->next = NULL; + cxgb3_ofld_send(dev, skb); + } + e->arpq_tail = NULL; + e->state = L2T_STATE_VALID; + + return 0; +} + +/* + * Add a packet to the an L2T entry's queue of packets awaiting resolution. + * Must be called with the entry's lock held. + */ +static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb) +{ + skb->next = NULL; + if (e->arpq_head) + e->arpq_tail->next = skb; + else + e->arpq_head = skb; + e->arpq_tail = skb; +} + +int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb, + struct l2t_entry *e) +{ +again: + switch (e->state) { + case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ + neigh_event_send(e->neigh, NULL); + spin_lock_bh(&e->lock); + if (e->state == L2T_STATE_STALE) + e->state = L2T_STATE_VALID; + spin_unlock_bh(&e->lock); + case L2T_STATE_VALID: /* fast-path, send the packet on */ + return cxgb3_ofld_send(dev, skb); + case L2T_STATE_RESOLVING: + spin_lock_bh(&e->lock); + if (e->state != L2T_STATE_RESOLVING) { + /* ARP already completed */ + spin_unlock_bh(&e->lock); + goto again; + } + arpq_enqueue(e, skb); + spin_unlock_bh(&e->lock); + + /* + * Only the first packet added to the arpq should kick off + * resolution. However, because the alloc_skb below can fail, + * we allow each packet added to the arpq to retry resolution + * as a way of recovering from transient memory exhaustion. + * A better way would be to use a work request to retry L2T + * entries when there's no memory. + */ + if (!neigh_event_send(e->neigh, NULL)) { + skb = alloc_skb(sizeof(struct cpl_l2t_write_req), + GFP_ATOMIC); + if (!skb) + break; + + spin_lock_bh(&e->lock); + if (e->arpq_head) + setup_l2e_send_pending(dev, skb, e); + else /* we lost the race */ + __kfree_skb(skb); + spin_unlock_bh(&e->lock); + } + } + return 0; +} + +EXPORT_SYMBOL(t3_l2t_send_slow); + +void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e) +{ +again: + switch (e->state) { + case L2T_STATE_STALE: /* entry is stale, kick off revalidation */ + neigh_event_send(e->neigh, NULL); + spin_lock_bh(&e->lock); + if (e->state == L2T_STATE_STALE) { + e->state = L2T_STATE_VALID; + } + spin_unlock_bh(&e->lock); + return; + case L2T_STATE_VALID: /* fast-path, send the packet on */ + return; + case L2T_STATE_RESOLVING: + spin_lock_bh(&e->lock); + if (e->state != L2T_STATE_RESOLVING) { + /* ARP already completed */ + spin_unlock_bh(&e->lock); + goto again; + } + spin_unlock_bh(&e->lock); + + /* + * Only the first packet added to the arpq should kick off + * resolution. However, because the alloc_skb below can fail, + * we allow each packet added to the arpq to retry resolution + * as a way of recovering from transient memory exhaustion. + * A better way would be to use a work request to retry L2T + * entries when there's no memory. + */ + neigh_event_send(e->neigh, NULL); + } + return; +} + +EXPORT_SYMBOL(t3_l2t_send_event); + +/* + * Allocate a free L2T entry. Must be called with l2t_data.lock held. + */ +static struct l2t_entry *alloc_l2e(struct l2t_data *d) +{ + struct l2t_entry *end, *e, **p; + + if (!atomic_read(&d->nfree)) + return NULL; + + /* there's definitely a free entry */ + for (e = d->rover, end = &d->l2tab[d->nentries]; e != end; ++e) + if (atomic_read(&e->refcnt) == 0) + goto found; + + for (e = &d->l2tab[1]; atomic_read(&e->refcnt); ++e) ; +found: + d->rover = e + 1; + atomic_dec(&d->nfree); + + /* + * The entry we found may be an inactive entry that is + * presently in the hash table. We need to remove it. + */ + if (e->state != L2T_STATE_UNUSED) { + int hash = arp_hash(e->addr, e->ifindex, d); + + for (p = &d->l2tab[hash].first; *p; p = &(*p)->next) + if (*p == e) { + *p = e->next; + break; + } + e->state = L2T_STATE_UNUSED; + } + return e; +} + +/* + * Called when an L2T entry has no more users. The entry is left in the hash + * table since it is likely to be reused but we also bump nfree to indicate + * that the entry can be reallocated for a different neighbor. We also drop + * the existing neighbor reference in case the neighbor is going away and is + * waiting on our reference. + * + * Because entries can be reallocated to other neighbors once their ref count + * drops to 0 we need to take the entry's lock to avoid races with a new + * incarnation. + */ +void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e) +{ + spin_lock_bh(&e->lock); + if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ + if (e->neigh) { + neigh_release(e->neigh); + e->neigh = NULL; + } + } + spin_unlock_bh(&e->lock); + atomic_inc(&d->nfree); +} + +EXPORT_SYMBOL(t3_l2e_free); + +/* + * Update an L2T entry that was previously used for the same next hop as neigh. + * Must be called with softirqs disabled. + */ +static inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh) +{ + unsigned int nud_state; + + spin_lock(&e->lock); /* avoid race with t3_l2t_free */ + + if (neigh != e->neigh) + neigh_replace(e, neigh); + nud_state = neigh->nud_state; + if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) || + !(nud_state & NUD_VALID)) + e->state = L2T_STATE_RESOLVING; + else if (nud_state & NUD_CONNECTED) + e->state = L2T_STATE_VALID; + else + e->state = L2T_STATE_STALE; + spin_unlock(&e->lock); +} + +struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, + struct net_device *dev) +{ + struct l2t_entry *e; + struct l2t_data *d = L2DATA(cdev); + u32 addr = *(u32 *) neigh->primary_key; + int ifidx = neigh->dev->ifindex; + int hash = arp_hash(addr, ifidx, d); + struct port_info *p = netdev_priv(dev); + int smt_idx = p->port_id; + + write_lock_bh(&d->lock); + for (e = d->l2tab[hash].first; e; e = e->next) + if (e->addr == addr && e->ifindex == ifidx && + e->smt_idx == smt_idx) { + l2t_hold(d, e); + if (atomic_read(&e->refcnt) == 1) + reuse_entry(e, neigh); + goto done; + } + + /* Need to allocate a new entry */ + e = alloc_l2e(d); + if (e) { + spin_lock(&e->lock); /* avoid race with t3_l2t_free */ + e->next = d->l2tab[hash].first; + d->l2tab[hash].first = e; + e->state = L2T_STATE_RESOLVING; + e->addr = addr; + e->ifindex = ifidx; + e->smt_idx = smt_idx; + atomic_set(&e->refcnt, 1); + neigh_replace(e, neigh); + if (neigh->dev->priv_flags & IFF_802_1Q_VLAN) + e->vlan = VLAN_DEV_INFO(neigh->dev)->vlan_id; + else + e->vlan = VLAN_NONE; + spin_unlock(&e->lock); + } +done: + write_unlock_bh(&d->lock); + return e; +} + +EXPORT_SYMBOL(t3_l2t_get); + +/* + * Called when address resolution fails for an L2T entry to handle packets + * on the arpq head. If a packet specifies a failure handler it is invoked, + * otherwise the packets is sent to the offload device. + * + * XXX: maybe we should abandon the latter behavior and just require a failure + * handler. + */ +static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff *arpq) +{ + while (arpq) { + struct sk_buff *skb = arpq; + struct l2t_skb_cb *cb = L2T_SKB_CB(skb); + + arpq = skb->next; + skb->next = NULL; + if (cb->arp_failure_handler) + cb->arp_failure_handler(dev, skb); + else + cxgb3_ofld_send(dev, skb); + } +} + +/* + * Called when the host's ARP layer makes a change to some entry that is + * loaded into the HW L2 table. + */ +void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh) +{ + struct l2t_entry *e; + struct sk_buff *arpq = NULL; + struct l2t_data *d = L2DATA(dev); + u32 addr = *(u32 *) neigh->primary_key; + int ifidx = neigh->dev->ifindex; + int hash = arp_hash(addr, ifidx, d); + + read_lock_bh(&d->lock); + for (e = d->l2tab[hash].first; e; e = e->next) + if (e->addr == addr && e->ifindex == ifidx) { + spin_lock(&e->lock); + goto found; + } + read_unlock_bh(&d->lock); + return; + +found: + read_unlock(&d->lock); + if (atomic_read(&e->refcnt)) { + if (neigh != e->neigh) + neigh_replace(e, neigh); + + if (e->state == L2T_STATE_RESOLVING) { + if (neigh->nud_state & NUD_FAILED) { + arpq = e->arpq_head; + e->arpq_head = e->arpq_tail = NULL; + } else if (neigh_is_connected(neigh)) + setup_l2e_send_pending(dev, NULL, e); + } else { + e->state = neigh_is_connected(neigh) ? + L2T_STATE_VALID : L2T_STATE_STALE; + if (memcmp(e->dmac, neigh->ha, 6)) + setup_l2e_send_pending(dev, NULL, e); + } + } + spin_unlock_bh(&e->lock); + + if (arpq) + handle_failed_resolution(dev, arpq); +} + +struct l2t_data *t3_init_l2t(unsigned int l2t_capacity) +{ + struct l2t_data *d; + int i, size = sizeof(*d) + l2t_capacity * sizeof(struct l2t_entry); + + d = cxgb_alloc_mem(size); + if (!d) + return NULL; + + d->nentries = l2t_capacity; + d->rover = &d->l2tab[1]; /* entry 0 is not used */ + atomic_set(&d->nfree, l2t_capacity - 1); + rwlock_init(&d->lock); + + for (i = 0; i < l2t_capacity; ++i) { + d->l2tab[i].idx = i; + d->l2tab[i].state = L2T_STATE_UNUSED; + spin_lock_init(&d->l2tab[i].lock); + atomic_set(&d->l2tab[i].refcnt, 0); + } + return d; +} + +void t3_free_l2t(struct l2t_data *d) +{ + cxgb_free_mem(d); +} + diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h new file mode 100644 index 000000000000..ba5d2cbd7241 --- /dev/null +++ b/drivers/net/cxgb3/l2t.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _CHELSIO_L2T_H +#define _CHELSIO_L2T_H + +#include +#include "t3cdev.h" +#include + +enum { + L2T_STATE_VALID, /* entry is up to date */ + L2T_STATE_STALE, /* entry may be used but needs revalidation */ + L2T_STATE_RESOLVING, /* entry needs address resolution */ + L2T_STATE_UNUSED /* entry not in use */ +}; + +struct neighbour; +struct sk_buff; + +/* + * Each L2T entry plays multiple roles. First of all, it keeps state for the + * corresponding entry of the HW L2 table and maintains a queue of offload + * packets awaiting address resolution. Second, it is a node of a hash table + * chain, where the nodes of the chain are linked together through their next + * pointer. Finally, each node is a bucket of a hash table, pointing to the + * first element in its chain through its first pointer. + */ +struct l2t_entry { + u16 state; /* entry state */ + u16 idx; /* entry index */ + u32 addr; /* dest IP address */ + int ifindex; /* neighbor's net_device's ifindex */ + u16 smt_idx; /* SMT index */ + u16 vlan; /* VLAN TCI (id: bits 0-11, prio: 13-15 */ + struct neighbour *neigh; /* associated neighbour */ + struct l2t_entry *first; /* start of hash chain */ + struct l2t_entry *next; /* next l2t_entry on chain */ + struct sk_buff *arpq_head; /* queue of packets awaiting resolution */ + struct sk_buff *arpq_tail; + spinlock_t lock; + atomic_t refcnt; /* entry reference count */ + u8 dmac[6]; /* neighbour's MAC address */ +}; + +struct l2t_data { + unsigned int nentries; /* number of entries */ + struct l2t_entry *rover; /* starting point for next allocation */ + atomic_t nfree; /* number of free entries */ + rwlock_t lock; + struct l2t_entry l2tab[0]; +}; + +typedef void (*arp_failure_handler_func)(struct t3cdev * dev, + struct sk_buff * skb); + +/* + * Callback stored in an skb to handle address resolution failure. + */ +struct l2t_skb_cb { + arp_failure_handler_func arp_failure_handler; +}; + +#define L2T_SKB_CB(skb) ((struct l2t_skb_cb *)(skb)->cb) + +static inline void set_arp_failure_handler(struct sk_buff *skb, + arp_failure_handler_func hnd) +{ + L2T_SKB_CB(skb)->arp_failure_handler = hnd; +} + +/* + * Getting to the L2 data from an offload device. + */ +#define L2DATA(dev) ((dev)->l2opt) + +#define W_TCB_L2T_IX 0 +#define S_TCB_L2T_IX 7 +#define M_TCB_L2T_IX 0x7ffULL +#define V_TCB_L2T_IX(x) ((x) << S_TCB_L2T_IX) + +void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e); +void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh); +struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, + struct net_device *dev); +int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb, + struct l2t_entry *e); +void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e); +struct l2t_data *t3_init_l2t(unsigned int l2t_capacity); +void t3_free_l2t(struct l2t_data *d); + +int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb); + +static inline int l2t_send(struct t3cdev *dev, struct sk_buff *skb, + struct l2t_entry *e) +{ + if (likely(e->state == L2T_STATE_VALID)) + return cxgb3_ofld_send(dev, skb); + return t3_l2t_send_slow(dev, skb, e); +} + +static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e) +{ + if (atomic_dec_and_test(&e->refcnt)) + t3_l2e_free(d, e); +} + +static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e) +{ + if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */ + atomic_dec(&d->nfree); +} + +#endif diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c new file mode 100644 index 000000000000..644d62ea86a6 --- /dev/null +++ b/drivers/net/cxgb3/mc5.c @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" +#include "regs.h" + +enum { + IDT75P52100 = 4, + IDT75N43102 = 5 +}; + +/* DBGI command mode */ +enum { + DBGI_MODE_MBUS = 0, + DBGI_MODE_IDT52100 = 5 +}; + +/* IDT 75P52100 commands */ +#define IDT_CMD_READ 0 +#define IDT_CMD_WRITE 1 +#define IDT_CMD_SEARCH 2 +#define IDT_CMD_LEARN 3 + +/* IDT LAR register address and value for 144-bit mode (low 32 bits) */ +#define IDT_LAR_ADR0 0x180006 +#define IDT_LAR_MODE144 0xffff0000 + +/* IDT SCR and SSR addresses (low 32 bits) */ +#define IDT_SCR_ADR0 0x180000 +#define IDT_SSR0_ADR0 0x180002 +#define IDT_SSR1_ADR0 0x180004 + +/* IDT GMR base address (low 32 bits) */ +#define IDT_GMR_BASE_ADR0 0x180020 + +/* IDT data and mask array base addresses (low 32 bits) */ +#define IDT_DATARY_BASE_ADR0 0 +#define IDT_MSKARY_BASE_ADR0 0x80000 + +/* IDT 75N43102 commands */ +#define IDT4_CMD_SEARCH144 3 +#define IDT4_CMD_WRITE 4 +#define IDT4_CMD_READ 5 + +/* IDT 75N43102 SCR address (low 32 bits) */ +#define IDT4_SCR_ADR0 0x3 + +/* IDT 75N43102 GMR base addresses (low 32 bits) */ +#define IDT4_GMR_BASE0 0x10 +#define IDT4_GMR_BASE1 0x20 +#define IDT4_GMR_BASE2 0x30 + +/* IDT 75N43102 data and mask array base addresses (low 32 bits) */ +#define IDT4_DATARY_BASE_ADR0 0x1000000 +#define IDT4_MSKARY_BASE_ADR0 0x2000000 + +#define MAX_WRITE_ATTEMPTS 5 + +#define MAX_ROUTES 2048 + +/* + * Issue a command to the TCAM and wait for its completion. The address and + * any data required by the command must have been setup by the caller. + */ +static int mc5_cmd_write(struct adapter *adapter, u32 cmd) +{ + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_CMD, cmd); + return t3_wait_op_done(adapter, A_MC5_DB_DBGI_RSP_STATUS, + F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1); +} + +static inline void dbgi_wr_addr3(struct adapter *adapter, u32 v1, u32 v2, + u32 v3) +{ + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, v1); + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR1, v2); + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR2, v3); +} + +static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2, + u32 v3) +{ + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA0, v1); + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA1, v2); + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3); +} + +static inline void dbgi_rd_rsp3(struct adapter *adapter, u32 *v1, u32 *v2, + u32 *v3) +{ + *v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0); + *v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1); + *v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2); +} + +/* + * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM + * command cmd. The data to be written must have been set up by the caller. + * Returns -1 on failure, 0 on success. + */ +static int mc5_write(struct adapter *adapter, u32 addr_lo, u32 cmd) +{ + t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, addr_lo); + if (mc5_cmd_write(adapter, cmd) == 0) + return 0; + CH_ERR(adapter, "MC5 timeout writing to TCAM address 0x%x\n", + addr_lo); + return -1; +} + +static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base, + u32 data_array_base, u32 write_cmd, + int addr_shift) +{ + unsigned int i; + struct adapter *adap = mc5->adapter; + + /* + * We need the size of the TCAM data and mask arrays in terms of + * 72-bit entries. + */ + unsigned int size72 = mc5->tcam_size; + unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX); + + if (mc5->mode == MC5_MODE_144_BIT) { + size72 *= 2; /* 1 144-bit entry is 2 72-bit entries */ + server_base *= 2; + } + + /* Clear the data array */ + dbgi_wr_data3(adap, 0, 0, 0); + for (i = 0; i < size72; i++) + if (mc5_write(adap, data_array_base + (i << addr_shift), + write_cmd)) + return -1; + + /* Initialize the mask array. */ + dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); + for (i = 0; i < size72; i++) { + if (i == server_base) /* entering server or routing region */ + t3_write_reg(adap, A_MC5_DB_DBGI_REQ_DATA0, + mc5->mode == MC5_MODE_144_BIT ? + 0xfffffff9 : 0xfffffffd); + if (mc5_write(adap, mask_array_base + (i << addr_shift), + write_cmd)) + return -1; + } + return 0; +} + +static int init_idt52100(struct mc5 *mc5) +{ + int i; + struct adapter *adap = mc5->adapter; + + t3_write_reg(adap, A_MC5_DB_RSP_LATENCY, + V_RDLAT(0x15) | V_LRNLAT(0x15) | V_SRCHLAT(0x15)); + t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 2); + + /* + * Use GMRs 14-15 for ELOOKUP, GMRs 12-13 for SYN lookups, and + * GMRs 8-9 for ACK- and AOPEN searches. + */ + t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, IDT_CMD_SEARCH); + t3_write_reg(adap, A_MC5_DB_AOPEN_LRN_CMD, IDT_CMD_LEARN); + t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT_CMD_SEARCH | 0x6000); + t3_write_reg(adap, A_MC5_DB_SYN_LRN_CMD, IDT_CMD_LEARN); + t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT_CMD_SEARCH); + t3_write_reg(adap, A_MC5_DB_ACK_LRN_CMD, IDT_CMD_LEARN); + t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT_CMD_SEARCH); + t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT_CMD_SEARCH | 0x7000); + t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT_CMD_READ); + + /* Set DBGI command mode for IDT TCAM. */ + t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100); + + /* Set up LAR */ + dbgi_wr_data3(adap, IDT_LAR_MODE144, 0, 0); + if (mc5_write(adap, IDT_LAR_ADR0, IDT_CMD_WRITE)) + goto err; + + /* Set up SSRs */ + dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0); + if (mc5_write(adap, IDT_SSR0_ADR0, IDT_CMD_WRITE) || + mc5_write(adap, IDT_SSR1_ADR0, IDT_CMD_WRITE)) + goto err; + + /* Set up GMRs */ + for (i = 0; i < 32; ++i) { + if (i >= 12 && i < 15) + dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff); + else if (i == 15) + dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff); + else + dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); + + if (mc5_write(adap, IDT_GMR_BASE_ADR0 + i, IDT_CMD_WRITE)) + goto err; + } + + /* Set up SCR */ + dbgi_wr_data3(adap, 1, 0, 0); + if (mc5_write(adap, IDT_SCR_ADR0, IDT_CMD_WRITE)) + goto err; + + return init_mask_data_array(mc5, IDT_MSKARY_BASE_ADR0, + IDT_DATARY_BASE_ADR0, IDT_CMD_WRITE, 0); +err: + return -EIO; +} + +static int init_idt43102(struct mc5 *mc5) +{ + int i; + struct adapter *adap = mc5->adapter; + + t3_write_reg(adap, A_MC5_DB_RSP_LATENCY, + adap->params.rev == 0 ? V_RDLAT(0xd) | V_SRCHLAT(0x11) : + V_RDLAT(0xd) | V_SRCHLAT(0x12)); + + /* + * Use GMRs 24-25 for ELOOKUP, GMRs 20-21 for SYN lookups, and no mask + * for ACK- and AOPEN searches. + */ + t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT4_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT4_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, + IDT4_CMD_SEARCH144 | 0x3800); + t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT4_CMD_SEARCH144); + t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT4_CMD_SEARCH144 | 0x3800); + t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x3800); + t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x800); + t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT4_CMD_WRITE); + t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT4_CMD_READ); + + t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 3); + + /* Set DBGI command mode for IDT TCAM. */ + t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100); + + /* Set up GMRs */ + dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff); + for (i = 0; i < 7; ++i) + if (mc5_write(adap, IDT4_GMR_BASE0 + i, IDT4_CMD_WRITE)) + goto err; + + for (i = 0; i < 4; ++i) + if (mc5_write(adap, IDT4_GMR_BASE2 + i, IDT4_CMD_WRITE)) + goto err; + + dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff); + if (mc5_write(adap, IDT4_GMR_BASE1, IDT4_CMD_WRITE) || + mc5_write(adap, IDT4_GMR_BASE1 + 1, IDT4_CMD_WRITE) || + mc5_write(adap, IDT4_GMR_BASE1 + 4, IDT4_CMD_WRITE)) + goto err; + + dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff); + if (mc5_write(adap, IDT4_GMR_BASE1 + 5, IDT4_CMD_WRITE)) + goto err; + + /* Set up SCR */ + dbgi_wr_data3(adap, 0xf0000000, 0, 0); + if (mc5_write(adap, IDT4_SCR_ADR0, IDT4_CMD_WRITE)) + goto err; + + return init_mask_data_array(mc5, IDT4_MSKARY_BASE_ADR0, + IDT4_DATARY_BASE_ADR0, IDT4_CMD_WRITE, 1); +err: + return -EIO; +} + +/* Put MC5 in DBGI mode. */ +static inline void mc5_dbgi_mode_enable(const struct mc5 *mc5) +{ + t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG, + V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_DBGIEN); +} + +/* Put MC5 in M-Bus mode. */ +static void mc5_dbgi_mode_disable(const struct mc5 *mc5) +{ + t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG, + V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | + V_COMPEN(mc5->mode == MC5_MODE_72_BIT) | + V_PRTYEN(mc5->parity_enabled) | F_MBUSEN); +} + +/* + * Initialization that requires the OS and protocol layers to already + * be intialized goes here. + */ +int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, + unsigned int nroutes) +{ + u32 cfg; + int err; + unsigned int tcam_size = mc5->tcam_size; + struct adapter *adap = mc5->adapter; + + if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size) + return -EINVAL; + + /* Reset the TCAM */ + cfg = t3_read_reg(adap, A_MC5_DB_CONFIG) & ~F_TMMODE; + cfg |= V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_TMRST; + t3_write_reg(adap, A_MC5_DB_CONFIG, cfg); + if (t3_wait_op_done(adap, A_MC5_DB_CONFIG, F_TMRDY, 1, 500, 0)) { + CH_ERR(adap, "TCAM reset timed out\n"); + return -1; + } + + t3_write_reg(adap, A_MC5_DB_ROUTING_TABLE_INDEX, tcam_size - nroutes); + t3_write_reg(adap, A_MC5_DB_FILTER_TABLE, + tcam_size - nroutes - nfilters); + t3_write_reg(adap, A_MC5_DB_SERVER_INDEX, + tcam_size - nroutes - nfilters - nservers); + + mc5->parity_enabled = 1; + + /* All the TCAM addresses we access have only the low 32 bits non 0 */ + t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR1, 0); + t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR2, 0); + + mc5_dbgi_mode_enable(mc5); + + switch (mc5->part_type) { + case IDT75P52100: + err = init_idt52100(mc5); + break; + case IDT75N43102: + err = init_idt43102(mc5); + break; + default: + CH_ERR(adap, "Unsupported TCAM type %d\n", mc5->part_type); + err = -EINVAL; + break; + } + + mc5_dbgi_mode_disable(mc5); + return err; +} + +/* + * read_mc5_range - dump a part of the memory managed by MC5 + * @mc5: the MC5 handle + * @start: the start address for the dump + * @n: number of 72-bit words to read + * @buf: result buffer + * + * Read n 72-bit words from MC5 memory from the given start location. + */ +int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start, + unsigned int n, u32 *buf) +{ + u32 read_cmd; + int err = 0; + struct adapter *adap = mc5->adapter; + + if (mc5->part_type == IDT75P52100) + read_cmd = IDT_CMD_READ; + else if (mc5->part_type == IDT75N43102) + read_cmd = IDT4_CMD_READ; + else + return -EINVAL; + + mc5_dbgi_mode_enable(mc5); + + while (n--) { + t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR0, start++); + if (mc5_cmd_write(adap, read_cmd)) { + err = -EIO; + break; + } + dbgi_rd_rsp3(adap, buf + 2, buf + 1, buf); + buf += 3; + } + + mc5_dbgi_mode_disable(mc5); + return 0; +} + +#define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR) + +/* + * MC5 interrupt handler + */ +void t3_mc5_intr_handler(struct mc5 *mc5) +{ + struct adapter *adap = mc5->adapter; + u32 cause = t3_read_reg(adap, A_MC5_DB_INT_CAUSE); + + if ((cause & F_PARITYERR) && mc5->parity_enabled) { + CH_ALERT(adap, "MC5 parity error\n"); + mc5->stats.parity_err++; + } + + if (cause & F_REQQPARERR) { + CH_ALERT(adap, "MC5 request queue parity error\n"); + mc5->stats.reqq_parity_err++; + } + + if (cause & F_DISPQPARERR) { + CH_ALERT(adap, "MC5 dispatch queue parity error\n"); + mc5->stats.dispq_parity_err++; + } + + if (cause & F_ACTRGNFULL) + mc5->stats.active_rgn_full++; + if (cause & F_NFASRCHFAIL) + mc5->stats.nfa_srch_err++; + if (cause & F_UNKNOWNCMD) + mc5->stats.unknown_cmd++; + if (cause & F_DELACTEMPTY) + mc5->stats.del_act_empty++; + if (cause & MC5_INT_FATAL) + t3_fatal_err(adap); + + t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause); +} + +void __devinit t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode) +{ +#define K * 1024 + + static unsigned int tcam_part_size[] = { /* in K 72-bit entries */ + 64 K, 128 K, 256 K, 32 K + }; + +#undef K + + u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG); + + mc5->adapter = adapter; + mc5->mode = (unsigned char)mode; + mc5->part_type = (unsigned char)G_TMTYPE(cfg); + if (cfg & F_TMTYPEHI) + mc5->part_type |= 4; + + mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)]; + if (mode == MC5_MODE_144_BIT) + mc5->tcam_size /= 2; +} diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h new file mode 100644 index 000000000000..b56c5f52bcdc --- /dev/null +++ b/drivers/net/cxgb3/regs.h @@ -0,0 +1,2195 @@ +#define A_SG_CONTROL 0x0 + +#define S_DROPPKT 20 +#define V_DROPPKT(x) ((x) << S_DROPPKT) +#define F_DROPPKT V_DROPPKT(1U) + +#define S_EGRGENCTRL 19 +#define V_EGRGENCTRL(x) ((x) << S_EGRGENCTRL) +#define F_EGRGENCTRL V_EGRGENCTRL(1U) + +#define S_USERSPACESIZE 14 +#define M_USERSPACESIZE 0x1f +#define V_USERSPACESIZE(x) ((x) << S_USERSPACESIZE) + +#define S_HOSTPAGESIZE 11 +#define M_HOSTPAGESIZE 0x7 +#define V_HOSTPAGESIZE(x) ((x) << S_HOSTPAGESIZE) + +#define S_FLMODE 9 +#define V_FLMODE(x) ((x) << S_FLMODE) +#define F_FLMODE V_FLMODE(1U) + +#define S_PKTSHIFT 6 +#define M_PKTSHIFT 0x7 +#define V_PKTSHIFT(x) ((x) << S_PKTSHIFT) + +#define S_ONEINTMULTQ 5 +#define V_ONEINTMULTQ(x) ((x) << S_ONEINTMULTQ) +#define F_ONEINTMULTQ V_ONEINTMULTQ(1U) + +#define S_BIGENDIANINGRESS 2 +#define V_BIGENDIANINGRESS(x) ((x) << S_BIGENDIANINGRESS) +#define F_BIGENDIANINGRESS V_BIGENDIANINGRESS(1U) + +#define S_ISCSICOALESCING 1 +#define V_ISCSICOALESCING(x) ((x) << S_ISCSICOALESCING) +#define F_ISCSICOALESCING V_ISCSICOALESCING(1U) + +#define S_GLOBALENABLE 0 +#define V_GLOBALENABLE(x) ((x) << S_GLOBALENABLE) +#define F_GLOBALENABLE V_GLOBALENABLE(1U) + +#define S_AVOIDCQOVFL 24 +#define V_AVOIDCQOVFL(x) ((x) << S_AVOIDCQOVFL) +#define F_AVOIDCQOVFL V_AVOIDCQOVFL(1U) + +#define S_OPTONEINTMULTQ 23 +#define V_OPTONEINTMULTQ(x) ((x) << S_OPTONEINTMULTQ) +#define F_OPTONEINTMULTQ V_OPTONEINTMULTQ(1U) + +#define S_CQCRDTCTRL 22 +#define V_CQCRDTCTRL(x) ((x) << S_CQCRDTCTRL) +#define F_CQCRDTCTRL V_CQCRDTCTRL(1U) + +#define A_SG_KDOORBELL 0x4 + +#define S_SELEGRCNTX 31 +#define V_SELEGRCNTX(x) ((x) << S_SELEGRCNTX) +#define F_SELEGRCNTX V_SELEGRCNTX(1U) + +#define S_EGRCNTX 0 +#define M_EGRCNTX 0xffff +#define V_EGRCNTX(x) ((x) << S_EGRCNTX) + +#define A_SG_GTS 0x8 + +#define S_RSPQ 29 +#define M_RSPQ 0x7 +#define V_RSPQ(x) ((x) << S_RSPQ) +#define G_RSPQ(x) (((x) >> S_RSPQ) & M_RSPQ) + +#define S_NEWTIMER 16 +#define M_NEWTIMER 0x1fff +#define V_NEWTIMER(x) ((x) << S_NEWTIMER) + +#define S_NEWINDEX 0 +#define M_NEWINDEX 0xffff +#define V_NEWINDEX(x) ((x) << S_NEWINDEX) + +#define A_SG_CONTEXT_CMD 0xc + +#define S_CONTEXT_CMD_OPCODE 28 +#define M_CONTEXT_CMD_OPCODE 0xf +#define V_CONTEXT_CMD_OPCODE(x) ((x) << S_CONTEXT_CMD_OPCODE) + +#define S_CONTEXT_CMD_BUSY 27 +#define V_CONTEXT_CMD_BUSY(x) ((x) << S_CONTEXT_CMD_BUSY) +#define F_CONTEXT_CMD_BUSY V_CONTEXT_CMD_BUSY(1U) + +#define S_CQ_CREDIT 20 + +#define M_CQ_CREDIT 0x7f + +#define V_CQ_CREDIT(x) ((x) << S_CQ_CREDIT) + +#define G_CQ_CREDIT(x) (((x) >> S_CQ_CREDIT) & M_CQ_CREDIT) + +#define S_CQ 19 + +#define V_CQ(x) ((x) << S_CQ) +#define F_CQ V_CQ(1U) + +#define S_RESPONSEQ 18 +#define V_RESPONSEQ(x) ((x) << S_RESPONSEQ) +#define F_RESPONSEQ V_RESPONSEQ(1U) + +#define S_EGRESS 17 +#define V_EGRESS(x) ((x) << S_EGRESS) +#define F_EGRESS V_EGRESS(1U) + +#define S_FREELIST 16 +#define V_FREELIST(x) ((x) << S_FREELIST) +#define F_FREELIST V_FREELIST(1U) + +#define S_CONTEXT 0 +#define M_CONTEXT 0xffff +#define V_CONTEXT(x) ((x) << S_CONTEXT) + +#define G_CONTEXT(x) (((x) >> S_CONTEXT) & M_CONTEXT) + +#define A_SG_CONTEXT_DATA0 0x10 + +#define A_SG_CONTEXT_DATA1 0x14 + +#define A_SG_CONTEXT_DATA2 0x18 + +#define A_SG_CONTEXT_DATA3 0x1c + +#define A_SG_CONTEXT_MASK0 0x20 + +#define A_SG_CONTEXT_MASK1 0x24 + +#define A_SG_CONTEXT_MASK2 0x28 + +#define A_SG_CONTEXT_MASK3 0x2c + +#define A_SG_RSPQ_CREDIT_RETURN 0x30 + +#define S_CREDITS 0 +#define M_CREDITS 0xffff +#define V_CREDITS(x) ((x) << S_CREDITS) + +#define A_SG_DATA_INTR 0x34 + +#define S_ERRINTR 31 +#define V_ERRINTR(x) ((x) << S_ERRINTR) +#define F_ERRINTR V_ERRINTR(1U) + +#define A_SG_HI_DRB_HI_THRSH 0x38 + +#define A_SG_HI_DRB_LO_THRSH 0x3c + +#define A_SG_LO_DRB_HI_THRSH 0x40 + +#define A_SG_LO_DRB_LO_THRSH 0x44 + +#define A_SG_RSPQ_FL_STATUS 0x4c + +#define S_RSPQ0DISABLED 8 + +#define A_SG_EGR_RCQ_DRB_THRSH 0x54 + +#define S_HIRCQDRBTHRSH 16 +#define M_HIRCQDRBTHRSH 0x7ff +#define V_HIRCQDRBTHRSH(x) ((x) << S_HIRCQDRBTHRSH) + +#define S_LORCQDRBTHRSH 0 +#define M_LORCQDRBTHRSH 0x7ff +#define V_LORCQDRBTHRSH(x) ((x) << S_LORCQDRBTHRSH) + +#define A_SG_EGR_CNTX_BADDR 0x58 + +#define A_SG_INT_CAUSE 0x5c + +#define S_RSPQDISABLED 3 +#define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED) +#define F_RSPQDISABLED V_RSPQDISABLED(1U) + +#define S_RSPQCREDITOVERFOW 2 +#define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW) +#define F_RSPQCREDITOVERFOW V_RSPQCREDITOVERFOW(1U) + +#define A_SG_INT_ENABLE 0x60 + +#define A_SG_CMDQ_CREDIT_TH 0x64 + +#define S_TIMEOUT 8 +#define M_TIMEOUT 0xffffff +#define V_TIMEOUT(x) ((x) << S_TIMEOUT) + +#define S_THRESHOLD 0 +#define M_THRESHOLD 0xff +#define V_THRESHOLD(x) ((x) << S_THRESHOLD) + +#define A_SG_TIMER_TICK 0x68 + +#define A_SG_CQ_CONTEXT_BADDR 0x6c + +#define A_SG_OCO_BASE 0x70 + +#define S_BASE1 16 +#define M_BASE1 0xffff +#define V_BASE1(x) ((x) << S_BASE1) + +#define A_SG_DRB_PRI_THRESH 0x74 + +#define A_PCIX_INT_ENABLE 0x80 + +#define S_MSIXPARERR 22 +#define M_MSIXPARERR 0x7 + +#define V_MSIXPARERR(x) ((x) << S_MSIXPARERR) + +#define S_CFPARERR 18 +#define M_CFPARERR 0xf + +#define V_CFPARERR(x) ((x) << S_CFPARERR) + +#define S_RFPARERR 14 +#define M_RFPARERR 0xf + +#define V_RFPARERR(x) ((x) << S_RFPARERR) + +#define S_WFPARERR 12 +#define M_WFPARERR 0x3 + +#define V_WFPARERR(x) ((x) << S_WFPARERR) + +#define S_PIOPARERR 11 +#define V_PIOPARERR(x) ((x) << S_PIOPARERR) +#define F_PIOPARERR V_PIOPARERR(1U) + +#define S_DETUNCECCERR 10 +#define V_DETUNCECCERR(x) ((x) << S_DETUNCECCERR) +#define F_DETUNCECCERR V_DETUNCECCERR(1U) + +#define S_DETCORECCERR 9 +#define V_DETCORECCERR(x) ((x) << S_DETCORECCERR) +#define F_DETCORECCERR V_DETCORECCERR(1U) + +#define S_RCVSPLCMPERR 8 +#define V_RCVSPLCMPERR(x) ((x) << S_RCVSPLCMPERR) +#define F_RCVSPLCMPERR V_RCVSPLCMPERR(1U) + +#define S_UNXSPLCMP 7 +#define V_UNXSPLCMP(x) ((x) << S_UNXSPLCMP) +#define F_UNXSPLCMP V_UNXSPLCMP(1U) + +#define S_SPLCMPDIS 6 +#define V_SPLCMPDIS(x) ((x) << S_SPLCMPDIS) +#define F_SPLCMPDIS V_SPLCMPDIS(1U) + +#define S_DETPARERR 5 +#define V_DETPARERR(x) ((x) << S_DETPARERR) +#define F_DETPARERR V_DETPARERR(1U) + +#define S_SIGSYSERR 4 +#define V_SIGSYSERR(x) ((x) << S_SIGSYSERR) +#define F_SIGSYSERR V_SIGSYSERR(1U) + +#define S_RCVMSTABT 3 +#define V_RCVMSTABT(x) ((x) << S_RCVMSTABT) +#define F_RCVMSTABT V_RCVMSTABT(1U) + +#define S_RCVTARABT 2 +#define V_RCVTARABT(x) ((x) << S_RCVTARABT) +#define F_RCVTARABT V_RCVTARABT(1U) + +#define S_SIGTARABT 1 +#define V_SIGTARABT(x) ((x) << S_SIGTARABT) +#define F_SIGTARABT V_SIGTARABT(1U) + +#define S_MSTDETPARERR 0 +#define V_MSTDETPARERR(x) ((x) << S_MSTDETPARERR) +#define F_MSTDETPARERR V_MSTDETPARERR(1U) + +#define A_PCIX_INT_CAUSE 0x84 + +#define A_PCIX_CFG 0x88 + +#define S_CLIDECEN 18 +#define V_CLIDECEN(x) ((x) << S_CLIDECEN) +#define F_CLIDECEN V_CLIDECEN(1U) + +#define A_PCIX_MODE 0x8c + +#define S_PCLKRANGE 6 +#define M_PCLKRANGE 0x3 +#define V_PCLKRANGE(x) ((x) << S_PCLKRANGE) +#define G_PCLKRANGE(x) (((x) >> S_PCLKRANGE) & M_PCLKRANGE) + +#define S_PCIXINITPAT 2 +#define M_PCIXINITPAT 0xf +#define V_PCIXINITPAT(x) ((x) << S_PCIXINITPAT) +#define G_PCIXINITPAT(x) (((x) >> S_PCIXINITPAT) & M_PCIXINITPAT) + +#define S_64BIT 0 +#define V_64BIT(x) ((x) << S_64BIT) +#define F_64BIT V_64BIT(1U) + +#define A_PCIE_INT_ENABLE 0x80 + +#define S_BISTERR 15 +#define M_BISTERR 0xff + +#define V_BISTERR(x) ((x) << S_BISTERR) + +#define S_PCIE_MSIXPARERR 12 +#define M_PCIE_MSIXPARERR 0x7 + +#define V_PCIE_MSIXPARERR(x) ((x) << S_PCIE_MSIXPARERR) + +#define S_PCIE_CFPARERR 11 +#define V_PCIE_CFPARERR(x) ((x) << S_PCIE_CFPARERR) +#define F_PCIE_CFPARERR V_PCIE_CFPARERR(1U) + +#define S_PCIE_RFPARERR 10 +#define V_PCIE_RFPARERR(x) ((x) << S_PCIE_RFPARERR) +#define F_PCIE_RFPARERR V_PCIE_RFPARERR(1U) + +#define S_PCIE_WFPARERR 9 +#define V_PCIE_WFPARERR(x) ((x) << S_PCIE_WFPARERR) +#define F_PCIE_WFPARERR V_PCIE_WFPARERR(1U) + +#define S_PCIE_PIOPARERR 8 +#define V_PCIE_PIOPARERR(x) ((x) << S_PCIE_PIOPARERR) +#define F_PCIE_PIOPARERR V_PCIE_PIOPARERR(1U) + +#define S_UNXSPLCPLERRC 7 +#define V_UNXSPLCPLERRC(x) ((x) << S_UNXSPLCPLERRC) +#define F_UNXSPLCPLERRC V_UNXSPLCPLERRC(1U) + +#define S_UNXSPLCPLERRR 6 +#define V_UNXSPLCPLERRR(x) ((x) << S_UNXSPLCPLERRR) +#define F_UNXSPLCPLERRR V_UNXSPLCPLERRR(1U) + +#define S_PEXERR 0 +#define V_PEXERR(x) ((x) << S_PEXERR) +#define F_PEXERR V_PEXERR(1U) + +#define A_PCIE_INT_CAUSE 0x84 + +#define A_PCIE_CFG 0x88 + +#define S_PCIE_CLIDECEN 16 +#define V_PCIE_CLIDECEN(x) ((x) << S_PCIE_CLIDECEN) +#define F_PCIE_CLIDECEN V_PCIE_CLIDECEN(1U) + +#define S_CRSTWRMMODE 0 +#define V_CRSTWRMMODE(x) ((x) << S_CRSTWRMMODE) +#define F_CRSTWRMMODE V_CRSTWRMMODE(1U) + +#define A_PCIE_MODE 0x8c + +#define S_NUMFSTTRNSEQRX 10 +#define M_NUMFSTTRNSEQRX 0xff +#define V_NUMFSTTRNSEQRX(x) ((x) << S_NUMFSTTRNSEQRX) +#define G_NUMFSTTRNSEQRX(x) (((x) >> S_NUMFSTTRNSEQRX) & M_NUMFSTTRNSEQRX) + +#define A_PCIE_PEX_CTRL0 0x98 + +#define S_NUMFSTTRNSEQ 22 +#define M_NUMFSTTRNSEQ 0xff +#define V_NUMFSTTRNSEQ(x) ((x) << S_NUMFSTTRNSEQ) +#define G_NUMFSTTRNSEQ(x) (((x) >> S_NUMFSTTRNSEQ) & M_NUMFSTTRNSEQ) + +#define S_REPLAYLMT 2 +#define M_REPLAYLMT 0xfffff + +#define V_REPLAYLMT(x) ((x) << S_REPLAYLMT) + +#define A_PCIE_PEX_CTRL1 0x9c + +#define S_T3A_ACKLAT 0 +#define M_T3A_ACKLAT 0x7ff + +#define V_T3A_ACKLAT(x) ((x) << S_T3A_ACKLAT) + +#define S_ACKLAT 0 +#define M_ACKLAT 0x1fff + +#define V_ACKLAT(x) ((x) << S_ACKLAT) + +#define A_PCIE_PEX_ERR 0xa4 + +#define A_T3DBG_GPIO_EN 0xd0 + +#define S_GPIO11_OEN 27 +#define V_GPIO11_OEN(x) ((x) << S_GPIO11_OEN) +#define F_GPIO11_OEN V_GPIO11_OEN(1U) + +#define S_GPIO10_OEN 26 +#define V_GPIO10_OEN(x) ((x) << S_GPIO10_OEN) +#define F_GPIO10_OEN V_GPIO10_OEN(1U) + +#define S_GPIO7_OEN 23 +#define V_GPIO7_OEN(x) ((x) << S_GPIO7_OEN) +#define F_GPIO7_OEN V_GPIO7_OEN(1U) + +#define S_GPIO6_OEN 22 +#define V_GPIO6_OEN(x) ((x) << S_GPIO6_OEN) +#define F_GPIO6_OEN V_GPIO6_OEN(1U) + +#define S_GPIO5_OEN 21 +#define V_GPIO5_OEN(x) ((x) << S_GPIO5_OEN) +#define F_GPIO5_OEN V_GPIO5_OEN(1U) + +#define S_GPIO4_OEN 20 +#define V_GPIO4_OEN(x) ((x) << S_GPIO4_OEN) +#define F_GPIO4_OEN V_GPIO4_OEN(1U) + +#define S_GPIO2_OEN 18 +#define V_GPIO2_OEN(x) ((x) << S_GPIO2_OEN) +#define F_GPIO2_OEN V_GPIO2_OEN(1U) + +#define S_GPIO1_OEN 17 +#define V_GPIO1_OEN(x) ((x) << S_GPIO1_OEN) +#define F_GPIO1_OEN V_GPIO1_OEN(1U) + +#define S_GPIO0_OEN 16 +#define V_GPIO0_OEN(x) ((x) << S_GPIO0_OEN) +#define F_GPIO0_OEN V_GPIO0_OEN(1U) + +#define S_GPIO10_OUT_VAL 10 +#define V_GPIO10_OUT_VAL(x) ((x) << S_GPIO10_OUT_VAL) +#define F_GPIO10_OUT_VAL V_GPIO10_OUT_VAL(1U) + +#define S_GPIO7_OUT_VAL 7 +#define V_GPIO7_OUT_VAL(x) ((x) << S_GPIO7_OUT_VAL) +#define F_GPIO7_OUT_VAL V_GPIO7_OUT_VAL(1U) + +#define S_GPIO6_OUT_VAL 6 +#define V_GPIO6_OUT_VAL(x) ((x) << S_GPIO6_OUT_VAL) +#define F_GPIO6_OUT_VAL V_GPIO6_OUT_VAL(1U) + +#define S_GPIO5_OUT_VAL 5 +#define V_GPIO5_OUT_VAL(x) ((x) << S_GPIO5_OUT_VAL) +#define F_GPIO5_OUT_VAL V_GPIO5_OUT_VAL(1U) + +#define S_GPIO4_OUT_VAL 4 +#define V_GPIO4_OUT_VAL(x) ((x) << S_GPIO4_OUT_VAL) +#define F_GPIO4_OUT_VAL V_GPIO4_OUT_VAL(1U) + +#define S_GPIO2_OUT_VAL 2 +#define V_GPIO2_OUT_VAL(x) ((x) << S_GPIO2_OUT_VAL) +#define F_GPIO2_OUT_VAL V_GPIO2_OUT_VAL(1U) + +#define S_GPIO1_OUT_VAL 1 +#define V_GPIO1_OUT_VAL(x) ((x) << S_GPIO1_OUT_VAL) +#define F_GPIO1_OUT_VAL V_GPIO1_OUT_VAL(1U) + +#define S_GPIO0_OUT_VAL 0 +#define V_GPIO0_OUT_VAL(x) ((x) << S_GPIO0_OUT_VAL) +#define F_GPIO0_OUT_VAL V_GPIO0_OUT_VAL(1U) + +#define A_T3DBG_INT_ENABLE 0xd8 + +#define S_GPIO11 11 +#define V_GPIO11(x) ((x) << S_GPIO11) +#define F_GPIO11 V_GPIO11(1U) + +#define S_GPIO10 10 +#define V_GPIO10(x) ((x) << S_GPIO10) +#define F_GPIO10 V_GPIO10(1U) + +#define S_GPIO7 7 +#define V_GPIO7(x) ((x) << S_GPIO7) +#define F_GPIO7 V_GPIO7(1U) + +#define S_GPIO6 6 +#define V_GPIO6(x) ((x) << S_GPIO6) +#define F_GPIO6 V_GPIO6(1U) + +#define S_GPIO5 5 +#define V_GPIO5(x) ((x) << S_GPIO5) +#define F_GPIO5 V_GPIO5(1U) + +#define S_GPIO4 4 +#define V_GPIO4(x) ((x) << S_GPIO4) +#define F_GPIO4 V_GPIO4(1U) + +#define S_GPIO3 3 +#define V_GPIO3(x) ((x) << S_GPIO3) +#define F_GPIO3 V_GPIO3(1U) + +#define S_GPIO2 2 +#define V_GPIO2(x) ((x) << S_GPIO2) +#define F_GPIO2 V_GPIO2(1U) + +#define S_GPIO1 1 +#define V_GPIO1(x) ((x) << S_GPIO1) +#define F_GPIO1 V_GPIO1(1U) + +#define S_GPIO0 0 +#define V_GPIO0(x) ((x) << S_GPIO0) +#define F_GPIO0 V_GPIO0(1U) + +#define A_T3DBG_INT_CAUSE 0xdc + +#define A_T3DBG_GPIO_ACT_LOW 0xf0 + +#define MC7_PMRX_BASE_ADDR 0x100 + +#define A_MC7_CFG 0x100 + +#define S_IFEN 13 +#define V_IFEN(x) ((x) << S_IFEN) +#define F_IFEN V_IFEN(1U) + +#define S_TERM150 11 +#define V_TERM150(x) ((x) << S_TERM150) +#define F_TERM150 V_TERM150(1U) + +#define S_SLOW 10 +#define V_SLOW(x) ((x) << S_SLOW) +#define F_SLOW V_SLOW(1U) + +#define S_WIDTH 8 +#define M_WIDTH 0x3 +#define V_WIDTH(x) ((x) << S_WIDTH) +#define G_WIDTH(x) (((x) >> S_WIDTH) & M_WIDTH) + +#define S_BKS 6 +#define V_BKS(x) ((x) << S_BKS) +#define F_BKS V_BKS(1U) + +#define S_ORG 5 +#define V_ORG(x) ((x) << S_ORG) +#define F_ORG V_ORG(1U) + +#define S_DEN 2 +#define M_DEN 0x7 +#define V_DEN(x) ((x) << S_DEN) +#define G_DEN(x) (((x) >> S_DEN) & M_DEN) + +#define S_RDY 1 +#define V_RDY(x) ((x) << S_RDY) +#define F_RDY V_RDY(1U) + +#define S_CLKEN 0 +#define V_CLKEN(x) ((x) << S_CLKEN) +#define F_CLKEN V_CLKEN(1U) + +#define A_MC7_MODE 0x104 + +#define S_BUSY 31 +#define V_BUSY(x) ((x) << S_BUSY) +#define F_BUSY V_BUSY(1U) + +#define S_BUSY 31 +#define V_BUSY(x) ((x) << S_BUSY) +#define F_BUSY V_BUSY(1U) + +#define A_MC7_EXT_MODE1 0x108 + +#define A_MC7_EXT_MODE2 0x10c + +#define A_MC7_EXT_MODE3 0x110 + +#define A_MC7_PRE 0x114 + +#define A_MC7_REF 0x118 + +#define S_PREREFDIV 1 +#define M_PREREFDIV 0x3fff +#define V_PREREFDIV(x) ((x) << S_PREREFDIV) + +#define S_PERREFEN 0 +#define V_PERREFEN(x) ((x) << S_PERREFEN) +#define F_PERREFEN V_PERREFEN(1U) + +#define A_MC7_DLL 0x11c + +#define S_DLLENB 1 +#define V_DLLENB(x) ((x) << S_DLLENB) +#define F_DLLENB V_DLLENB(1U) + +#define S_DLLRST 0 +#define V_DLLRST(x) ((x) << S_DLLRST) +#define F_DLLRST V_DLLRST(1U) + +#define A_MC7_PARM 0x120 + +#define S_ACTTOPREDLY 26 +#define M_ACTTOPREDLY 0xf +#define V_ACTTOPREDLY(x) ((x) << S_ACTTOPREDLY) + +#define S_ACTTORDWRDLY 23 +#define M_ACTTORDWRDLY 0x7 +#define V_ACTTORDWRDLY(x) ((x) << S_ACTTORDWRDLY) + +#define S_PRECYC 20 +#define M_PRECYC 0x7 +#define V_PRECYC(x) ((x) << S_PRECYC) + +#define S_REFCYC 13 +#define M_REFCYC 0x7f +#define V_REFCYC(x) ((x) << S_REFCYC) + +#define S_BKCYC 8 +#define M_BKCYC 0x1f +#define V_BKCYC(x) ((x) << S_BKCYC) + +#define S_WRTORDDLY 4 +#define M_WRTORDDLY 0xf +#define V_WRTORDDLY(x) ((x) << S_WRTORDDLY) + +#define S_RDTOWRDLY 0 +#define M_RDTOWRDLY 0xf +#define V_RDTOWRDLY(x) ((x) << S_RDTOWRDLY) + +#define A_MC7_CAL 0x128 + +#define S_BUSY 31 +#define V_BUSY(x) ((x) << S_BUSY) +#define F_BUSY V_BUSY(1U) + +#define S_BUSY 31 +#define V_BUSY(x) ((x) << S_BUSY) +#define F_BUSY V_BUSY(1U) + +#define S_CAL_FAULT 30 +#define V_CAL_FAULT(x) ((x) << S_CAL_FAULT) +#define F_CAL_FAULT V_CAL_FAULT(1U) + +#define S_SGL_CAL_EN 20 +#define V_SGL_CAL_EN(x) ((x) << S_SGL_CAL_EN) +#define F_SGL_CAL_EN V_SGL_CAL_EN(1U) + +#define A_MC7_ERR_ADDR 0x12c + +#define A_MC7_ECC 0x130 + +#define S_ECCCHKEN 1 +#define V_ECCCHKEN(x) ((x) << S_ECCCHKEN) +#define F_ECCCHKEN V_ECCCHKEN(1U) + +#define S_ECCGENEN 0 +#define V_ECCGENEN(x) ((x) << S_ECCGENEN) +#define F_ECCGENEN V_ECCGENEN(1U) + +#define A_MC7_CE_ADDR 0x134 + +#define A_MC7_CE_DATA0 0x138 + +#define A_MC7_CE_DATA1 0x13c + +#define A_MC7_CE_DATA2 0x140 + +#define S_DATA 0 +#define M_DATA 0xff + +#define G_DATA(x) (((x) >> S_DATA) & M_DATA) + +#define A_MC7_UE_ADDR 0x144 + +#define A_MC7_UE_DATA0 0x148 + +#define A_MC7_UE_DATA1 0x14c + +#define A_MC7_UE_DATA2 0x150 + +#define A_MC7_BD_ADDR 0x154 + +#define S_ADDR 3 + +#define M_ADDR 0x1fffffff + +#define A_MC7_BD_DATA0 0x158 + +#define A_MC7_BD_DATA1 0x15c + +#define A_MC7_BD_OP 0x164 + +#define S_OP 0 + +#define V_OP(x) ((x) << S_OP) +#define F_OP V_OP(1U) + +#define F_OP V_OP(1U) +#define A_SF_OP 0x6dc + +#define A_MC7_BIST_ADDR_BEG 0x168 + +#define A_MC7_BIST_ADDR_END 0x16c + +#define A_MC7_BIST_DATA 0x170 + +#define A_MC7_BIST_OP 0x174 + +#define S_CONT 3 +#define V_CONT(x) ((x) << S_CONT) +#define F_CONT V_CONT(1U) + +#define F_CONT V_CONT(1U) + +#define A_MC7_INT_ENABLE 0x178 + +#define S_AE 17 +#define V_AE(x) ((x) << S_AE) +#define F_AE V_AE(1U) + +#define S_PE 2 +#define M_PE 0x7fff + +#define V_PE(x) ((x) << S_PE) + +#define G_PE(x) (((x) >> S_PE) & M_PE) + +#define S_UE 1 +#define V_UE(x) ((x) << S_UE) +#define F_UE V_UE(1U) + +#define S_CE 0 +#define V_CE(x) ((x) << S_CE) +#define F_CE V_CE(1U) + +#define A_MC7_INT_CAUSE 0x17c + +#define MC7_PMTX_BASE_ADDR 0x180 + +#define MC7_CM_BASE_ADDR 0x200 + +#define A_CIM_BOOT_CFG 0x280 + +#define S_BOOTADDR 2 +#define M_BOOTADDR 0x3fffffff +#define V_BOOTADDR(x) ((x) << S_BOOTADDR) + +#define A_CIM_SDRAM_BASE_ADDR 0x28c + +#define A_CIM_SDRAM_ADDR_SIZE 0x290 + +#define A_CIM_HOST_INT_ENABLE 0x298 + +#define A_CIM_HOST_INT_CAUSE 0x29c + +#define S_BLKWRPLINT 12 +#define V_BLKWRPLINT(x) ((x) << S_BLKWRPLINT) +#define F_BLKWRPLINT V_BLKWRPLINT(1U) + +#define S_BLKRDPLINT 11 +#define V_BLKRDPLINT(x) ((x) << S_BLKRDPLINT) +#define F_BLKRDPLINT V_BLKRDPLINT(1U) + +#define S_BLKWRCTLINT 10 +#define V_BLKWRCTLINT(x) ((x) << S_BLKWRCTLINT) +#define F_BLKWRCTLINT V_BLKWRCTLINT(1U) + +#define S_BLKRDCTLINT 9 +#define V_BLKRDCTLINT(x) ((x) << S_BLKRDCTLINT) +#define F_BLKRDCTLINT V_BLKRDCTLINT(1U) + +#define S_BLKWRFLASHINT 8 +#define V_BLKWRFLASHINT(x) ((x) << S_BLKWRFLASHINT) +#define F_BLKWRFLASHINT V_BLKWRFLASHINT(1U) + +#define S_BLKRDFLASHINT 7 +#define V_BLKRDFLASHINT(x) ((x) << S_BLKRDFLASHINT) +#define F_BLKRDFLASHINT V_BLKRDFLASHINT(1U) + +#define S_SGLWRFLASHINT 6 +#define V_SGLWRFLASHINT(x) ((x) << S_SGLWRFLASHINT) +#define F_SGLWRFLASHINT V_SGLWRFLASHINT(1U) + +#define S_WRBLKFLASHINT 5 +#define V_WRBLKFLASHINT(x) ((x) << S_WRBLKFLASHINT) +#define F_WRBLKFLASHINT V_WRBLKFLASHINT(1U) + +#define S_BLKWRBOOTINT 4 +#define V_BLKWRBOOTINT(x) ((x) << S_BLKWRBOOTINT) +#define F_BLKWRBOOTINT V_BLKWRBOOTINT(1U) + +#define S_FLASHRANGEINT 2 +#define V_FLASHRANGEINT(x) ((x) << S_FLASHRANGEINT) +#define F_FLASHRANGEINT V_FLASHRANGEINT(1U) + +#define S_SDRAMRANGEINT 1 +#define V_SDRAMRANGEINT(x) ((x) << S_SDRAMRANGEINT) +#define F_SDRAMRANGEINT V_SDRAMRANGEINT(1U) + +#define S_RSVDSPACEINT 0 +#define V_RSVDSPACEINT(x) ((x) << S_RSVDSPACEINT) +#define F_RSVDSPACEINT V_RSVDSPACEINT(1U) + +#define A_CIM_HOST_ACC_CTRL 0x2b0 + +#define S_HOSTBUSY 17 +#define V_HOSTBUSY(x) ((x) << S_HOSTBUSY) +#define F_HOSTBUSY V_HOSTBUSY(1U) + +#define A_CIM_HOST_ACC_DATA 0x2b4 + +#define A_TP_IN_CONFIG 0x300 + +#define S_NICMODE 14 +#define V_NICMODE(x) ((x) << S_NICMODE) +#define F_NICMODE V_NICMODE(1U) + +#define F_NICMODE V_NICMODE(1U) + +#define S_IPV6ENABLE 15 +#define V_IPV6ENABLE(x) ((x) << S_IPV6ENABLE) +#define F_IPV6ENABLE V_IPV6ENABLE(1U) + +#define A_TP_OUT_CONFIG 0x304 + +#define S_VLANEXTRACTIONENABLE 12 + +#define A_TP_GLOBAL_CONFIG 0x308 + +#define S_TXPACINGENABLE 24 +#define V_TXPACINGENABLE(x) ((x) << S_TXPACINGENABLE) +#define F_TXPACINGENABLE V_TXPACINGENABLE(1U) + +#define S_PATHMTU 15 +#define V_PATHMTU(x) ((x) << S_PATHMTU) +#define F_PATHMTU V_PATHMTU(1U) + +#define S_IPCHECKSUMOFFLOAD 13 +#define V_IPCHECKSUMOFFLOAD(x) ((x) << S_IPCHECKSUMOFFLOAD) +#define F_IPCHECKSUMOFFLOAD V_IPCHECKSUMOFFLOAD(1U) + +#define S_UDPCHECKSUMOFFLOAD 12 +#define V_UDPCHECKSUMOFFLOAD(x) ((x) << S_UDPCHECKSUMOFFLOAD) +#define F_UDPCHECKSUMOFFLOAD V_UDPCHECKSUMOFFLOAD(1U) + +#define S_TCPCHECKSUMOFFLOAD 11 +#define V_TCPCHECKSUMOFFLOAD(x) ((x) << S_TCPCHECKSUMOFFLOAD) +#define F_TCPCHECKSUMOFFLOAD V_TCPCHECKSUMOFFLOAD(1U) + +#define S_IPTTL 0 +#define M_IPTTL 0xff +#define V_IPTTL(x) ((x) << S_IPTTL) + +#define A_TP_CMM_MM_BASE 0x314 + +#define A_TP_CMM_TIMER_BASE 0x318 + +#define S_CMTIMERMAXNUM 28 +#define M_CMTIMERMAXNUM 0x3 +#define V_CMTIMERMAXNUM(x) ((x) << S_CMTIMERMAXNUM) + +#define A_TP_PMM_SIZE 0x31c + +#define A_TP_PMM_TX_BASE 0x320 + +#define A_TP_PMM_RX_BASE 0x328 + +#define A_TP_PMM_RX_PAGE_SIZE 0x32c + +#define A_TP_PMM_RX_MAX_PAGE 0x330 + +#define A_TP_PMM_TX_PAGE_SIZE 0x334 + +#define A_TP_PMM_TX_MAX_PAGE 0x338 + +#define A_TP_TCP_OPTIONS 0x340 + +#define S_MTUDEFAULT 16 +#define M_MTUDEFAULT 0xffff +#define V_MTUDEFAULT(x) ((x) << S_MTUDEFAULT) + +#define S_MTUENABLE 10 +#define V_MTUENABLE(x) ((x) << S_MTUENABLE) +#define F_MTUENABLE V_MTUENABLE(1U) + +#define S_SACKRX 8 +#define V_SACKRX(x) ((x) << S_SACKRX) +#define F_SACKRX V_SACKRX(1U) + +#define S_SACKMODE 4 + +#define M_SACKMODE 0x3 + +#define V_SACKMODE(x) ((x) << S_SACKMODE) + +#define S_WINDOWSCALEMODE 2 +#define M_WINDOWSCALEMODE 0x3 +#define V_WINDOWSCALEMODE(x) ((x) << S_WINDOWSCALEMODE) + +#define S_TIMESTAMPSMODE 0 + +#define M_TIMESTAMPSMODE 0x3 + +#define V_TIMESTAMPSMODE(x) ((x) << S_TIMESTAMPSMODE) + +#define A_TP_DACK_CONFIG 0x344 + +#define S_AUTOSTATE3 30 +#define M_AUTOSTATE3 0x3 +#define V_AUTOSTATE3(x) ((x) << S_AUTOSTATE3) + +#define S_AUTOSTATE2 28 +#define M_AUTOSTATE2 0x3 +#define V_AUTOSTATE2(x) ((x) << S_AUTOSTATE2) + +#define S_AUTOSTATE1 26 +#define M_AUTOSTATE1 0x3 +#define V_AUTOSTATE1(x) ((x) << S_AUTOSTATE1) + +#define S_BYTETHRESHOLD 5 +#define M_BYTETHRESHOLD 0xfffff +#define V_BYTETHRESHOLD(x) ((x) << S_BYTETHRESHOLD) + +#define S_MSSTHRESHOLD 3 +#define M_MSSTHRESHOLD 0x3 +#define V_MSSTHRESHOLD(x) ((x) << S_MSSTHRESHOLD) + +#define S_AUTOCAREFUL 2 +#define V_AUTOCAREFUL(x) ((x) << S_AUTOCAREFUL) +#define F_AUTOCAREFUL V_AUTOCAREFUL(1U) + +#define S_AUTOENABLE 1 +#define V_AUTOENABLE(x) ((x) << S_AUTOENABLE) +#define F_AUTOENABLE V_AUTOENABLE(1U) + +#define S_DACK_MODE 0 +#define V_DACK_MODE(x) ((x) << S_DACK_MODE) +#define F_DACK_MODE V_DACK_MODE(1U) + +#define A_TP_PC_CONFIG 0x348 + +#define S_TXTOSQUEUEMAPMODE 26 +#define V_TXTOSQUEUEMAPMODE(x) ((x) << S_TXTOSQUEUEMAPMODE) +#define F_TXTOSQUEUEMAPMODE V_TXTOSQUEUEMAPMODE(1U) + +#define S_ENABLEEPCMDAFULL 23 +#define V_ENABLEEPCMDAFULL(x) ((x) << S_ENABLEEPCMDAFULL) +#define F_ENABLEEPCMDAFULL V_ENABLEEPCMDAFULL(1U) + +#define S_MODULATEUNIONMODE 22 +#define V_MODULATEUNIONMODE(x) ((x) << S_MODULATEUNIONMODE) +#define F_MODULATEUNIONMODE V_MODULATEUNIONMODE(1U) + +#define S_TXDEFERENABLE 20 +#define V_TXDEFERENABLE(x) ((x) << S_TXDEFERENABLE) +#define F_TXDEFERENABLE V_TXDEFERENABLE(1U) + +#define S_RXCONGESTIONMODE 19 +#define V_RXCONGESTIONMODE(x) ((x) << S_RXCONGESTIONMODE) +#define F_RXCONGESTIONMODE V_RXCONGESTIONMODE(1U) + +#define S_HEARBEATDACK 16 +#define V_HEARBEATDACK(x) ((x) << S_HEARBEATDACK) +#define F_HEARBEATDACK V_HEARBEATDACK(1U) + +#define S_TXCONGESTIONMODE 15 +#define V_TXCONGESTIONMODE(x) ((x) << S_TXCONGESTIONMODE) +#define F_TXCONGESTIONMODE V_TXCONGESTIONMODE(1U) + +#define S_ENABLEOCSPIFULL 30 +#define V_ENABLEOCSPIFULL(x) ((x) << S_ENABLEOCSPIFULL) +#define F_ENABLEOCSPIFULL V_ENABLEOCSPIFULL(1U) + +#define S_LOCKTID 28 +#define V_LOCKTID(x) ((x) << S_LOCKTID) +#define F_LOCKTID V_LOCKTID(1U) + +#define A_TP_PC_CONFIG2 0x34c + +#define S_CHDRAFULL 4 +#define V_CHDRAFULL(x) ((x) << S_CHDRAFULL) +#define F_CHDRAFULL V_CHDRAFULL(1U) + +#define A_TP_TCP_BACKOFF_REG0 0x350 + +#define A_TP_TCP_BACKOFF_REG1 0x354 + +#define A_TP_TCP_BACKOFF_REG2 0x358 + +#define A_TP_TCP_BACKOFF_REG3 0x35c + +#define A_TP_PARA_REG2 0x368 + +#define S_MAXRXDATA 16 +#define M_MAXRXDATA 0xffff +#define V_MAXRXDATA(x) ((x) << S_MAXRXDATA) + +#define S_RXCOALESCESIZE 0 +#define M_RXCOALESCESIZE 0xffff +#define V_RXCOALESCESIZE(x) ((x) << S_RXCOALESCESIZE) + +#define A_TP_PARA_REG3 0x36c + +#define S_TXDATAACKIDX 16 +#define M_TXDATAACKIDX 0xf + +#define V_TXDATAACKIDX(x) ((x) << S_TXDATAACKIDX) + +#define S_TXPACEAUTOSTRICT 10 +#define V_TXPACEAUTOSTRICT(x) ((x) << S_TXPACEAUTOSTRICT) +#define F_TXPACEAUTOSTRICT V_TXPACEAUTOSTRICT(1U) + +#define S_TXPACEFIXED 9 +#define V_TXPACEFIXED(x) ((x) << S_TXPACEFIXED) +#define F_TXPACEFIXED V_TXPACEFIXED(1U) + +#define S_TXPACEAUTO 8 +#define V_TXPACEAUTO(x) ((x) << S_TXPACEAUTO) +#define F_TXPACEAUTO V_TXPACEAUTO(1U) + +#define S_RXCOALESCEENABLE 1 +#define V_RXCOALESCEENABLE(x) ((x) << S_RXCOALESCEENABLE) +#define F_RXCOALESCEENABLE V_RXCOALESCEENABLE(1U) + +#define S_RXCOALESCEPSHEN 0 +#define V_RXCOALESCEPSHEN(x) ((x) << S_RXCOALESCEPSHEN) +#define F_RXCOALESCEPSHEN V_RXCOALESCEPSHEN(1U) + +#define A_TP_PARA_REG4 0x370 + +#define A_TP_PARA_REG6 0x378 + +#define S_T3A_ENABLEESND 13 +#define V_T3A_ENABLEESND(x) ((x) << S_T3A_ENABLEESND) +#define F_T3A_ENABLEESND V_T3A_ENABLEESND(1U) + +#define S_ENABLEESND 11 +#define V_ENABLEESND(x) ((x) << S_ENABLEESND) +#define F_ENABLEESND V_ENABLEESND(1U) + +#define A_TP_PARA_REG7 0x37c + +#define S_PMMAXXFERLEN1 16 +#define M_PMMAXXFERLEN1 0xffff +#define V_PMMAXXFERLEN1(x) ((x) << S_PMMAXXFERLEN1) + +#define S_PMMAXXFERLEN0 0 +#define M_PMMAXXFERLEN0 0xffff +#define V_PMMAXXFERLEN0(x) ((x) << S_PMMAXXFERLEN0) + +#define A_TP_TIMER_RESOLUTION 0x390 + +#define S_TIMERRESOLUTION 16 +#define M_TIMERRESOLUTION 0xff +#define V_TIMERRESOLUTION(x) ((x) << S_TIMERRESOLUTION) + +#define S_TIMESTAMPRESOLUTION 8 +#define M_TIMESTAMPRESOLUTION 0xff +#define V_TIMESTAMPRESOLUTION(x) ((x) << S_TIMESTAMPRESOLUTION) + +#define S_DELAYEDACKRESOLUTION 0 +#define M_DELAYEDACKRESOLUTION 0xff +#define V_DELAYEDACKRESOLUTION(x) ((x) << S_DELAYEDACKRESOLUTION) + +#define A_TP_MSL 0x394 + +#define A_TP_RXT_MIN 0x398 + +#define A_TP_RXT_MAX 0x39c + +#define A_TP_PERS_MIN 0x3a0 + +#define A_TP_PERS_MAX 0x3a4 + +#define A_TP_KEEP_IDLE 0x3a8 + +#define A_TP_KEEP_INTVL 0x3ac + +#define A_TP_INIT_SRTT 0x3b0 + +#define A_TP_DACK_TIMER 0x3b4 + +#define A_TP_FINWAIT2_TIMER 0x3b8 + +#define A_TP_SHIFT_CNT 0x3c0 + +#define S_SYNSHIFTMAX 24 + +#define M_SYNSHIFTMAX 0xff + +#define V_SYNSHIFTMAX(x) ((x) << S_SYNSHIFTMAX) + +#define S_RXTSHIFTMAXR1 20 + +#define M_RXTSHIFTMAXR1 0xf + +#define V_RXTSHIFTMAXR1(x) ((x) << S_RXTSHIFTMAXR1) + +#define S_RXTSHIFTMAXR2 16 + +#define M_RXTSHIFTMAXR2 0xf + +#define V_RXTSHIFTMAXR2(x) ((x) << S_RXTSHIFTMAXR2) + +#define S_PERSHIFTBACKOFFMAX 12 +#define M_PERSHIFTBACKOFFMAX 0xf +#define V_PERSHIFTBACKOFFMAX(x) ((x) << S_PERSHIFTBACKOFFMAX) + +#define S_PERSHIFTMAX 8 +#define M_PERSHIFTMAX 0xf +#define V_PERSHIFTMAX(x) ((x) << S_PERSHIFTMAX) + +#define S_KEEPALIVEMAX 0 + +#define M_KEEPALIVEMAX 0xff + +#define V_KEEPALIVEMAX(x) ((x) << S_KEEPALIVEMAX) + +#define A_TP_MTU_PORT_TABLE 0x3d0 + +#define A_TP_CCTRL_TABLE 0x3dc + +#define A_TP_MTU_TABLE 0x3e4 + +#define A_TP_RSS_MAP_TABLE 0x3e8 + +#define A_TP_RSS_LKP_TABLE 0x3ec + +#define A_TP_RSS_CONFIG 0x3f0 + +#define S_TNL4TUPEN 29 +#define V_TNL4TUPEN(x) ((x) << S_TNL4TUPEN) +#define F_TNL4TUPEN V_TNL4TUPEN(1U) + +#define S_TNL2TUPEN 28 +#define V_TNL2TUPEN(x) ((x) << S_TNL2TUPEN) +#define F_TNL2TUPEN V_TNL2TUPEN(1U) + +#define S_TNLPRTEN 26 +#define V_TNLPRTEN(x) ((x) << S_TNLPRTEN) +#define F_TNLPRTEN V_TNLPRTEN(1U) + +#define S_TNLMAPEN 25 +#define V_TNLMAPEN(x) ((x) << S_TNLMAPEN) +#define F_TNLMAPEN V_TNLMAPEN(1U) + +#define S_TNLLKPEN 24 +#define V_TNLLKPEN(x) ((x) << S_TNLLKPEN) +#define F_TNLLKPEN V_TNLLKPEN(1U) + +#define S_RRCPLCPUSIZE 4 +#define M_RRCPLCPUSIZE 0x7 +#define V_RRCPLCPUSIZE(x) ((x) << S_RRCPLCPUSIZE) + +#define S_RQFEEDBACKENABLE 3 +#define V_RQFEEDBACKENABLE(x) ((x) << S_RQFEEDBACKENABLE) +#define F_RQFEEDBACKENABLE V_RQFEEDBACKENABLE(1U) + +#define S_DISABLE 0 + +#define A_TP_TM_PIO_ADDR 0x418 + +#define A_TP_TM_PIO_DATA 0x41c + +#define A_TP_TX_MOD_QUE_TABLE 0x420 + +#define A_TP_TX_RESOURCE_LIMIT 0x424 + +#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x428 + +#define S_TX_MOD_QUEUE_REQ_MAP 0 +#define M_TX_MOD_QUEUE_REQ_MAP 0xff +#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP) + +#define A_TP_TX_MOD_QUEUE_WEIGHT1 0x42c + +#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x430 + +#define A_TP_MOD_CHANNEL_WEIGHT 0x434 + +#define A_TP_PIO_ADDR 0x440 + +#define A_TP_PIO_DATA 0x444 + +#define A_TP_RESET 0x44c + +#define S_FLSTINITENABLE 1 +#define V_FLSTINITENABLE(x) ((x) << S_FLSTINITENABLE) +#define F_FLSTINITENABLE V_FLSTINITENABLE(1U) + +#define S_TPRESET 0 +#define V_TPRESET(x) ((x) << S_TPRESET) +#define F_TPRESET V_TPRESET(1U) + +#define A_TP_CMM_MM_RX_FLST_BASE 0x460 + +#define A_TP_CMM_MM_TX_FLST_BASE 0x464 + +#define A_TP_CMM_MM_PS_FLST_BASE 0x468 + +#define A_TP_MIB_INDEX 0x450 + +#define A_TP_MIB_RDATA 0x454 + +#define A_TP_CMM_MM_MAX_PSTRUCT 0x46c + +#define A_TP_INT_ENABLE 0x470 + +#define A_TP_INT_CAUSE 0x474 + +#define A_TP_TX_MOD_Q1_Q0_RATE_LIMIT 0x8 + +#define A_TP_TX_DROP_CFG_CH0 0x12b + +#define A_TP_TX_DROP_MODE 0x12f + +#define A_TP_EGRESS_CONFIG 0x145 + +#define S_REWRITEFORCETOSIZE 0 +#define V_REWRITEFORCETOSIZE(x) ((x) << S_REWRITEFORCETOSIZE) +#define F_REWRITEFORCETOSIZE V_REWRITEFORCETOSIZE(1U) + +#define A_TP_TX_TRC_KEY0 0x20 + +#define A_TP_RX_TRC_KEY0 0x120 + +#define A_ULPRX_CTL 0x500 + +#define S_ROUND_ROBIN 4 +#define V_ROUND_ROBIN(x) ((x) << S_ROUND_ROBIN) +#define F_ROUND_ROBIN V_ROUND_ROBIN(1U) + +#define A_ULPRX_INT_ENABLE 0x504 + +#define S_PARERR 0 +#define V_PARERR(x) ((x) << S_PARERR) +#define F_PARERR V_PARERR(1U) + +#define A_ULPRX_INT_CAUSE 0x508 + +#define A_ULPRX_ISCSI_LLIMIT 0x50c + +#define A_ULPRX_ISCSI_ULIMIT 0x510 + +#define A_ULPRX_ISCSI_TAGMASK 0x514 + +#define A_ULPRX_TDDP_LLIMIT 0x51c + +#define A_ULPRX_TDDP_ULIMIT 0x520 + +#define A_ULPRX_STAG_LLIMIT 0x52c + +#define A_ULPRX_STAG_ULIMIT 0x530 + +#define A_ULPRX_RQ_LLIMIT 0x534 +#define A_ULPRX_RQ_LLIMIT 0x534 + +#define A_ULPRX_RQ_ULIMIT 0x538 +#define A_ULPRX_RQ_ULIMIT 0x538 + +#define A_ULPRX_PBL_LLIMIT 0x53c + +#define A_ULPRX_PBL_ULIMIT 0x540 +#define A_ULPRX_PBL_ULIMIT 0x540 + +#define A_ULPRX_TDDP_TAGMASK 0x524 + +#define A_ULPRX_RQ_LLIMIT 0x534 +#define A_ULPRX_RQ_LLIMIT 0x534 + +#define A_ULPRX_RQ_ULIMIT 0x538 +#define A_ULPRX_RQ_ULIMIT 0x538 + +#define A_ULPRX_PBL_ULIMIT 0x540 +#define A_ULPRX_PBL_ULIMIT 0x540 + +#define A_ULPTX_CONFIG 0x580 + +#define S_CFG_RR_ARB 0 +#define V_CFG_RR_ARB(x) ((x) << S_CFG_RR_ARB) +#define F_CFG_RR_ARB V_CFG_RR_ARB(1U) + +#define A_ULPTX_INT_ENABLE 0x584 + +#define S_PBL_BOUND_ERR_CH1 1 +#define V_PBL_BOUND_ERR_CH1(x) ((x) << S_PBL_BOUND_ERR_CH1) +#define F_PBL_BOUND_ERR_CH1 V_PBL_BOUND_ERR_CH1(1U) + +#define S_PBL_BOUND_ERR_CH0 0 +#define V_PBL_BOUND_ERR_CH0(x) ((x) << S_PBL_BOUND_ERR_CH0) +#define F_PBL_BOUND_ERR_CH0 V_PBL_BOUND_ERR_CH0(1U) + +#define A_ULPTX_INT_CAUSE 0x588 + +#define A_ULPTX_TPT_LLIMIT 0x58c + +#define A_ULPTX_TPT_ULIMIT 0x590 + +#define A_ULPTX_PBL_LLIMIT 0x594 + +#define A_ULPTX_PBL_ULIMIT 0x598 + +#define A_ULPTX_DMA_WEIGHT 0x5ac + +#define S_D1_WEIGHT 16 +#define M_D1_WEIGHT 0xffff +#define V_D1_WEIGHT(x) ((x) << S_D1_WEIGHT) + +#define S_D0_WEIGHT 0 +#define M_D0_WEIGHT 0xffff +#define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT) + +#define A_PM1_RX_CFG 0x5c0 + +#define A_PM1_RX_INT_ENABLE 0x5d8 + +#define S_ZERO_E_CMD_ERROR 18 +#define V_ZERO_E_CMD_ERROR(x) ((x) << S_ZERO_E_CMD_ERROR) +#define F_ZERO_E_CMD_ERROR V_ZERO_E_CMD_ERROR(1U) + +#define S_IESPI0_FIFO2X_RX_FRAMING_ERROR 17 +#define V_IESPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_FIFO2X_RX_FRAMING_ERROR) +#define F_IESPI0_FIFO2X_RX_FRAMING_ERROR V_IESPI0_FIFO2X_RX_FRAMING_ERROR(1U) + +#define S_IESPI1_FIFO2X_RX_FRAMING_ERROR 16 +#define V_IESPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_FIFO2X_RX_FRAMING_ERROR) +#define F_IESPI1_FIFO2X_RX_FRAMING_ERROR V_IESPI1_FIFO2X_RX_FRAMING_ERROR(1U) + +#define S_IESPI0_RX_FRAMING_ERROR 15 +#define V_IESPI0_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_RX_FRAMING_ERROR) +#define F_IESPI0_RX_FRAMING_ERROR V_IESPI0_RX_FRAMING_ERROR(1U) + +#define S_IESPI1_RX_FRAMING_ERROR 14 +#define V_IESPI1_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_RX_FRAMING_ERROR) +#define F_IESPI1_RX_FRAMING_ERROR V_IESPI1_RX_FRAMING_ERROR(1U) + +#define S_IESPI0_TX_FRAMING_ERROR 13 +#define V_IESPI0_TX_FRAMING_ERROR(x) ((x) << S_IESPI0_TX_FRAMING_ERROR) +#define F_IESPI0_TX_FRAMING_ERROR V_IESPI0_TX_FRAMING_ERROR(1U) + +#define S_IESPI1_TX_FRAMING_ERROR 12 +#define V_IESPI1_TX_FRAMING_ERROR(x) ((x) << S_IESPI1_TX_FRAMING_ERROR) +#define F_IESPI1_TX_FRAMING_ERROR V_IESPI1_TX_FRAMING_ERROR(1U) + +#define S_OCSPI0_RX_FRAMING_ERROR 11 +#define V_OCSPI0_RX_FRAMING_ERROR(x) ((x) << S_OCSPI0_RX_FRAMING_ERROR) +#define F_OCSPI0_RX_FRAMING_ERROR V_OCSPI0_RX_FRAMING_ERROR(1U) + +#define S_OCSPI1_RX_FRAMING_ERROR 10 +#define V_OCSPI1_RX_FRAMING_ERROR(x) ((x) << S_OCSPI1_RX_FRAMING_ERROR) +#define F_OCSPI1_RX_FRAMING_ERROR V_OCSPI1_RX_FRAMING_ERROR(1U) + +#define S_OCSPI0_TX_FRAMING_ERROR 9 +#define V_OCSPI0_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_TX_FRAMING_ERROR) +#define F_OCSPI0_TX_FRAMING_ERROR V_OCSPI0_TX_FRAMING_ERROR(1U) + +#define S_OCSPI1_TX_FRAMING_ERROR 8 +#define V_OCSPI1_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_TX_FRAMING_ERROR) +#define F_OCSPI1_TX_FRAMING_ERROR V_OCSPI1_TX_FRAMING_ERROR(1U) + +#define S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR 7 +#define V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR) +#define F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(1U) + +#define S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR 6 +#define V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR) +#define F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(1U) + +#define S_IESPI_PAR_ERROR 3 +#define M_IESPI_PAR_ERROR 0x7 + +#define V_IESPI_PAR_ERROR(x) ((x) << S_IESPI_PAR_ERROR) + +#define S_OCSPI_PAR_ERROR 0 +#define M_OCSPI_PAR_ERROR 0x7 + +#define V_OCSPI_PAR_ERROR(x) ((x) << S_OCSPI_PAR_ERROR) + +#define A_PM1_RX_INT_CAUSE 0x5dc + +#define A_PM1_TX_CFG 0x5e0 + +#define A_PM1_TX_INT_ENABLE 0x5f8 + +#define S_ZERO_C_CMD_ERROR 18 +#define V_ZERO_C_CMD_ERROR(x) ((x) << S_ZERO_C_CMD_ERROR) +#define F_ZERO_C_CMD_ERROR V_ZERO_C_CMD_ERROR(1U) + +#define S_ICSPI0_FIFO2X_RX_FRAMING_ERROR 17 +#define V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_FIFO2X_RX_FRAMING_ERROR) +#define F_ICSPI0_FIFO2X_RX_FRAMING_ERROR V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(1U) + +#define S_ICSPI1_FIFO2X_RX_FRAMING_ERROR 16 +#define V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_FIFO2X_RX_FRAMING_ERROR) +#define F_ICSPI1_FIFO2X_RX_FRAMING_ERROR V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(1U) + +#define S_ICSPI0_RX_FRAMING_ERROR 15 +#define V_ICSPI0_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_RX_FRAMING_ERROR) +#define F_ICSPI0_RX_FRAMING_ERROR V_ICSPI0_RX_FRAMING_ERROR(1U) + +#define S_ICSPI1_RX_FRAMING_ERROR 14 +#define V_ICSPI1_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_RX_FRAMING_ERROR) +#define F_ICSPI1_RX_FRAMING_ERROR V_ICSPI1_RX_FRAMING_ERROR(1U) + +#define S_ICSPI0_TX_FRAMING_ERROR 13 +#define V_ICSPI0_TX_FRAMING_ERROR(x) ((x) << S_ICSPI0_TX_FRAMING_ERROR) +#define F_ICSPI0_TX_FRAMING_ERROR V_ICSPI0_TX_FRAMING_ERROR(1U) + +#define S_ICSPI1_TX_FRAMING_ERROR 12 +#define V_ICSPI1_TX_FRAMING_ERROR(x) ((x) << S_ICSPI1_TX_FRAMING_ERROR) +#define F_ICSPI1_TX_FRAMING_ERROR V_ICSPI1_TX_FRAMING_ERROR(1U) + +#define S_OESPI0_RX_FRAMING_ERROR 11 +#define V_OESPI0_RX_FRAMING_ERROR(x) ((x) << S_OESPI0_RX_FRAMING_ERROR) +#define F_OESPI0_RX_FRAMING_ERROR V_OESPI0_RX_FRAMING_ERROR(1U) + +#define S_OESPI1_RX_FRAMING_ERROR 10 +#define V_OESPI1_RX_FRAMING_ERROR(x) ((x) << S_OESPI1_RX_FRAMING_ERROR) +#define F_OESPI1_RX_FRAMING_ERROR V_OESPI1_RX_FRAMING_ERROR(1U) + +#define S_OESPI0_TX_FRAMING_ERROR 9 +#define V_OESPI0_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_TX_FRAMING_ERROR) +#define F_OESPI0_TX_FRAMING_ERROR V_OESPI0_TX_FRAMING_ERROR(1U) + +#define S_OESPI1_TX_FRAMING_ERROR 8 +#define V_OESPI1_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_TX_FRAMING_ERROR) +#define F_OESPI1_TX_FRAMING_ERROR V_OESPI1_TX_FRAMING_ERROR(1U) + +#define S_OESPI0_OFIFO2X_TX_FRAMING_ERROR 7 +#define V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_OFIFO2X_TX_FRAMING_ERROR) +#define F_OESPI0_OFIFO2X_TX_FRAMING_ERROR V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(1U) + +#define S_OESPI1_OFIFO2X_TX_FRAMING_ERROR 6 +#define V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_OFIFO2X_TX_FRAMING_ERROR) +#define F_OESPI1_OFIFO2X_TX_FRAMING_ERROR V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(1U) + +#define S_ICSPI_PAR_ERROR 3 +#define M_ICSPI_PAR_ERROR 0x7 + +#define V_ICSPI_PAR_ERROR(x) ((x) << S_ICSPI_PAR_ERROR) + +#define S_OESPI_PAR_ERROR 0 +#define M_OESPI_PAR_ERROR 0x7 + +#define V_OESPI_PAR_ERROR(x) ((x) << S_OESPI_PAR_ERROR) + +#define A_PM1_TX_INT_CAUSE 0x5fc + +#define A_MPS_CFG 0x600 + +#define S_TPRXPORTEN 4 +#define V_TPRXPORTEN(x) ((x) << S_TPRXPORTEN) +#define F_TPRXPORTEN V_TPRXPORTEN(1U) + +#define S_TPTXPORT1EN 3 +#define V_TPTXPORT1EN(x) ((x) << S_TPTXPORT1EN) +#define F_TPTXPORT1EN V_TPTXPORT1EN(1U) + +#define S_TPTXPORT0EN 2 +#define V_TPTXPORT0EN(x) ((x) << S_TPTXPORT0EN) +#define F_TPTXPORT0EN V_TPTXPORT0EN(1U) + +#define S_PORT1ACTIVE 1 +#define V_PORT1ACTIVE(x) ((x) << S_PORT1ACTIVE) +#define F_PORT1ACTIVE V_PORT1ACTIVE(1U) + +#define S_PORT0ACTIVE 0 +#define V_PORT0ACTIVE(x) ((x) << S_PORT0ACTIVE) +#define F_PORT0ACTIVE V_PORT0ACTIVE(1U) + +#define S_ENFORCEPKT 11 +#define V_ENFORCEPKT(x) ((x) << S_ENFORCEPKT) +#define F_ENFORCEPKT V_ENFORCEPKT(1U) + +#define A_MPS_INT_ENABLE 0x61c + +#define S_MCAPARERRENB 6 +#define M_MCAPARERRENB 0x7 + +#define V_MCAPARERRENB(x) ((x) << S_MCAPARERRENB) + +#define S_RXTPPARERRENB 4 +#define M_RXTPPARERRENB 0x3 + +#define V_RXTPPARERRENB(x) ((x) << S_RXTPPARERRENB) + +#define S_TX1TPPARERRENB 2 +#define M_TX1TPPARERRENB 0x3 + +#define V_TX1TPPARERRENB(x) ((x) << S_TX1TPPARERRENB) + +#define S_TX0TPPARERRENB 0 +#define M_TX0TPPARERRENB 0x3 + +#define V_TX0TPPARERRENB(x) ((x) << S_TX0TPPARERRENB) + +#define A_MPS_INT_CAUSE 0x620 + +#define S_MCAPARERR 6 +#define M_MCAPARERR 0x7 + +#define V_MCAPARERR(x) ((x) << S_MCAPARERR) + +#define S_RXTPPARERR 4 +#define M_RXTPPARERR 0x3 + +#define V_RXTPPARERR(x) ((x) << S_RXTPPARERR) + +#define S_TX1TPPARERR 2 +#define M_TX1TPPARERR 0x3 + +#define V_TX1TPPARERR(x) ((x) << S_TX1TPPARERR) + +#define S_TX0TPPARERR 0 +#define M_TX0TPPARERR 0x3 + +#define V_TX0TPPARERR(x) ((x) << S_TX0TPPARERR) + +#define A_CPL_SWITCH_CNTRL 0x640 + +#define A_CPL_INTR_ENABLE 0x650 + +#define S_CIM_OVFL_ERROR 4 +#define V_CIM_OVFL_ERROR(x) ((x) << S_CIM_OVFL_ERROR) +#define F_CIM_OVFL_ERROR V_CIM_OVFL_ERROR(1U) + +#define S_TP_FRAMING_ERROR 3 +#define V_TP_FRAMING_ERROR(x) ((x) << S_TP_FRAMING_ERROR) +#define F_TP_FRAMING_ERROR V_TP_FRAMING_ERROR(1U) + +#define S_SGE_FRAMING_ERROR 2 +#define V_SGE_FRAMING_ERROR(x) ((x) << S_SGE_FRAMING_ERROR) +#define F_SGE_FRAMING_ERROR V_SGE_FRAMING_ERROR(1U) + +#define S_CIM_FRAMING_ERROR 1 +#define V_CIM_FRAMING_ERROR(x) ((x) << S_CIM_FRAMING_ERROR) +#define F_CIM_FRAMING_ERROR V_CIM_FRAMING_ERROR(1U) + +#define S_ZERO_SWITCH_ERROR 0 +#define V_ZERO_SWITCH_ERROR(x) ((x) << S_ZERO_SWITCH_ERROR) +#define F_ZERO_SWITCH_ERROR V_ZERO_SWITCH_ERROR(1U) + +#define A_CPL_INTR_CAUSE 0x654 + +#define A_CPL_MAP_TBL_DATA 0x65c + +#define A_SMB_GLOBAL_TIME_CFG 0x660 + +#define A_I2C_CFG 0x6a0 + +#define S_I2C_CLKDIV 0 +#define M_I2C_CLKDIV 0xfff +#define V_I2C_CLKDIV(x) ((x) << S_I2C_CLKDIV) + +#define A_MI1_CFG 0x6b0 + +#define S_CLKDIV 5 +#define M_CLKDIV 0xff +#define V_CLKDIV(x) ((x) << S_CLKDIV) + +#define S_ST 3 + +#define M_ST 0x3 + +#define V_ST(x) ((x) << S_ST) + +#define G_ST(x) (((x) >> S_ST) & M_ST) + +#define S_PREEN 2 +#define V_PREEN(x) ((x) << S_PREEN) +#define F_PREEN V_PREEN(1U) + +#define S_MDIINV 1 +#define V_MDIINV(x) ((x) << S_MDIINV) +#define F_MDIINV V_MDIINV(1U) + +#define S_MDIEN 0 +#define V_MDIEN(x) ((x) << S_MDIEN) +#define F_MDIEN V_MDIEN(1U) + +#define A_MI1_ADDR 0x6b4 + +#define S_PHYADDR 5 +#define M_PHYADDR 0x1f +#define V_PHYADDR(x) ((x) << S_PHYADDR) + +#define S_REGADDR 0 +#define M_REGADDR 0x1f +#define V_REGADDR(x) ((x) << S_REGADDR) + +#define A_MI1_DATA 0x6b8 + +#define A_MI1_OP 0x6bc + +#define S_MDI_OP 0 +#define M_MDI_OP 0x3 +#define V_MDI_OP(x) ((x) << S_MDI_OP) + +#define A_SF_DATA 0x6d8 + +#define A_SF_OP 0x6dc + +#define S_BYTECNT 1 +#define M_BYTECNT 0x3 +#define V_BYTECNT(x) ((x) << S_BYTECNT) + +#define A_PL_INT_ENABLE0 0x6e0 + +#define S_T3DBG 23 +#define V_T3DBG(x) ((x) << S_T3DBG) +#define F_T3DBG V_T3DBG(1U) + +#define S_XGMAC0_1 20 +#define V_XGMAC0_1(x) ((x) << S_XGMAC0_1) +#define F_XGMAC0_1 V_XGMAC0_1(1U) + +#define S_XGMAC0_0 19 +#define V_XGMAC0_0(x) ((x) << S_XGMAC0_0) +#define F_XGMAC0_0 V_XGMAC0_0(1U) + +#define S_MC5A 18 +#define V_MC5A(x) ((x) << S_MC5A) +#define F_MC5A V_MC5A(1U) + +#define S_CPL_SWITCH 12 +#define V_CPL_SWITCH(x) ((x) << S_CPL_SWITCH) +#define F_CPL_SWITCH V_CPL_SWITCH(1U) + +#define S_MPS0 11 +#define V_MPS0(x) ((x) << S_MPS0) +#define F_MPS0 V_MPS0(1U) + +#define S_PM1_TX 10 +#define V_PM1_TX(x) ((x) << S_PM1_TX) +#define F_PM1_TX V_PM1_TX(1U) + +#define S_PM1_RX 9 +#define V_PM1_RX(x) ((x) << S_PM1_RX) +#define F_PM1_RX V_PM1_RX(1U) + +#define S_ULP2_TX 8 +#define V_ULP2_TX(x) ((x) << S_ULP2_TX) +#define F_ULP2_TX V_ULP2_TX(1U) + +#define S_ULP2_RX 7 +#define V_ULP2_RX(x) ((x) << S_ULP2_RX) +#define F_ULP2_RX V_ULP2_RX(1U) + +#define S_TP1 6 +#define V_TP1(x) ((x) << S_TP1) +#define F_TP1 V_TP1(1U) + +#define S_CIM 5 +#define V_CIM(x) ((x) << S_CIM) +#define F_CIM V_CIM(1U) + +#define S_MC7_CM 4 +#define V_MC7_CM(x) ((x) << S_MC7_CM) +#define F_MC7_CM V_MC7_CM(1U) + +#define S_MC7_PMTX 3 +#define V_MC7_PMTX(x) ((x) << S_MC7_PMTX) +#define F_MC7_PMTX V_MC7_PMTX(1U) + +#define S_MC7_PMRX 2 +#define V_MC7_PMRX(x) ((x) << S_MC7_PMRX) +#define F_MC7_PMRX V_MC7_PMRX(1U) + +#define S_PCIM0 1 +#define V_PCIM0(x) ((x) << S_PCIM0) +#define F_PCIM0 V_PCIM0(1U) + +#define S_SGE3 0 +#define V_SGE3(x) ((x) << S_SGE3) +#define F_SGE3 V_SGE3(1U) + +#define A_PL_INT_CAUSE0 0x6e4 + +#define A_PL_RST 0x6f0 + +#define S_CRSTWRM 1 +#define V_CRSTWRM(x) ((x) << S_CRSTWRM) +#define F_CRSTWRM V_CRSTWRM(1U) + +#define A_PL_REV 0x6f4 + +#define A_PL_CLI 0x6f8 + +#define A_MC5_DB_CONFIG 0x704 + +#define S_TMTYPEHI 30 +#define V_TMTYPEHI(x) ((x) << S_TMTYPEHI) +#define F_TMTYPEHI V_TMTYPEHI(1U) + +#define S_TMPARTSIZE 28 +#define M_TMPARTSIZE 0x3 +#define V_TMPARTSIZE(x) ((x) << S_TMPARTSIZE) +#define G_TMPARTSIZE(x) (((x) >> S_TMPARTSIZE) & M_TMPARTSIZE) + +#define S_TMTYPE 26 +#define M_TMTYPE 0x3 +#define V_TMTYPE(x) ((x) << S_TMTYPE) +#define G_TMTYPE(x) (((x) >> S_TMTYPE) & M_TMTYPE) + +#define S_COMPEN 17 +#define V_COMPEN(x) ((x) << S_COMPEN) +#define F_COMPEN V_COMPEN(1U) + +#define S_PRTYEN 6 +#define V_PRTYEN(x) ((x) << S_PRTYEN) +#define F_PRTYEN V_PRTYEN(1U) + +#define S_MBUSEN 5 +#define V_MBUSEN(x) ((x) << S_MBUSEN) +#define F_MBUSEN V_MBUSEN(1U) + +#define S_DBGIEN 4 +#define V_DBGIEN(x) ((x) << S_DBGIEN) +#define F_DBGIEN V_DBGIEN(1U) + +#define S_TMRDY 2 +#define V_TMRDY(x) ((x) << S_TMRDY) +#define F_TMRDY V_TMRDY(1U) + +#define S_TMRST 1 +#define V_TMRST(x) ((x) << S_TMRST) +#define F_TMRST V_TMRST(1U) + +#define S_TMMODE 0 +#define V_TMMODE(x) ((x) << S_TMMODE) +#define F_TMMODE V_TMMODE(1U) + +#define F_TMMODE V_TMMODE(1U) + +#define A_MC5_DB_ROUTING_TABLE_INDEX 0x70c + +#define A_MC5_DB_FILTER_TABLE 0x710 + +#define A_MC5_DB_SERVER_INDEX 0x714 + +#define A_MC5_DB_RSP_LATENCY 0x720 + +#define S_RDLAT 16 +#define M_RDLAT 0x1f +#define V_RDLAT(x) ((x) << S_RDLAT) + +#define S_LRNLAT 8 +#define M_LRNLAT 0x1f +#define V_LRNLAT(x) ((x) << S_LRNLAT) + +#define S_SRCHLAT 0 +#define M_SRCHLAT 0x1f +#define V_SRCHLAT(x) ((x) << S_SRCHLAT) + +#define A_MC5_DB_PART_ID_INDEX 0x72c + +#define A_MC5_DB_INT_ENABLE 0x740 + +#define S_DELACTEMPTY 18 +#define V_DELACTEMPTY(x) ((x) << S_DELACTEMPTY) +#define F_DELACTEMPTY V_DELACTEMPTY(1U) + +#define S_DISPQPARERR 17 +#define V_DISPQPARERR(x) ((x) << S_DISPQPARERR) +#define F_DISPQPARERR V_DISPQPARERR(1U) + +#define S_REQQPARERR 16 +#define V_REQQPARERR(x) ((x) << S_REQQPARERR) +#define F_REQQPARERR V_REQQPARERR(1U) + +#define S_UNKNOWNCMD 15 +#define V_UNKNOWNCMD(x) ((x) << S_UNKNOWNCMD) +#define F_UNKNOWNCMD V_UNKNOWNCMD(1U) + +#define S_NFASRCHFAIL 8 +#define V_NFASRCHFAIL(x) ((x) << S_NFASRCHFAIL) +#define F_NFASRCHFAIL V_NFASRCHFAIL(1U) + +#define S_ACTRGNFULL 7 +#define V_ACTRGNFULL(x) ((x) << S_ACTRGNFULL) +#define F_ACTRGNFULL V_ACTRGNFULL(1U) + +#define S_PARITYERR 6 +#define V_PARITYERR(x) ((x) << S_PARITYERR) +#define F_PARITYERR V_PARITYERR(1U) + +#define A_MC5_DB_INT_CAUSE 0x744 + +#define A_MC5_DB_DBGI_CONFIG 0x774 + +#define A_MC5_DB_DBGI_REQ_CMD 0x778 + +#define A_MC5_DB_DBGI_REQ_ADDR0 0x77c + +#define A_MC5_DB_DBGI_REQ_ADDR1 0x780 + +#define A_MC5_DB_DBGI_REQ_ADDR2 0x784 + +#define A_MC5_DB_DBGI_REQ_DATA0 0x788 + +#define A_MC5_DB_DBGI_REQ_DATA1 0x78c + +#define A_MC5_DB_DBGI_REQ_DATA2 0x790 + +#define A_MC5_DB_DBGI_RSP_STATUS 0x7b0 + +#define S_DBGIRSPVALID 0 +#define V_DBGIRSPVALID(x) ((x) << S_DBGIRSPVALID) +#define F_DBGIRSPVALID V_DBGIRSPVALID(1U) + +#define A_MC5_DB_DBGI_RSP_DATA0 0x7b4 + +#define A_MC5_DB_DBGI_RSP_DATA1 0x7b8 + +#define A_MC5_DB_DBGI_RSP_DATA2 0x7bc + +#define A_MC5_DB_POPEN_DATA_WR_CMD 0x7cc + +#define A_MC5_DB_POPEN_MASK_WR_CMD 0x7d0 + +#define A_MC5_DB_AOPEN_SRCH_CMD 0x7d4 + +#define A_MC5_DB_AOPEN_LRN_CMD 0x7d8 + +#define A_MC5_DB_SYN_SRCH_CMD 0x7dc + +#define A_MC5_DB_SYN_LRN_CMD 0x7e0 + +#define A_MC5_DB_ACK_SRCH_CMD 0x7e4 + +#define A_MC5_DB_ACK_LRN_CMD 0x7e8 + +#define A_MC5_DB_ILOOKUP_CMD 0x7ec + +#define A_MC5_DB_ELOOKUP_CMD 0x7f0 + +#define A_MC5_DB_DATA_WRITE_CMD 0x7f4 + +#define A_MC5_DB_DATA_READ_CMD 0x7f8 + +#define XGMAC0_0_BASE_ADDR 0x800 + +#define A_XGM_TX_CTRL 0x800 + +#define S_TXEN 0 +#define V_TXEN(x) ((x) << S_TXEN) +#define F_TXEN V_TXEN(1U) + +#define A_XGM_TX_CFG 0x804 + +#define S_TXPAUSEEN 0 +#define V_TXPAUSEEN(x) ((x) << S_TXPAUSEEN) +#define F_TXPAUSEEN V_TXPAUSEEN(1U) + +#define A_XGM_RX_CTRL 0x80c + +#define S_RXEN 0 +#define V_RXEN(x) ((x) << S_RXEN) +#define F_RXEN V_RXEN(1U) + +#define A_XGM_RX_CFG 0x810 + +#define S_DISPAUSEFRAMES 9 +#define V_DISPAUSEFRAMES(x) ((x) << S_DISPAUSEFRAMES) +#define F_DISPAUSEFRAMES V_DISPAUSEFRAMES(1U) + +#define S_EN1536BFRAMES 8 +#define V_EN1536BFRAMES(x) ((x) << S_EN1536BFRAMES) +#define F_EN1536BFRAMES V_EN1536BFRAMES(1U) + +#define S_ENJUMBO 7 +#define V_ENJUMBO(x) ((x) << S_ENJUMBO) +#define F_ENJUMBO V_ENJUMBO(1U) + +#define S_RMFCS 6 +#define V_RMFCS(x) ((x) << S_RMFCS) +#define F_RMFCS V_RMFCS(1U) + +#define S_ENHASHMCAST 2 +#define V_ENHASHMCAST(x) ((x) << S_ENHASHMCAST) +#define F_ENHASHMCAST V_ENHASHMCAST(1U) + +#define S_COPYALLFRAMES 0 +#define V_COPYALLFRAMES(x) ((x) << S_COPYALLFRAMES) +#define F_COPYALLFRAMES V_COPYALLFRAMES(1U) + +#define A_XGM_RX_HASH_LOW 0x814 + +#define A_XGM_RX_HASH_HIGH 0x818 + +#define A_XGM_RX_EXACT_MATCH_LOW_1 0x81c + +#define A_XGM_RX_EXACT_MATCH_HIGH_1 0x820 + +#define A_XGM_RX_EXACT_MATCH_LOW_2 0x824 + +#define A_XGM_RX_EXACT_MATCH_LOW_3 0x82c + +#define A_XGM_RX_EXACT_MATCH_LOW_4 0x834 + +#define A_XGM_RX_EXACT_MATCH_LOW_5 0x83c + +#define A_XGM_RX_EXACT_MATCH_LOW_6 0x844 + +#define A_XGM_RX_EXACT_MATCH_LOW_7 0x84c + +#define A_XGM_RX_EXACT_MATCH_LOW_8 0x854 + +#define A_XGM_STAT_CTRL 0x880 + +#define S_CLRSTATS 2 +#define V_CLRSTATS(x) ((x) << S_CLRSTATS) +#define F_CLRSTATS V_CLRSTATS(1U) + +#define A_XGM_RXFIFO_CFG 0x884 + +#define S_RXFIFOPAUSEHWM 17 +#define M_RXFIFOPAUSEHWM 0xfff + +#define V_RXFIFOPAUSEHWM(x) ((x) << S_RXFIFOPAUSEHWM) + +#define G_RXFIFOPAUSEHWM(x) (((x) >> S_RXFIFOPAUSEHWM) & M_RXFIFOPAUSEHWM) + +#define S_RXFIFOPAUSELWM 5 +#define M_RXFIFOPAUSELWM 0xfff + +#define V_RXFIFOPAUSELWM(x) ((x) << S_RXFIFOPAUSELWM) + +#define G_RXFIFOPAUSELWM(x) (((x) >> S_RXFIFOPAUSELWM) & M_RXFIFOPAUSELWM) + +#define S_RXSTRFRWRD 1 +#define V_RXSTRFRWRD(x) ((x) << S_RXSTRFRWRD) +#define F_RXSTRFRWRD V_RXSTRFRWRD(1U) + +#define S_DISERRFRAMES 0 +#define V_DISERRFRAMES(x) ((x) << S_DISERRFRAMES) +#define F_DISERRFRAMES V_DISERRFRAMES(1U) + +#define A_XGM_TXFIFO_CFG 0x888 + +#define S_TXFIFOTHRESH 4 +#define M_TXFIFOTHRESH 0x1ff + +#define V_TXFIFOTHRESH(x) ((x) << S_TXFIFOTHRESH) + +#define A_XGM_SERDES_CTRL 0x890 +#define A_XGM_SERDES_CTRL0 0x8e0 + +#define S_SERDESRESET_ 24 +#define V_SERDESRESET_(x) ((x) << S_SERDESRESET_) +#define F_SERDESRESET_ V_SERDESRESET_(1U) + +#define S_RXENABLE 4 +#define V_RXENABLE(x) ((x) << S_RXENABLE) +#define F_RXENABLE V_RXENABLE(1U) + +#define S_TXENABLE 3 +#define V_TXENABLE(x) ((x) << S_TXENABLE) +#define F_TXENABLE V_TXENABLE(1U) + +#define A_XGM_PAUSE_TIMER 0x890 + +#define A_XGM_RGMII_IMP 0x89c + +#define S_XGM_IMPSETUPDATE 6 +#define V_XGM_IMPSETUPDATE(x) ((x) << S_XGM_IMPSETUPDATE) +#define F_XGM_IMPSETUPDATE V_XGM_IMPSETUPDATE(1U) + +#define S_RGMIIIMPPD 3 +#define M_RGMIIIMPPD 0x7 +#define V_RGMIIIMPPD(x) ((x) << S_RGMIIIMPPD) + +#define S_RGMIIIMPPU 0 +#define M_RGMIIIMPPU 0x7 +#define V_RGMIIIMPPU(x) ((x) << S_RGMIIIMPPU) + +#define S_CALRESET 8 +#define V_CALRESET(x) ((x) << S_CALRESET) +#define F_CALRESET V_CALRESET(1U) + +#define S_CALUPDATE 7 +#define V_CALUPDATE(x) ((x) << S_CALUPDATE) +#define F_CALUPDATE V_CALUPDATE(1U) + +#define A_XGM_XAUI_IMP 0x8a0 + +#define S_CALBUSY 31 +#define V_CALBUSY(x) ((x) << S_CALBUSY) +#define F_CALBUSY V_CALBUSY(1U) + +#define S_XGM_CALFAULT 29 +#define V_XGM_CALFAULT(x) ((x) << S_XGM_CALFAULT) +#define F_XGM_CALFAULT V_XGM_CALFAULT(1U) + +#define S_CALIMP 24 +#define M_CALIMP 0x1f +#define V_CALIMP(x) ((x) << S_CALIMP) +#define G_CALIMP(x) (((x) >> S_CALIMP) & M_CALIMP) + +#define S_XAUIIMP 0 +#define M_XAUIIMP 0x7 +#define V_XAUIIMP(x) ((x) << S_XAUIIMP) + +#define A_XGM_RX_MAX_PKT_SIZE 0x8a8 +#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4 + +#define A_XGM_RESET_CTRL 0x8ac + +#define S_XG2G_RESET_ 3 +#define V_XG2G_RESET_(x) ((x) << S_XG2G_RESET_) +#define F_XG2G_RESET_ V_XG2G_RESET_(1U) + +#define S_RGMII_RESET_ 2 +#define V_RGMII_RESET_(x) ((x) << S_RGMII_RESET_) +#define F_RGMII_RESET_ V_RGMII_RESET_(1U) + +#define S_PCS_RESET_ 1 +#define V_PCS_RESET_(x) ((x) << S_PCS_RESET_) +#define F_PCS_RESET_ V_PCS_RESET_(1U) + +#define S_MAC_RESET_ 0 +#define V_MAC_RESET_(x) ((x) << S_MAC_RESET_) +#define F_MAC_RESET_ V_MAC_RESET_(1U) + +#define A_XGM_PORT_CFG 0x8b8 + +#define S_CLKDIVRESET_ 3 +#define V_CLKDIVRESET_(x) ((x) << S_CLKDIVRESET_) +#define F_CLKDIVRESET_ V_CLKDIVRESET_(1U) + +#define S_PORTSPEED 1 +#define M_PORTSPEED 0x3 + +#define V_PORTSPEED(x) ((x) << S_PORTSPEED) + +#define S_ENRGMII 0 +#define V_ENRGMII(x) ((x) << S_ENRGMII) +#define F_ENRGMII V_ENRGMII(1U) + +#define A_XGM_INT_ENABLE 0x8d4 + +#define S_TXFIFO_PRTY_ERR 17 +#define M_TXFIFO_PRTY_ERR 0x7 + +#define V_TXFIFO_PRTY_ERR(x) ((x) << S_TXFIFO_PRTY_ERR) + +#define S_RXFIFO_PRTY_ERR 14 +#define M_RXFIFO_PRTY_ERR 0x7 + +#define V_RXFIFO_PRTY_ERR(x) ((x) << S_RXFIFO_PRTY_ERR) + +#define S_TXFIFO_UNDERRUN 13 +#define V_TXFIFO_UNDERRUN(x) ((x) << S_TXFIFO_UNDERRUN) +#define F_TXFIFO_UNDERRUN V_TXFIFO_UNDERRUN(1U) + +#define S_RXFIFO_OVERFLOW 12 +#define V_RXFIFO_OVERFLOW(x) ((x) << S_RXFIFO_OVERFLOW) +#define F_RXFIFO_OVERFLOW V_RXFIFO_OVERFLOW(1U) + +#define S_SERDES_LOS 4 +#define M_SERDES_LOS 0xf + +#define V_SERDES_LOS(x) ((x) << S_SERDES_LOS) + +#define S_XAUIPCSCTCERR 3 +#define V_XAUIPCSCTCERR(x) ((x) << S_XAUIPCSCTCERR) +#define F_XAUIPCSCTCERR V_XAUIPCSCTCERR(1U) + +#define S_XAUIPCSALIGNCHANGE 2 +#define V_XAUIPCSALIGNCHANGE(x) ((x) << S_XAUIPCSALIGNCHANGE) +#define F_XAUIPCSALIGNCHANGE V_XAUIPCSALIGNCHANGE(1U) + +#define A_XGM_INT_CAUSE 0x8d8 + +#define A_XGM_XAUI_ACT_CTRL 0x8dc + +#define S_TXACTENABLE 1 +#define V_TXACTENABLE(x) ((x) << S_TXACTENABLE) +#define F_TXACTENABLE V_TXACTENABLE(1U) + +#define A_XGM_SERDES_CTRL0 0x8e0 + +#define S_RESET3 23 +#define V_RESET3(x) ((x) << S_RESET3) +#define F_RESET3 V_RESET3(1U) + +#define S_RESET2 22 +#define V_RESET2(x) ((x) << S_RESET2) +#define F_RESET2 V_RESET2(1U) + +#define S_RESET1 21 +#define V_RESET1(x) ((x) << S_RESET1) +#define F_RESET1 V_RESET1(1U) + +#define S_RESET0 20 +#define V_RESET0(x) ((x) << S_RESET0) +#define F_RESET0 V_RESET0(1U) + +#define S_PWRDN3 19 +#define V_PWRDN3(x) ((x) << S_PWRDN3) +#define F_PWRDN3 V_PWRDN3(1U) + +#define S_PWRDN2 18 +#define V_PWRDN2(x) ((x) << S_PWRDN2) +#define F_PWRDN2 V_PWRDN2(1U) + +#define S_PWRDN1 17 +#define V_PWRDN1(x) ((x) << S_PWRDN1) +#define F_PWRDN1 V_PWRDN1(1U) + +#define S_PWRDN0 16 +#define V_PWRDN0(x) ((x) << S_PWRDN0) +#define F_PWRDN0 V_PWRDN0(1U) + +#define S_RESETPLL23 15 +#define V_RESETPLL23(x) ((x) << S_RESETPLL23) +#define F_RESETPLL23 V_RESETPLL23(1U) + +#define S_RESETPLL01 14 +#define V_RESETPLL01(x) ((x) << S_RESETPLL01) +#define F_RESETPLL01 V_RESETPLL01(1U) + +#define A_XGM_SERDES_STAT0 0x8f0 + +#define S_LOWSIG0 0 +#define V_LOWSIG0(x) ((x) << S_LOWSIG0) +#define F_LOWSIG0 V_LOWSIG0(1U) + +#define A_XGM_SERDES_STAT3 0x8fc + +#define A_XGM_STAT_TX_BYTE_LOW 0x900 + +#define A_XGM_STAT_TX_BYTE_HIGH 0x904 + +#define A_XGM_STAT_TX_FRAME_LOW 0x908 + +#define A_XGM_STAT_TX_FRAME_HIGH 0x90c + +#define A_XGM_STAT_TX_BCAST 0x910 + +#define A_XGM_STAT_TX_MCAST 0x914 + +#define A_XGM_STAT_TX_PAUSE 0x918 + +#define A_XGM_STAT_TX_64B_FRAMES 0x91c + +#define A_XGM_STAT_TX_65_127B_FRAMES 0x920 + +#define A_XGM_STAT_TX_128_255B_FRAMES 0x924 + +#define A_XGM_STAT_TX_256_511B_FRAMES 0x928 + +#define A_XGM_STAT_TX_512_1023B_FRAMES 0x92c + +#define A_XGM_STAT_TX_1024_1518B_FRAMES 0x930 + +#define A_XGM_STAT_TX_1519_MAXB_FRAMES 0x934 + +#define A_XGM_STAT_TX_ERR_FRAMES 0x938 + +#define A_XGM_STAT_RX_BYTES_LOW 0x93c + +#define A_XGM_STAT_RX_BYTES_HIGH 0x940 + +#define A_XGM_STAT_RX_FRAMES_LOW 0x944 + +#define A_XGM_STAT_RX_FRAMES_HIGH 0x948 + +#define A_XGM_STAT_RX_BCAST_FRAMES 0x94c + +#define A_XGM_STAT_RX_MCAST_FRAMES 0x950 + +#define A_XGM_STAT_RX_PAUSE_FRAMES 0x954 + +#define A_XGM_STAT_RX_64B_FRAMES 0x958 + +#define A_XGM_STAT_RX_65_127B_FRAMES 0x95c + +#define A_XGM_STAT_RX_128_255B_FRAMES 0x960 + +#define A_XGM_STAT_RX_256_511B_FRAMES 0x964 + +#define A_XGM_STAT_RX_512_1023B_FRAMES 0x968 + +#define A_XGM_STAT_RX_1024_1518B_FRAMES 0x96c + +#define A_XGM_STAT_RX_1519_MAXB_FRAMES 0x970 + +#define A_XGM_STAT_RX_SHORT_FRAMES 0x974 + +#define A_XGM_STAT_RX_OVERSIZE_FRAMES 0x978 + +#define A_XGM_STAT_RX_JABBER_FRAMES 0x97c + +#define A_XGM_STAT_RX_CRC_ERR_FRAMES 0x980 + +#define A_XGM_STAT_RX_LENGTH_ERR_FRAMES 0x984 + +#define A_XGM_STAT_RX_SYM_CODE_ERR_FRAMES 0x988 + +#define A_XGM_SERDES_STATUS0 0x98c + +#define A_XGM_SERDES_STATUS1 0x990 + +#define S_CMULOCK 31 +#define V_CMULOCK(x) ((x) << S_CMULOCK) +#define F_CMULOCK V_CMULOCK(1U) + +#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4 + +#define A_XGM_RX_SPI4_SOP_EOP_CNT 0x9ac + +#define XGMAC0_1_BASE_ADDR 0xa00 diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c new file mode 100644 index 000000000000..3f2cf8a07c61 --- /dev/null +++ b/drivers/net/cxgb3/sge.c @@ -0,0 +1,2681 @@ +/* + * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "regs.h" +#include "sge_defs.h" +#include "t3_cpl.h" +#include "firmware_exports.h" + +#define USE_GTS 0 + +#define SGE_RX_SM_BUF_SIZE 1536 +#define SGE_RX_COPY_THRES 256 + +# define SGE_RX_DROP_THRES 16 + +/* + * Period of the Tx buffer reclaim timer. This timer does not need to run + * frequently as Tx buffers are usually reclaimed by new Tx packets. + */ +#define TX_RECLAIM_PERIOD (HZ / 4) + +/* WR size in bytes */ +#define WR_LEN (WR_FLITS * 8) + +/* + * Types of Tx queues in each queue set. Order here matters, do not change. + */ +enum { TXQ_ETH, TXQ_OFLD, TXQ_CTRL }; + +/* Values for sge_txq.flags */ +enum { + TXQ_RUNNING = 1 << 0, /* fetch engine is running */ + TXQ_LAST_PKT_DB = 1 << 1, /* last packet rang the doorbell */ +}; + +struct tx_desc { + u64 flit[TX_DESC_FLITS]; +}; + +struct rx_desc { + __be32 addr_lo; + __be32 len_gen; + __be32 gen2; + __be32 addr_hi; +}; + +struct tx_sw_desc { /* SW state per Tx descriptor */ + struct sk_buff *skb; +}; + +struct rx_sw_desc { /* SW state per Rx descriptor */ + struct sk_buff *skb; + DECLARE_PCI_UNMAP_ADDR(dma_addr); +}; + +struct rsp_desc { /* response queue descriptor */ + struct rss_header rss_hdr; + __be32 flags; + __be32 len_cq; + u8 imm_data[47]; + u8 intr_gen; +}; + +struct unmap_info { /* packet unmapping info, overlays skb->cb */ + int sflit; /* start flit of first SGL entry in Tx descriptor */ + u16 fragidx; /* first page fragment in current Tx descriptor */ + u16 addr_idx; /* buffer index of first SGL entry in descriptor */ + u32 len; /* mapped length of skb main body */ +}; + +/* + * Maps a number of flits to the number of Tx descriptors that can hold them. + * The formula is + * + * desc = 1 + (flits - 2) / (WR_FLITS - 1). + * + * HW allows up to 4 descriptors to be combined into a WR. + */ +static u8 flit_desc_map[] = { + 0, +#if SGE_NUM_GENBITS == 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 +#elif SGE_NUM_GENBITS == 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +#else +# error "SGE_NUM_GENBITS must be 1 or 2" +#endif +}; + +static inline struct sge_qset *fl_to_qset(const struct sge_fl *q, int qidx) +{ + return container_of(q, struct sge_qset, fl[qidx]); +} + +static inline struct sge_qset *rspq_to_qset(const struct sge_rspq *q) +{ + return container_of(q, struct sge_qset, rspq); +} + +static inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx) +{ + return container_of(q, struct sge_qset, txq[qidx]); +} + +/** + * refill_rspq - replenish an SGE response queue + * @adapter: the adapter + * @q: the response queue to replenish + * @credits: how many new responses to make available + * + * Replenishes a response queue by making the supplied number of responses + * available to HW. + */ +static inline void refill_rspq(struct adapter *adapter, + const struct sge_rspq *q, unsigned int credits) +{ + t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN, + V_RSPQ(q->cntxt_id) | V_CREDITS(credits)); +} + +/** + * need_skb_unmap - does the platform need unmapping of sk_buffs? + * + * Returns true if the platfrom needs sk_buff unmapping. The compiler + * optimizes away unecessary code if this returns true. + */ +static inline int need_skb_unmap(void) +{ + /* + * This structure is used to tell if the platfrom needs buffer + * unmapping by checking if DECLARE_PCI_UNMAP_ADDR defines anything. + */ + struct dummy { + DECLARE_PCI_UNMAP_ADDR(addr); + }; + + return sizeof(struct dummy) != 0; +} + +/** + * unmap_skb - unmap a packet main body and its page fragments + * @skb: the packet + * @q: the Tx queue containing Tx descriptors for the packet + * @cidx: index of Tx descriptor + * @pdev: the PCI device + * + * Unmap the main body of an sk_buff and its page fragments, if any. + * Because of the fairly complicated structure of our SGLs and the desire + * to conserve space for metadata, we keep the information necessary to + * unmap an sk_buff partly in the sk_buff itself (in its cb), and partly + * in the Tx descriptors (the physical addresses of the various data + * buffers). The send functions initialize the state in skb->cb so we + * can unmap the buffers held in the first Tx descriptor here, and we + * have enough information at this point to update the state for the next + * Tx descriptor. + */ +static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q, + unsigned int cidx, struct pci_dev *pdev) +{ + const struct sg_ent *sgp; + struct unmap_info *ui = (struct unmap_info *)skb->cb; + int nfrags, frag_idx, curflit, j = ui->addr_idx; + + sgp = (struct sg_ent *)&q->desc[cidx].flit[ui->sflit]; + + if (ui->len) { + pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), ui->len, + PCI_DMA_TODEVICE); + ui->len = 0; /* so we know for next descriptor for this skb */ + j = 1; + } + + frag_idx = ui->fragidx; + curflit = ui->sflit + 1 + j; + nfrags = skb_shinfo(skb)->nr_frags; + + while (frag_idx < nfrags && curflit < WR_FLITS) { + pci_unmap_page(pdev, be64_to_cpu(sgp->addr[j]), + skb_shinfo(skb)->frags[frag_idx].size, + PCI_DMA_TODEVICE); + j ^= 1; + if (j == 0) { + sgp++; + curflit++; + } + curflit++; + frag_idx++; + } + + if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */ + ui->fragidx = frag_idx; + ui->addr_idx = j; + ui->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */ + } +} + +/** + * free_tx_desc - reclaims Tx descriptors and their buffers + * @adapter: the adapter + * @q: the Tx queue to reclaim descriptors from + * @n: the number of descriptors to reclaim + * + * Reclaims Tx descriptors from an SGE Tx queue and frees the associated + * Tx buffers. Called with the Tx queue lock held. + */ +static void free_tx_desc(struct adapter *adapter, struct sge_txq *q, + unsigned int n) +{ + struct tx_sw_desc *d; + struct pci_dev *pdev = adapter->pdev; + unsigned int cidx = q->cidx; + + d = &q->sdesc[cidx]; + while (n--) { + if (d->skb) { /* an SGL is present */ + if (need_skb_unmap()) + unmap_skb(d->skb, q, cidx, pdev); + if (d->skb->priority == cidx) + kfree_skb(d->skb); + } + ++d; + if (++cidx == q->size) { + cidx = 0; + d = q->sdesc; + } + } + q->cidx = cidx; +} + +/** + * reclaim_completed_tx - reclaims completed Tx descriptors + * @adapter: the adapter + * @q: the Tx queue to reclaim completed descriptors from + * + * Reclaims Tx descriptors that the SGE has indicated it has processed, + * and frees the associated buffers if possible. Called with the Tx + * queue's lock held. + */ +static inline void reclaim_completed_tx(struct adapter *adapter, + struct sge_txq *q) +{ + unsigned int reclaim = q->processed - q->cleaned; + + if (reclaim) { + free_tx_desc(adapter, q, reclaim); + q->cleaned += reclaim; + q->in_use -= reclaim; + } +} + +/** + * should_restart_tx - are there enough resources to restart a Tx queue? + * @q: the Tx queue + * + * Checks if there are enough descriptors to restart a suspended Tx queue. + */ +static inline int should_restart_tx(const struct sge_txq *q) +{ + unsigned int r = q->processed - q->cleaned; + + return q->in_use - r < (q->size >> 1); +} + +/** + * free_rx_bufs - free the Rx buffers on an SGE free list + * @pdev: the PCI device associated with the adapter + * @rxq: the SGE free list to clean up + * + * Release the buffers on an SGE free-buffer Rx queue. HW fetching from + * this queue should be stopped before calling this function. + */ +static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) +{ + unsigned int cidx = q->cidx; + + while (q->credits--) { + struct rx_sw_desc *d = &q->sdesc[cidx]; + + pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr), + q->buf_size, PCI_DMA_FROMDEVICE); + kfree_skb(d->skb); + d->skb = NULL; + if (++cidx == q->size) + cidx = 0; + } +} + +/** + * add_one_rx_buf - add a packet buffer to a free-buffer list + * @skb: the buffer to add + * @len: the buffer length + * @d: the HW Rx descriptor to write + * @sd: the SW Rx descriptor to write + * @gen: the generation bit value + * @pdev: the PCI device associated with the adapter + * + * Add a buffer of the given length to the supplied HW and SW Rx + * descriptors. + */ +static inline void add_one_rx_buf(struct sk_buff *skb, unsigned int len, + struct rx_desc *d, struct rx_sw_desc *sd, + unsigned int gen, struct pci_dev *pdev) +{ + dma_addr_t mapping; + + sd->skb = skb; + mapping = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE); + pci_unmap_addr_set(sd, dma_addr, mapping); + + d->addr_lo = cpu_to_be32(mapping); + d->addr_hi = cpu_to_be32((u64) mapping >> 32); + wmb(); + d->len_gen = cpu_to_be32(V_FLD_GEN1(gen)); + d->gen2 = cpu_to_be32(V_FLD_GEN2(gen)); +} + +/** + * refill_fl - refill an SGE free-buffer list + * @adapter: the adapter + * @q: the free-list to refill + * @n: the number of new buffers to allocate + * @gfp: the gfp flags for allocating new buffers + * + * (Re)populate an SGE free-buffer list with up to @n new packet buffers, + * allocated with the supplied gfp flags. The caller must assure that + * @n does not exceed the queue's capacity. + */ +static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) +{ + struct rx_sw_desc *sd = &q->sdesc[q->pidx]; + struct rx_desc *d = &q->desc[q->pidx]; + + while (n--) { + struct sk_buff *skb = alloc_skb(q->buf_size, gfp); + + if (!skb) + break; + + add_one_rx_buf(skb, q->buf_size, d, sd, q->gen, adap->pdev); + d++; + sd++; + if (++q->pidx == q->size) { + q->pidx = 0; + q->gen ^= 1; + sd = q->sdesc; + d = q->desc; + } + q->credits++; + } + + t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); +} + +static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl) +{ + refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC); +} + +/** + * recycle_rx_buf - recycle a receive buffer + * @adapter: the adapter + * @q: the SGE free list + * @idx: index of buffer to recycle + * + * Recycles the specified buffer on the given free list by adding it at + * the next available slot on the list. + */ +static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q, + unsigned int idx) +{ + struct rx_desc *from = &q->desc[idx]; + struct rx_desc *to = &q->desc[q->pidx]; + + q->sdesc[q->pidx] = q->sdesc[idx]; + to->addr_lo = from->addr_lo; /* already big endian */ + to->addr_hi = from->addr_hi; /* likewise */ + wmb(); + to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen)); + to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen)); + q->credits++; + + if (++q->pidx == q->size) { + q->pidx = 0; + q->gen ^= 1; + } + t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); +} + +/** + * alloc_ring - allocate resources for an SGE descriptor ring + * @pdev: the PCI device + * @nelem: the number of descriptors + * @elem_size: the size of each descriptor + * @sw_size: the size of the SW state associated with each ring element + * @phys: the physical address of the allocated ring + * @metadata: address of the array holding the SW state for the ring + * + * Allocates resources for an SGE descriptor ring, such as Tx queues, + * free buffer lists, or response queues. Each SGE ring requires + * space for its HW descriptors plus, optionally, space for the SW state + * associated with each HW entry (the metadata). The function returns + * three values: the virtual address for the HW ring (the return value + * of the function), the physical address of the HW ring, and the address + * of the SW ring. + */ +static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, + size_t sw_size, dma_addr_t *phys, void *metadata) +{ + size_t len = nelem * elem_size; + void *s = NULL; + void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL); + + if (!p) + return NULL; + if (sw_size) { + s = kcalloc(nelem, sw_size, GFP_KERNEL); + + if (!s) { + dma_free_coherent(&pdev->dev, len, p, *phys); + return NULL; + } + } + if (metadata) + *(void **)metadata = s; + memset(p, 0, len); + return p; +} + +/** + * free_qset - free the resources of an SGE queue set + * @adapter: the adapter owning the queue set + * @q: the queue set + * + * Release the HW and SW resources associated with an SGE queue set, such + * as HW contexts, packet buffers, and descriptor rings. Traffic to the + * queue set must be quiesced prior to calling this. + */ +void t3_free_qset(struct adapter *adapter, struct sge_qset *q) +{ + int i; + struct pci_dev *pdev = adapter->pdev; + + if (q->tx_reclaim_timer.function) + del_timer_sync(&q->tx_reclaim_timer); + + for (i = 0; i < SGE_RXQ_PER_SET; ++i) + if (q->fl[i].desc) { + spin_lock(&adapter->sge.reg_lock); + t3_sge_disable_fl(adapter, q->fl[i].cntxt_id); + spin_unlock(&adapter->sge.reg_lock); + free_rx_bufs(pdev, &q->fl[i]); + kfree(q->fl[i].sdesc); + dma_free_coherent(&pdev->dev, + q->fl[i].size * + sizeof(struct rx_desc), q->fl[i].desc, + q->fl[i].phys_addr); + } + + for (i = 0; i < SGE_TXQ_PER_SET; ++i) + if (q->txq[i].desc) { + spin_lock(&adapter->sge.reg_lock); + t3_sge_enable_ecntxt(adapter, q->txq[i].cntxt_id, 0); + spin_unlock(&adapter->sge.reg_lock); + if (q->txq[i].sdesc) { + free_tx_desc(adapter, &q->txq[i], + q->txq[i].in_use); + kfree(q->txq[i].sdesc); + } + dma_free_coherent(&pdev->dev, + q->txq[i].size * + sizeof(struct tx_desc), + q->txq[i].desc, q->txq[i].phys_addr); + __skb_queue_purge(&q->txq[i].sendq); + } + + if (q->rspq.desc) { + spin_lock(&adapter->sge.reg_lock); + t3_sge_disable_rspcntxt(adapter, q->rspq.cntxt_id); + spin_unlock(&adapter->sge.reg_lock); + dma_free_coherent(&pdev->dev, + q->rspq.size * sizeof(struct rsp_desc), + q->rspq.desc, q->rspq.phys_addr); + } + + if (q->netdev) + q->netdev->atalk_ptr = NULL; + + memset(q, 0, sizeof(*q)); +} + +/** + * init_qset_cntxt - initialize an SGE queue set context info + * @qs: the queue set + * @id: the queue set id + * + * Initializes the TIDs and context ids for the queues of a queue set. + */ +static void init_qset_cntxt(struct sge_qset *qs, unsigned int id) +{ + qs->rspq.cntxt_id = id; + qs->fl[0].cntxt_id = 2 * id; + qs->fl[1].cntxt_id = 2 * id + 1; + qs->txq[TXQ_ETH].cntxt_id = FW_TUNNEL_SGEEC_START + id; + qs->txq[TXQ_ETH].token = FW_TUNNEL_TID_START + id; + qs->txq[TXQ_OFLD].cntxt_id = FW_OFLD_SGEEC_START + id; + qs->txq[TXQ_CTRL].cntxt_id = FW_CTRL_SGEEC_START + id; + qs->txq[TXQ_CTRL].token = FW_CTRL_TID_START + id; +} + +/** + * sgl_len - calculates the size of an SGL of the given capacity + * @n: the number of SGL entries + * + * Calculates the number of flits needed for a scatter/gather list that + * can hold the given number of entries. + */ +static inline unsigned int sgl_len(unsigned int n) +{ + /* alternatively: 3 * (n / 2) + 2 * (n & 1) */ + return (3 * n) / 2 + (n & 1); +} + +/** + * flits_to_desc - returns the num of Tx descriptors for the given flits + * @n: the number of flits + * + * Calculates the number of Tx descriptors needed for the supplied number + * of flits. + */ +static inline unsigned int flits_to_desc(unsigned int n) +{ + BUG_ON(n >= ARRAY_SIZE(flit_desc_map)); + return flit_desc_map[n]; +} + +/** + * get_packet - return the next ingress packet buffer from a free list + * @adap: the adapter that received the packet + * @fl: the SGE free list holding the packet + * @len: the packet length including any SGE padding + * @drop_thres: # of remaining buffers before we start dropping packets + * + * Get the next packet from a free list and complete setup of the + * sk_buff. If the packet is small we make a copy and recycle the + * original buffer, otherwise we use the original buffer itself. If a + * positive drop threshold is supplied packets are dropped and their + * buffers recycled if (a) the number of remaining buffers is under the + * threshold and the packet is too big to copy, or (b) the packet should + * be copied but there is no memory for the copy. + */ +static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl, + unsigned int len, unsigned int drop_thres) +{ + struct sk_buff *skb = NULL; + struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; + + prefetch(sd->skb->data); + + if (len <= SGE_RX_COPY_THRES) { + skb = alloc_skb(len, GFP_ATOMIC); + if (likely(skb != NULL)) { + __skb_put(skb, len); + pci_dma_sync_single_for_cpu(adap->pdev, + pci_unmap_addr(sd, + dma_addr), + len, PCI_DMA_FROMDEVICE); + memcpy(skb->data, sd->skb->data, len); + pci_dma_sync_single_for_device(adap->pdev, + pci_unmap_addr(sd, + dma_addr), + len, PCI_DMA_FROMDEVICE); + } else if (!drop_thres) + goto use_orig_buf; + recycle: + recycle_rx_buf(adap, fl, fl->cidx); + return skb; + } + + if (unlikely(fl->credits < drop_thres)) + goto recycle; + + use_orig_buf: + pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr), + fl->buf_size, PCI_DMA_FROMDEVICE); + skb = sd->skb; + skb_put(skb, len); + __refill_fl(adap, fl); + return skb; +} + +/** + * get_imm_packet - return the next ingress packet buffer from a response + * @resp: the response descriptor containing the packet data + * + * Return a packet containing the immediate data of the given response. + */ +static inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp) +{ + struct sk_buff *skb = alloc_skb(IMMED_PKT_SIZE, GFP_ATOMIC); + + if (skb) { + __skb_put(skb, IMMED_PKT_SIZE); + memcpy(skb->data, resp->imm_data, IMMED_PKT_SIZE); + } + return skb; +} + +/** + * calc_tx_descs - calculate the number of Tx descriptors for a packet + * @skb: the packet + * + * Returns the number of Tx descriptors needed for the given Ethernet + * packet. Ethernet packets require addition of WR and CPL headers. + */ +static inline unsigned int calc_tx_descs(const struct sk_buff *skb) +{ + unsigned int flits; + + if (skb->len <= WR_LEN - sizeof(struct cpl_tx_pkt)) + return 1; + + flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 2; + if (skb_shinfo(skb)->gso_size) + flits++; + return flits_to_desc(flits); +} + +/** + * make_sgl - populate a scatter/gather list for a packet + * @skb: the packet + * @sgp: the SGL to populate + * @start: start address of skb main body data to include in the SGL + * @len: length of skb main body data to include in the SGL + * @pdev: the PCI device + * + * Generates a scatter/gather list for the buffers that make up a packet + * and returns the SGL size in 8-byte words. The caller must size the SGL + * appropriately. + */ +static inline unsigned int make_sgl(const struct sk_buff *skb, + struct sg_ent *sgp, unsigned char *start, + unsigned int len, struct pci_dev *pdev) +{ + dma_addr_t mapping; + unsigned int i, j = 0, nfrags; + + if (len) { + mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE); + sgp->len[0] = cpu_to_be32(len); + sgp->addr[0] = cpu_to_be64(mapping); + j = 1; + } + + nfrags = skb_shinfo(skb)->nr_frags; + for (i = 0; i < nfrags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + mapping = pci_map_page(pdev, frag->page, frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + sgp->len[j] = cpu_to_be32(frag->size); + sgp->addr[j] = cpu_to_be64(mapping); + j ^= 1; + if (j == 0) + ++sgp; + } + if (j) + sgp->len[j] = 0; + return ((nfrags + (len != 0)) * 3) / 2 + j; +} + +/** + * check_ring_tx_db - check and potentially ring a Tx queue's doorbell + * @adap: the adapter + * @q: the Tx queue + * + * Ring the doorbel if a Tx queue is asleep. There is a natural race, + * where the HW is going to sleep just after we checked, however, + * then the interrupt handler will detect the outstanding TX packet + * and ring the doorbell for us. + * + * When GTS is disabled we unconditionally ring the doorbell. + */ +static inline void check_ring_tx_db(struct adapter *adap, struct sge_txq *q) +{ +#if USE_GTS + clear_bit(TXQ_LAST_PKT_DB, &q->flags); + if (test_and_set_bit(TXQ_RUNNING, &q->flags) == 0) { + set_bit(TXQ_LAST_PKT_DB, &q->flags); + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); + } +#else + wmb(); /* write descriptors before telling HW */ + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); +#endif +} + +static inline void wr_gen2(struct tx_desc *d, unsigned int gen) +{ +#if SGE_NUM_GENBITS == 2 + d->flit[TX_DESC_FLITS - 1] = cpu_to_be64(gen); +#endif +} + +/** + * write_wr_hdr_sgl - write a WR header and, optionally, SGL + * @ndesc: number of Tx descriptors spanned by the SGL + * @skb: the packet corresponding to the WR + * @d: first Tx descriptor to be written + * @pidx: index of above descriptors + * @q: the SGE Tx queue + * @sgl: the SGL + * @flits: number of flits to the start of the SGL in the first descriptor + * @sgl_flits: the SGL size in flits + * @gen: the Tx descriptor generation + * @wr_hi: top 32 bits of WR header based on WR type (big endian) + * @wr_lo: low 32 bits of WR header based on WR type (big endian) + * + * Write a work request header and an associated SGL. If the SGL is + * small enough to fit into one Tx descriptor it has already been written + * and we just need to write the WR header. Otherwise we distribute the + * SGL across the number of descriptors it spans. + */ +static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, + struct tx_desc *d, unsigned int pidx, + const struct sge_txq *q, + const struct sg_ent *sgl, + unsigned int flits, unsigned int sgl_flits, + unsigned int gen, unsigned int wr_hi, + unsigned int wr_lo) +{ + struct work_request_hdr *wrp = (struct work_request_hdr *)d; + struct tx_sw_desc *sd = &q->sdesc[pidx]; + + sd->skb = skb; + if (need_skb_unmap()) { + struct unmap_info *ui = (struct unmap_info *)skb->cb; + + ui->fragidx = 0; + ui->addr_idx = 0; + ui->sflit = flits; + } + + if (likely(ndesc == 1)) { + skb->priority = pidx; + wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) | + V_WR_SGLSFLT(flits)) | wr_hi; + wmb(); + wrp->wr_lo = htonl(V_WR_LEN(flits + sgl_flits) | + V_WR_GEN(gen)) | wr_lo; + wr_gen2(d, gen); + } else { + unsigned int ogen = gen; + const u64 *fp = (const u64 *)sgl; + struct work_request_hdr *wp = wrp; + + wrp->wr_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) | + V_WR_SGLSFLT(flits)) | wr_hi; + + while (sgl_flits) { + unsigned int avail = WR_FLITS - flits; + + if (avail > sgl_flits) + avail = sgl_flits; + memcpy(&d->flit[flits], fp, avail * sizeof(*fp)); + sgl_flits -= avail; + ndesc--; + if (!sgl_flits) + break; + + fp += avail; + d++; + sd++; + if (++pidx == q->size) { + pidx = 0; + gen ^= 1; + d = q->desc; + sd = q->sdesc; + } + + sd->skb = skb; + wrp = (struct work_request_hdr *)d; + wrp->wr_hi = htonl(V_WR_DATATYPE(1) | + V_WR_SGLSFLT(1)) | wr_hi; + wrp->wr_lo = htonl(V_WR_LEN(min(WR_FLITS, + sgl_flits + 1)) | + V_WR_GEN(gen)) | wr_lo; + wr_gen2(d, gen); + flits = 1; + } + skb->priority = pidx; + wrp->wr_hi |= htonl(F_WR_EOP); + wmb(); + wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo; + wr_gen2((struct tx_desc *)wp, ogen); + WARN_ON(ndesc != 0); + } +} + +/** + * write_tx_pkt_wr - write a TX_PKT work request + * @adap: the adapter + * @skb: the packet to send + * @pi: the egress interface + * @pidx: index of the first Tx descriptor to write + * @gen: the generation value to use + * @q: the Tx queue + * @ndesc: number of descriptors the packet will occupy + * @compl: the value of the COMPL bit to use + * + * Generate a TX_PKT work request to send the supplied packet. + */ +static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, + const struct port_info *pi, + unsigned int pidx, unsigned int gen, + struct sge_txq *q, unsigned int ndesc, + unsigned int compl) +{ + unsigned int flits, sgl_flits, cntrl, tso_info; + struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1]; + struct tx_desc *d = &q->desc[pidx]; + struct cpl_tx_pkt *cpl = (struct cpl_tx_pkt *)d; + + cpl->len = htonl(skb->len | 0x80000000); + cntrl = V_TXPKT_INTF(pi->port_id); + + if (vlan_tx_tag_present(skb) && pi->vlan_grp) + cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(vlan_tx_tag_get(skb)); + + tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size); + if (tso_info) { + int eth_type; + struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)cpl; + + d->flit[2] = 0; + cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO); + hdr->cntrl = htonl(cntrl); + eth_type = skb->nh.raw - skb->data == ETH_HLEN ? + CPL_ETH_II : CPL_ETH_II_VLAN; + tso_info |= V_LSO_ETH_TYPE(eth_type) | + V_LSO_IPHDR_WORDS(skb->nh.iph->ihl) | + V_LSO_TCPHDR_WORDS(skb->h.th->doff); + hdr->lso_info = htonl(tso_info); + flits = 3; + } else { + cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT); + cntrl |= F_TXPKT_IPCSUM_DIS; /* SW calculates IP csum */ + cntrl |= V_TXPKT_L4CSUM_DIS(skb->ip_summed != CHECKSUM_PARTIAL); + cpl->cntrl = htonl(cntrl); + + if (skb->len <= WR_LEN - sizeof(*cpl)) { + q->sdesc[pidx].skb = NULL; + if (!skb->data_len) + memcpy(&d->flit[2], skb->data, skb->len); + else + skb_copy_bits(skb, 0, &d->flit[2], skb->len); + + flits = (skb->len + 7) / 8 + 2; + cpl->wr.wr_hi = htonl(V_WR_BCNTLFLT(skb->len & 7) | + V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) + | F_WR_SOP | F_WR_EOP | compl); + wmb(); + cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) | + V_WR_TID(q->token)); + wr_gen2(d, gen); + kfree_skb(skb); + return; + } + + flits = 2; + } + + sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; + sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev); + if (need_skb_unmap()) + ((struct unmap_info *)skb->cb)->len = skb_headlen(skb); + + write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen, + htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl), + htonl(V_WR_TID(q->token))); +} + +/** + * eth_xmit - add a packet to the Ethernet Tx queue + * @skb: the packet + * @dev: the egress net device + * + * Add a packet to an SGE Tx queue. Runs with softirqs disabled. + */ +int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) +{ + unsigned int ndesc, pidx, credits, gen, compl; + const struct port_info *pi = netdev_priv(dev); + struct adapter *adap = dev->priv; + struct sge_qset *qs = dev2qset(dev); + struct sge_txq *q = &qs->txq[TXQ_ETH]; + + /* + * The chip min packet length is 9 octets but play safe and reject + * anything shorter than an Ethernet header. + */ + if (unlikely(skb->len < ETH_HLEN)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + spin_lock(&q->lock); + reclaim_completed_tx(adap, q); + + credits = q->size - q->in_use; + ndesc = calc_tx_descs(skb); + + if (unlikely(credits < ndesc)) { + if (!netif_queue_stopped(dev)) { + netif_stop_queue(dev); + set_bit(TXQ_ETH, &qs->txq_stopped); + q->stops++; + dev_err(&adap->pdev->dev, + "%s: Tx ring %u full while queue awake!\n", + dev->name, q->cntxt_id & 7); + } + spin_unlock(&q->lock); + return NETDEV_TX_BUSY; + } + + q->in_use += ndesc; + if (unlikely(credits - ndesc < q->stop_thres)) { + q->stops++; + netif_stop_queue(dev); + set_bit(TXQ_ETH, &qs->txq_stopped); +#if !USE_GTS + if (should_restart_tx(q) && + test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { + q->restarts++; + netif_wake_queue(dev); + } +#endif + } + + gen = q->gen; + q->unacked += ndesc; + compl = (q->unacked & 8) << (S_WR_COMPL - 3); + q->unacked &= 7; + pidx = q->pidx; + q->pidx += ndesc; + if (q->pidx >= q->size) { + q->pidx -= q->size; + q->gen ^= 1; + } + + /* update port statistics */ + if (skb->ip_summed == CHECKSUM_COMPLETE) + qs->port_stats[SGE_PSTAT_TX_CSUM]++; + if (skb_shinfo(skb)->gso_size) + qs->port_stats[SGE_PSTAT_TSO]++; + if (vlan_tx_tag_present(skb) && pi->vlan_grp) + qs->port_stats[SGE_PSTAT_VLANINS]++; + + dev->trans_start = jiffies; + spin_unlock(&q->lock); + + /* + * We do not use Tx completion interrupts to free DMAd Tx packets. + * This is good for performamce but means that we rely on new Tx + * packets arriving to run the destructors of completed packets, + * which open up space in their sockets' send queues. Sometimes + * we do not get such new packets causing Tx to stall. A single + * UDP transmitter is a good example of this situation. We have + * a clean up timer that periodically reclaims completed packets + * but it doesn't run often enough (nor do we want it to) to prevent + * lengthy stalls. A solution to this problem is to run the + * destructor early, after the packet is queued but before it's DMAd. + * A cons is that we lie to socket memory accounting, but the amount + * of extra memory is reasonable (limited by the number of Tx + * descriptors), the packets do actually get freed quickly by new + * packets almost always, and for protocols like TCP that wait for + * acks to really free up the data the extra memory is even less. + * On the positive side we run the destructors on the sending CPU + * rather than on a potentially different completing CPU, usually a + * good thing. We also run them without holding our Tx queue lock, + * unlike what reclaim_completed_tx() would otherwise do. + * + * Run the destructor before telling the DMA engine about the packet + * to make sure it doesn't complete and get freed prematurely. + */ + if (likely(!skb_shared(skb))) + skb_orphan(skb); + + write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl); + check_ring_tx_db(adap, q); + return NETDEV_TX_OK; +} + +/** + * write_imm - write a packet into a Tx descriptor as immediate data + * @d: the Tx descriptor to write + * @skb: the packet + * @len: the length of packet data to write as immediate data + * @gen: the generation bit value to write + * + * Writes a packet as immediate data into a Tx descriptor. The packet + * contains a work request at its beginning. We must write the packet + * carefully so the SGE doesn't read accidentally before it's written in + * its entirety. + */ +static inline void write_imm(struct tx_desc *d, struct sk_buff *skb, + unsigned int len, unsigned int gen) +{ + struct work_request_hdr *from = (struct work_request_hdr *)skb->data; + struct work_request_hdr *to = (struct work_request_hdr *)d; + + memcpy(&to[1], &from[1], len - sizeof(*from)); + to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP | + V_WR_BCNTLFLT(len & 7)); + wmb(); + to->wr_lo = from->wr_lo | htonl(V_WR_GEN(gen) | + V_WR_LEN((len + 7) / 8)); + wr_gen2(d, gen); + kfree_skb(skb); +} + +/** + * check_desc_avail - check descriptor availability on a send queue + * @adap: the adapter + * @q: the send queue + * @skb: the packet needing the descriptors + * @ndesc: the number of Tx descriptors needed + * @qid: the Tx queue number in its queue set (TXQ_OFLD or TXQ_CTRL) + * + * Checks if the requested number of Tx descriptors is available on an + * SGE send queue. If the queue is already suspended or not enough + * descriptors are available the packet is queued for later transmission. + * Must be called with the Tx queue locked. + * + * Returns 0 if enough descriptors are available, 1 if there aren't + * enough descriptors and the packet has been queued, and 2 if the caller + * needs to retry because there weren't enough descriptors at the + * beginning of the call but some freed up in the mean time. + */ +static inline int check_desc_avail(struct adapter *adap, struct sge_txq *q, + struct sk_buff *skb, unsigned int ndesc, + unsigned int qid) +{ + if (unlikely(!skb_queue_empty(&q->sendq))) { + addq_exit:__skb_queue_tail(&q->sendq, skb); + return 1; + } + if (unlikely(q->size - q->in_use < ndesc)) { + struct sge_qset *qs = txq_to_qset(q, qid); + + set_bit(qid, &qs->txq_stopped); + smp_mb__after_clear_bit(); + + if (should_restart_tx(q) && + test_and_clear_bit(qid, &qs->txq_stopped)) + return 2; + + q->stops++; + goto addq_exit; + } + return 0; +} + +/** + * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs + * @q: the SGE control Tx queue + * + * This is a variant of reclaim_completed_tx() that is used for Tx queues + * that send only immediate data (presently just the control queues) and + * thus do not have any sk_buffs to release. + */ +static inline void reclaim_completed_tx_imm(struct sge_txq *q) +{ + unsigned int reclaim = q->processed - q->cleaned; + + q->in_use -= reclaim; + q->cleaned += reclaim; +} + +static inline int immediate(const struct sk_buff *skb) +{ + return skb->len <= WR_LEN && !skb->data_len; +} + +/** + * ctrl_xmit - send a packet through an SGE control Tx queue + * @adap: the adapter + * @q: the control queue + * @skb: the packet + * + * Send a packet through an SGE control Tx queue. Packets sent through + * a control queue must fit entirely as immediate data in a single Tx + * descriptor and have no page fragments. + */ +static int ctrl_xmit(struct adapter *adap, struct sge_txq *q, + struct sk_buff *skb) +{ + int ret; + struct work_request_hdr *wrp = (struct work_request_hdr *)skb->data; + + if (unlikely(!immediate(skb))) { + WARN_ON(1); + dev_kfree_skb(skb); + return NET_XMIT_SUCCESS; + } + + wrp->wr_hi |= htonl(F_WR_SOP | F_WR_EOP); + wrp->wr_lo = htonl(V_WR_TID(q->token)); + + spin_lock(&q->lock); + again:reclaim_completed_tx_imm(q); + + ret = check_desc_avail(adap, q, skb, 1, TXQ_CTRL); + if (unlikely(ret)) { + if (ret == 1) { + spin_unlock(&q->lock); + return NET_XMIT_CN; + } + goto again; + } + + write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); + + q->in_use++; + if (++q->pidx >= q->size) { + q->pidx = 0; + q->gen ^= 1; + } + spin_unlock(&q->lock); + wmb(); + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); + return NET_XMIT_SUCCESS; +} + +/** + * restart_ctrlq - restart a suspended control queue + * @qs: the queue set cotaining the control queue + * + * Resumes transmission on a suspended Tx control queue. + */ +static void restart_ctrlq(unsigned long data) +{ + struct sk_buff *skb; + struct sge_qset *qs = (struct sge_qset *)data; + struct sge_txq *q = &qs->txq[TXQ_CTRL]; + struct adapter *adap = qs->netdev->priv; + + spin_lock(&q->lock); + again:reclaim_completed_tx_imm(q); + + while (q->in_use < q->size && (skb = __skb_dequeue(&q->sendq)) != NULL) { + + write_imm(&q->desc[q->pidx], skb, skb->len, q->gen); + + if (++q->pidx >= q->size) { + q->pidx = 0; + q->gen ^= 1; + } + q->in_use++; + } + + if (!skb_queue_empty(&q->sendq)) { + set_bit(TXQ_CTRL, &qs->txq_stopped); + smp_mb__after_clear_bit(); + + if (should_restart_tx(q) && + test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) + goto again; + q->stops++; + } + + spin_unlock(&q->lock); + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); +} + +/* + * Send a management message through control queue 0 + */ +int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb) +{ + return ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb); +} + +/** + * write_ofld_wr - write an offload work request + * @adap: the adapter + * @skb: the packet to send + * @q: the Tx queue + * @pidx: index of the first Tx descriptor to write + * @gen: the generation value to use + * @ndesc: number of descriptors the packet will occupy + * + * Write an offload work request to send the supplied packet. The packet + * data already carry the work request with most fields populated. + */ +static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, + struct sge_txq *q, unsigned int pidx, + unsigned int gen, unsigned int ndesc) +{ + unsigned int sgl_flits, flits; + struct work_request_hdr *from; + struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1]; + struct tx_desc *d = &q->desc[pidx]; + + if (immediate(skb)) { + q->sdesc[pidx].skb = NULL; + write_imm(d, skb, skb->len, gen); + return; + } + + /* Only TX_DATA builds SGLs */ + + from = (struct work_request_hdr *)skb->data; + memcpy(&d->flit[1], &from[1], skb->h.raw - skb->data - sizeof(*from)); + + flits = (skb->h.raw - skb->data) / 8; + sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; + sgl_flits = make_sgl(skb, sgp, skb->h.raw, skb->tail - skb->h.raw, + adap->pdev); + if (need_skb_unmap()) + ((struct unmap_info *)skb->cb)->len = skb->tail - skb->h.raw; + + write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, + gen, from->wr_hi, from->wr_lo); +} + +/** + * calc_tx_descs_ofld - calculate # of Tx descriptors for an offload packet + * @skb: the packet + * + * Returns the number of Tx descriptors needed for the given offload + * packet. These packets are already fully constructed. + */ +static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb) +{ + unsigned int flits, cnt = skb_shinfo(skb)->nr_frags; + + if (skb->len <= WR_LEN && cnt == 0) + return 1; /* packet fits as immediate data */ + + flits = (skb->h.raw - skb->data) / 8; /* headers */ + if (skb->tail != skb->h.raw) + cnt++; + return flits_to_desc(flits + sgl_len(cnt)); +} + +/** + * ofld_xmit - send a packet through an offload queue + * @adap: the adapter + * @q: the Tx offload queue + * @skb: the packet + * + * Send an offload packet through an SGE offload queue. + */ +static int ofld_xmit(struct adapter *adap, struct sge_txq *q, + struct sk_buff *skb) +{ + int ret; + unsigned int ndesc = calc_tx_descs_ofld(skb), pidx, gen; + + spin_lock(&q->lock); + again:reclaim_completed_tx(adap, q); + + ret = check_desc_avail(adap, q, skb, ndesc, TXQ_OFLD); + if (unlikely(ret)) { + if (ret == 1) { + skb->priority = ndesc; /* save for restart */ + spin_unlock(&q->lock); + return NET_XMIT_CN; + } + goto again; + } + + gen = q->gen; + q->in_use += ndesc; + pidx = q->pidx; + q->pidx += ndesc; + if (q->pidx >= q->size) { + q->pidx -= q->size; + q->gen ^= 1; + } + spin_unlock(&q->lock); + + write_ofld_wr(adap, skb, q, pidx, gen, ndesc); + check_ring_tx_db(adap, q); + return NET_XMIT_SUCCESS; +} + +/** + * restart_offloadq - restart a suspended offload queue + * @qs: the queue set cotaining the offload queue + * + * Resumes transmission on a suspended Tx offload queue. + */ +static void restart_offloadq(unsigned long data) +{ + struct sk_buff *skb; + struct sge_qset *qs = (struct sge_qset *)data; + struct sge_txq *q = &qs->txq[TXQ_OFLD]; + struct adapter *adap = qs->netdev->priv; + + spin_lock(&q->lock); + again:reclaim_completed_tx(adap, q); + + while ((skb = skb_peek(&q->sendq)) != NULL) { + unsigned int gen, pidx; + unsigned int ndesc = skb->priority; + + if (unlikely(q->size - q->in_use < ndesc)) { + set_bit(TXQ_OFLD, &qs->txq_stopped); + smp_mb__after_clear_bit(); + + if (should_restart_tx(q) && + test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) + goto again; + q->stops++; + break; + } + + gen = q->gen; + q->in_use += ndesc; + pidx = q->pidx; + q->pidx += ndesc; + if (q->pidx >= q->size) { + q->pidx -= q->size; + q->gen ^= 1; + } + __skb_unlink(skb, &q->sendq); + spin_unlock(&q->lock); + + write_ofld_wr(adap, skb, q, pidx, gen, ndesc); + spin_lock(&q->lock); + } + spin_unlock(&q->lock); + +#if USE_GTS + set_bit(TXQ_RUNNING, &q->flags); + set_bit(TXQ_LAST_PKT_DB, &q->flags); +#endif + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); +} + +/** + * queue_set - return the queue set a packet should use + * @skb: the packet + * + * Maps a packet to the SGE queue set it should use. The desired queue + * set is carried in bits 1-3 in the packet's priority. + */ +static inline int queue_set(const struct sk_buff *skb) +{ + return skb->priority >> 1; +} + +/** + * is_ctrl_pkt - return whether an offload packet is a control packet + * @skb: the packet + * + * Determines whether an offload packet should use an OFLD or a CTRL + * Tx queue. This is indicated by bit 0 in the packet's priority. + */ +static inline int is_ctrl_pkt(const struct sk_buff *skb) +{ + return skb->priority & 1; +} + +/** + * t3_offload_tx - send an offload packet + * @tdev: the offload device to send to + * @skb: the packet + * + * Sends an offload packet. We use the packet priority to select the + * appropriate Tx queue as follows: bit 0 indicates whether the packet + * should be sent as regular or control, bits 1-3 select the queue set. + */ +int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb) +{ + struct adapter *adap = tdev2adap(tdev); + struct sge_qset *qs = &adap->sge.qs[queue_set(skb)]; + + if (unlikely(is_ctrl_pkt(skb))) + return ctrl_xmit(adap, &qs->txq[TXQ_CTRL], skb); + + return ofld_xmit(adap, &qs->txq[TXQ_OFLD], skb); +} + +/** + * offload_enqueue - add an offload packet to an SGE offload receive queue + * @q: the SGE response queue + * @skb: the packet + * + * Add a new offload packet to an SGE response queue's offload packet + * queue. If the packet is the first on the queue it schedules the RX + * softirq to process the queue. + */ +static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb) +{ + skb->next = skb->prev = NULL; + if (q->rx_tail) + q->rx_tail->next = skb; + else { + struct sge_qset *qs = rspq_to_qset(q); + + if (__netif_rx_schedule_prep(qs->netdev)) + __netif_rx_schedule(qs->netdev); + q->rx_head = skb; + } + q->rx_tail = skb; +} + +/** + * deliver_partial_bundle - deliver a (partial) bundle of Rx offload pkts + * @tdev: the offload device that will be receiving the packets + * @q: the SGE response queue that assembled the bundle + * @skbs: the partial bundle + * @n: the number of packets in the bundle + * + * Delivers a (partial) bundle of Rx offload packets to an offload device. + */ +static inline void deliver_partial_bundle(struct t3cdev *tdev, + struct sge_rspq *q, + struct sk_buff *skbs[], int n) +{ + if (n) { + q->offload_bundles++; + tdev->recv(tdev, skbs, n); + } +} + +/** + * ofld_poll - NAPI handler for offload packets in interrupt mode + * @dev: the network device doing the polling + * @budget: polling budget + * + * The NAPI handler for offload packets when a response queue is serviced + * by the hard interrupt handler, i.e., when it's operating in non-polling + * mode. Creates small packet batches and sends them through the offload + * receive handler. Batches need to be of modest size as we do prefetches + * on the packets in each. + */ +static int ofld_poll(struct net_device *dev, int *budget) +{ + struct adapter *adapter = dev->priv; + struct sge_qset *qs = dev2qset(dev); + struct sge_rspq *q = &qs->rspq; + int work_done, limit = min(*budget, dev->quota), avail = limit; + + while (avail) { + struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE]; + int ngathered; + + spin_lock_irq(&q->lock); + head = q->rx_head; + if (!head) { + work_done = limit - avail; + *budget -= work_done; + dev->quota -= work_done; + __netif_rx_complete(dev); + spin_unlock_irq(&q->lock); + return 0; + } + + tail = q->rx_tail; + q->rx_head = q->rx_tail = NULL; + spin_unlock_irq(&q->lock); + + for (ngathered = 0; avail && head; avail--) { + prefetch(head->data); + skbs[ngathered] = head; + head = head->next; + skbs[ngathered]->next = NULL; + if (++ngathered == RX_BUNDLE_SIZE) { + q->offload_bundles++; + adapter->tdev.recv(&adapter->tdev, skbs, + ngathered); + ngathered = 0; + } + } + if (head) { /* splice remaining packets back onto Rx queue */ + spin_lock_irq(&q->lock); + tail->next = q->rx_head; + if (!q->rx_head) + q->rx_tail = tail; + q->rx_head = head; + spin_unlock_irq(&q->lock); + } + deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered); + } + work_done = limit - avail; + *budget -= work_done; + dev->quota -= work_done; + return 1; +} + +/** + * rx_offload - process a received offload packet + * @tdev: the offload device receiving the packet + * @rq: the response queue that received the packet + * @skb: the packet + * @rx_gather: a gather list of packets if we are building a bundle + * @gather_idx: index of the next available slot in the bundle + * + * Process an ingress offload pakcet and add it to the offload ingress + * queue. Returns the index of the next available slot in the bundle. + */ +static inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq, + struct sk_buff *skb, struct sk_buff *rx_gather[], + unsigned int gather_idx) +{ + rq->offload_pkts++; + skb->mac.raw = skb->nh.raw = skb->h.raw = skb->data; + + if (rq->polling) { + rx_gather[gather_idx++] = skb; + if (gather_idx == RX_BUNDLE_SIZE) { + tdev->recv(tdev, rx_gather, RX_BUNDLE_SIZE); + gather_idx = 0; + rq->offload_bundles++; + } + } else + offload_enqueue(rq, skb); + + return gather_idx; +} + +/** + * restart_tx - check whether to restart suspended Tx queues + * @qs: the queue set to resume + * + * Restarts suspended Tx queues of an SGE queue set if they have enough + * free resources to resume operation. + */ +static void restart_tx(struct sge_qset *qs) +{ + if (test_bit(TXQ_ETH, &qs->txq_stopped) && + should_restart_tx(&qs->txq[TXQ_ETH]) && + test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { + qs->txq[TXQ_ETH].restarts++; + if (netif_running(qs->netdev)) + netif_wake_queue(qs->netdev); + } + + if (test_bit(TXQ_OFLD, &qs->txq_stopped) && + should_restart_tx(&qs->txq[TXQ_OFLD]) && + test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) { + qs->txq[TXQ_OFLD].restarts++; + tasklet_schedule(&qs->txq[TXQ_OFLD].qresume_tsk); + } + if (test_bit(TXQ_CTRL, &qs->txq_stopped) && + should_restart_tx(&qs->txq[TXQ_CTRL]) && + test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) { + qs->txq[TXQ_CTRL].restarts++; + tasklet_schedule(&qs->txq[TXQ_CTRL].qresume_tsk); + } +} + +/** + * rx_eth - process an ingress ethernet packet + * @adap: the adapter + * @rq: the response queue that received the packet + * @skb: the packet + * @pad: amount of padding at the start of the buffer + * + * Process an ingress ethernet pakcet and deliver it to the stack. + * The padding is 2 if the packet was delivered in an Rx buffer and 0 + * if it was immediate data in a response. + */ +static void rx_eth(struct adapter *adap, struct sge_rspq *rq, + struct sk_buff *skb, int pad) +{ + struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad); + struct port_info *pi; + + rq->eth_pkts++; + skb_pull(skb, sizeof(*p) + pad); + skb->dev = adap->port[p->iff]; + skb->dev->last_rx = jiffies; + skb->protocol = eth_type_trans(skb, skb->dev); + pi = netdev_priv(skb->dev); + if (pi->rx_csum_offload && p->csum_valid && p->csum == 0xffff && + !p->fragment) { + rspq_to_qset(rq)->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else + skb->ip_summed = CHECKSUM_NONE; + + if (unlikely(p->vlan_valid)) { + struct vlan_group *grp = pi->vlan_grp; + + rspq_to_qset(rq)->port_stats[SGE_PSTAT_VLANEX]++; + if (likely(grp)) + __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan), + rq->polling); + else + dev_kfree_skb_any(skb); + } else if (rq->polling) + netif_receive_skb(skb); + else + netif_rx(skb); +} + +/** + * handle_rsp_cntrl_info - handles control information in a response + * @qs: the queue set corresponding to the response + * @flags: the response control flags + * + * Handles the control information of an SGE response, such as GTS + * indications and completion credits for the queue set's Tx queues. + * HW coalesces credits, we don't do any extra SW coalescing. + */ +static inline void handle_rsp_cntrl_info(struct sge_qset *qs, u32 flags) +{ + unsigned int credits; + +#if USE_GTS + if (flags & F_RSPD_TXQ0_GTS) + clear_bit(TXQ_RUNNING, &qs->txq[TXQ_ETH].flags); +#endif + + credits = G_RSPD_TXQ0_CR(flags); + if (credits) + qs->txq[TXQ_ETH].processed += credits; + + credits = G_RSPD_TXQ2_CR(flags); + if (credits) + qs->txq[TXQ_CTRL].processed += credits; + +# if USE_GTS + if (flags & F_RSPD_TXQ1_GTS) + clear_bit(TXQ_RUNNING, &qs->txq[TXQ_OFLD].flags); +# endif + credits = G_RSPD_TXQ1_CR(flags); + if (credits) + qs->txq[TXQ_OFLD].processed += credits; +} + +/** + * check_ring_db - check if we need to ring any doorbells + * @adapter: the adapter + * @qs: the queue set whose Tx queues are to be examined + * @sleeping: indicates which Tx queue sent GTS + * + * Checks if some of a queue set's Tx queues need to ring their doorbells + * to resume transmission after idling while they still have unprocessed + * descriptors. + */ +static void check_ring_db(struct adapter *adap, struct sge_qset *qs, + unsigned int sleeping) +{ + if (sleeping & F_RSPD_TXQ0_GTS) { + struct sge_txq *txq = &qs->txq[TXQ_ETH]; + + if (txq->cleaned + txq->in_use != txq->processed && + !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) { + set_bit(TXQ_RUNNING, &txq->flags); + t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | + V_EGRCNTX(txq->cntxt_id)); + } + } + + if (sleeping & F_RSPD_TXQ1_GTS) { + struct sge_txq *txq = &qs->txq[TXQ_OFLD]; + + if (txq->cleaned + txq->in_use != txq->processed && + !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) { + set_bit(TXQ_RUNNING, &txq->flags); + t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | + V_EGRCNTX(txq->cntxt_id)); + } + } +} + +/** + * is_new_response - check if a response is newly written + * @r: the response descriptor + * @q: the response queue + * + * Returns true if a response descriptor contains a yet unprocessed + * response. + */ +static inline int is_new_response(const struct rsp_desc *r, + const struct sge_rspq *q) +{ + return (r->intr_gen & F_RSPD_GEN2) == q->gen; +} + +#define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS) +#define RSPD_CTRL_MASK (RSPD_GTS_MASK | \ + V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \ + V_RSPD_TXQ1_CR(M_RSPD_TXQ1_CR) | \ + V_RSPD_TXQ2_CR(M_RSPD_TXQ2_CR)) + +/* How long to delay the next interrupt in case of memory shortage, in 0.1us. */ +#define NOMEM_INTR_DELAY 2500 + +/** + * process_responses - process responses from an SGE response queue + * @adap: the adapter + * @qs: the queue set to which the response queue belongs + * @budget: how many responses can be processed in this round + * + * Process responses from an SGE response queue up to the supplied budget. + * Responses include received packets as well as credits and other events + * for the queues that belong to the response queue's queue set. + * A negative budget is effectively unlimited. + * + * Additionally choose the interrupt holdoff time for the next interrupt + * on this queue. If the system is under memory shortage use a fairly + * long delay to help recovery. + */ +static int process_responses(struct adapter *adap, struct sge_qset *qs, + int budget) +{ + struct sge_rspq *q = &qs->rspq; + struct rsp_desc *r = &q->desc[q->cidx]; + int budget_left = budget; + unsigned int sleeping = 0; + struct sk_buff *offload_skbs[RX_BUNDLE_SIZE]; + int ngathered = 0; + + q->next_holdoff = q->holdoff_tmr; + + while (likely(budget_left && is_new_response(r, q))) { + int eth, ethpad = 0; + struct sk_buff *skb = NULL; + u32 len, flags = ntohl(r->flags); + u32 rss_hi = *(const u32 *)r, rss_lo = r->rss_hdr.rss_hash_val; + + eth = r->rss_hdr.opcode == CPL_RX_PKT; + + if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) { + skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC); + if (!skb) + goto no_mem; + + memcpy(__skb_put(skb, AN_PKT_SIZE), r, AN_PKT_SIZE); + skb->data[0] = CPL_ASYNC_NOTIF; + rss_hi = htonl(CPL_ASYNC_NOTIF << 24); + q->async_notif++; + } else if (flags & F_RSPD_IMM_DATA_VALID) { + skb = get_imm_packet(r); + if (unlikely(!skb)) { + no_mem: + q->next_holdoff = NOMEM_INTR_DELAY; + q->nomem++; + /* consume one credit since we tried */ + budget_left--; + break; + } + q->imm_data++; + } else if ((len = ntohl(r->len_cq)) != 0) { + struct sge_fl *fl; + + fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0]; + fl->credits--; + skb = get_packet(adap, fl, G_RSPD_LEN(len), + eth ? SGE_RX_DROP_THRES : 0); + if (!skb) + q->rx_drops++; + else if (r->rss_hdr.opcode == CPL_TRACE_PKT) + __skb_pull(skb, 2); + ethpad = 2; + if (++fl->cidx == fl->size) + fl->cidx = 0; + } else + q->pure_rsps++; + + if (flags & RSPD_CTRL_MASK) { + sleeping |= flags & RSPD_GTS_MASK; + handle_rsp_cntrl_info(qs, flags); + } + + r++; + if (unlikely(++q->cidx == q->size)) { + q->cidx = 0; + q->gen ^= 1; + r = q->desc; + } + prefetch(r); + + if (++q->credits >= (q->size / 4)) { + refill_rspq(adap, q, q->credits); + q->credits = 0; + } + + if (likely(skb != NULL)) { + if (eth) + rx_eth(adap, q, skb, ethpad); + else { + /* Preserve the RSS info in csum & priority */ + skb->csum = rss_hi; + skb->priority = rss_lo; + ngathered = rx_offload(&adap->tdev, q, skb, + offload_skbs, ngathered); + } + } + + --budget_left; + } + + deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered); + if (sleeping) + check_ring_db(adap, qs, sleeping); + + smp_mb(); /* commit Tx queue .processed updates */ + if (unlikely(qs->txq_stopped != 0)) + restart_tx(qs); + + budget -= budget_left; + return budget; +} + +static inline int is_pure_response(const struct rsp_desc *r) +{ + u32 n = ntohl(r->flags) & (F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID); + + return (n | r->len_cq) == 0; +} + +/** + * napi_rx_handler - the NAPI handler for Rx processing + * @dev: the net device + * @budget: how many packets we can process in this round + * + * Handler for new data events when using NAPI. + */ +static int napi_rx_handler(struct net_device *dev, int *budget) +{ + struct adapter *adap = dev->priv; + struct sge_qset *qs = dev2qset(dev); + int effective_budget = min(*budget, dev->quota); + + int work_done = process_responses(adap, qs, effective_budget); + *budget -= work_done; + dev->quota -= work_done; + + if (work_done >= effective_budget) + return 1; + + netif_rx_complete(dev); + + /* + * Because we don't atomically flush the following write it is + * possible that in very rare cases it can reach the device in a way + * that races with a new response being written plus an error interrupt + * causing the NAPI interrupt handler below to return unhandled status + * to the OS. To protect against this would require flushing the write + * and doing both the write and the flush with interrupts off. Way too + * expensive and unjustifiable given the rarity of the race. + * + * The race cannot happen at all with MSI-X. + */ + t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) | + V_NEWTIMER(qs->rspq.next_holdoff) | + V_NEWINDEX(qs->rspq.cidx)); + return 0; +} + +/* + * Returns true if the device is already scheduled for polling. + */ +static inline int napi_is_scheduled(struct net_device *dev) +{ + return test_bit(__LINK_STATE_RX_SCHED, &dev->state); +} + +/** + * process_pure_responses - process pure responses from a response queue + * @adap: the adapter + * @qs: the queue set owning the response queue + * @r: the first pure response to process + * + * A simpler version of process_responses() that handles only pure (i.e., + * non data-carrying) responses. Such respones are too light-weight to + * justify calling a softirq under NAPI, so we handle them specially in + * the interrupt handler. The function is called with a pointer to a + * response, which the caller must ensure is a valid pure response. + * + * Returns 1 if it encounters a valid data-carrying response, 0 otherwise. + */ +static int process_pure_responses(struct adapter *adap, struct sge_qset *qs, + struct rsp_desc *r) +{ + struct sge_rspq *q = &qs->rspq; + unsigned int sleeping = 0; + + do { + u32 flags = ntohl(r->flags); + + r++; + if (unlikely(++q->cidx == q->size)) { + q->cidx = 0; + q->gen ^= 1; + r = q->desc; + } + prefetch(r); + + if (flags & RSPD_CTRL_MASK) { + sleeping |= flags & RSPD_GTS_MASK; + handle_rsp_cntrl_info(qs, flags); + } + + q->pure_rsps++; + if (++q->credits >= (q->size / 4)) { + refill_rspq(adap, q, q->credits); + q->credits = 0; + } + } while (is_new_response(r, q) && is_pure_response(r)); + + if (sleeping) + check_ring_db(adap, qs, sleeping); + + smp_mb(); /* commit Tx queue .processed updates */ + if (unlikely(qs->txq_stopped != 0)) + restart_tx(qs); + + return is_new_response(r, q); +} + +/** + * handle_responses - decide what to do with new responses in NAPI mode + * @adap: the adapter + * @q: the response queue + * + * This is used by the NAPI interrupt handlers to decide what to do with + * new SGE responses. If there are no new responses it returns -1. If + * there are new responses and they are pure (i.e., non-data carrying) + * it handles them straight in hard interrupt context as they are very + * cheap and don't deliver any packets. Finally, if there are any data + * signaling responses it schedules the NAPI handler. Returns 1 if it + * schedules NAPI, 0 if all new responses were pure. + * + * The caller must ascertain NAPI is not already running. + */ +static inline int handle_responses(struct adapter *adap, struct sge_rspq *q) +{ + struct sge_qset *qs = rspq_to_qset(q); + struct rsp_desc *r = &q->desc[q->cidx]; + + if (!is_new_response(r, q)) + return -1; + if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) { + t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | + V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx)); + return 0; + } + if (likely(__netif_rx_schedule_prep(qs->netdev))) + __netif_rx_schedule(qs->netdev); + return 1; +} + +/* + * The MSI-X interrupt handler for an SGE response queue for the non-NAPI case + * (i.e., response queue serviced in hard interrupt). + */ +irqreturn_t t3_sge_intr_msix(int irq, void *cookie) +{ + struct sge_qset *qs = cookie; + struct adapter *adap = qs->netdev->priv; + struct sge_rspq *q = &qs->rspq; + + spin_lock(&q->lock); + if (process_responses(adap, qs, -1) == 0) + q->unhandled_irqs++; + t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | + V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx)); + spin_unlock(&q->lock); + return IRQ_HANDLED; +} + +/* + * The MSI-X interrupt handler for an SGE response queue for the NAPI case + * (i.e., response queue serviced by NAPI polling). + */ +irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie) +{ + struct sge_qset *qs = cookie; + struct adapter *adap = qs->netdev->priv; + struct sge_rspq *q = &qs->rspq; + + spin_lock(&q->lock); + BUG_ON(napi_is_scheduled(qs->netdev)); + + if (handle_responses(adap, q) < 0) + q->unhandled_irqs++; + spin_unlock(&q->lock); + return IRQ_HANDLED; +} + +/* + * The non-NAPI MSI interrupt handler. This needs to handle data events from + * SGE response queues as well as error and other async events as they all use + * the same MSI vector. We use one SGE response queue per port in this mode + * and protect all response queues with queue 0's lock. + */ +static irqreturn_t t3_intr_msi(int irq, void *cookie) +{ + int new_packets = 0; + struct adapter *adap = cookie; + struct sge_rspq *q = &adap->sge.qs[0].rspq; + + spin_lock(&q->lock); + + if (process_responses(adap, &adap->sge.qs[0], -1)) { + t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) | + V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx)); + new_packets = 1; + } + + if (adap->params.nports == 2 && + process_responses(adap, &adap->sge.qs[1], -1)) { + struct sge_rspq *q1 = &adap->sge.qs[1].rspq; + + t3_write_reg(adap, A_SG_GTS, V_RSPQ(q1->cntxt_id) | + V_NEWTIMER(q1->next_holdoff) | + V_NEWINDEX(q1->cidx)); + new_packets = 1; + } + + if (!new_packets && t3_slow_intr_handler(adap) == 0) + q->unhandled_irqs++; + + spin_unlock(&q->lock); + return IRQ_HANDLED; +} + +static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q) +{ + if (!napi_is_scheduled(dev) && is_new_response(&q->desc[q->cidx], q)) { + if (likely(__netif_rx_schedule_prep(dev))) + __netif_rx_schedule(dev); + return 1; + } + return 0; +} + +/* + * The MSI interrupt handler for the NAPI case (i.e., response queues serviced + * by NAPI polling). Handles data events from SGE response queues as well as + * error and other async events as they all use the same MSI vector. We use + * one SGE response queue per port in this mode and protect all response + * queues with queue 0's lock. + */ +irqreturn_t t3_intr_msi_napi(int irq, void *cookie) +{ + int new_packets; + struct adapter *adap = cookie; + struct sge_rspq *q = &adap->sge.qs[0].rspq; + + spin_lock(&q->lock); + + new_packets = rspq_check_napi(adap->sge.qs[0].netdev, q); + if (adap->params.nports == 2) + new_packets += rspq_check_napi(adap->sge.qs[1].netdev, + &adap->sge.qs[1].rspq); + if (!new_packets && t3_slow_intr_handler(adap) == 0) + q->unhandled_irqs++; + + spin_unlock(&q->lock); + return IRQ_HANDLED; +} + +/* + * A helper function that processes responses and issues GTS. + */ +static inline int process_responses_gts(struct adapter *adap, + struct sge_rspq *rq) +{ + int work; + + work = process_responses(adap, rspq_to_qset(rq), -1); + t3_write_reg(adap, A_SG_GTS, V_RSPQ(rq->cntxt_id) | + V_NEWTIMER(rq->next_holdoff) | V_NEWINDEX(rq->cidx)); + return work; +} + +/* + * The legacy INTx interrupt handler. This needs to handle data events from + * SGE response queues as well as error and other async events as they all use + * the same interrupt pin. We use one SGE response queue per port in this mode + * and protect all response queues with queue 0's lock. + */ +static irqreturn_t t3_intr(int irq, void *cookie) +{ + int work_done, w0, w1; + struct adapter *adap = cookie; + struct sge_rspq *q0 = &adap->sge.qs[0].rspq; + struct sge_rspq *q1 = &adap->sge.qs[1].rspq; + + spin_lock(&q0->lock); + + w0 = is_new_response(&q0->desc[q0->cidx], q0); + w1 = adap->params.nports == 2 && + is_new_response(&q1->desc[q1->cidx], q1); + + if (likely(w0 | w1)) { + t3_write_reg(adap, A_PL_CLI, 0); + t3_read_reg(adap, A_PL_CLI); /* flush */ + + if (likely(w0)) + process_responses_gts(adap, q0); + + if (w1) + process_responses_gts(adap, q1); + + work_done = w0 | w1; + } else + work_done = t3_slow_intr_handler(adap); + + spin_unlock(&q0->lock); + return IRQ_RETVAL(work_done != 0); +} + +/* + * Interrupt handler for legacy INTx interrupts for T3B-based cards. + * Handles data events from SGE response queues as well as error and other + * async events as they all use the same interrupt pin. We use one SGE + * response queue per port in this mode and protect all response queues with + * queue 0's lock. + */ +static irqreturn_t t3b_intr(int irq, void *cookie) +{ + u32 map; + struct adapter *adap = cookie; + struct sge_rspq *q0 = &adap->sge.qs[0].rspq; + + t3_write_reg(adap, A_PL_CLI, 0); + map = t3_read_reg(adap, A_SG_DATA_INTR); + + if (unlikely(!map)) /* shared interrupt, most likely */ + return IRQ_NONE; + + spin_lock(&q0->lock); + + if (unlikely(map & F_ERRINTR)) + t3_slow_intr_handler(adap); + + if (likely(map & 1)) + process_responses_gts(adap, q0); + + if (map & 2) + process_responses_gts(adap, &adap->sge.qs[1].rspq); + + spin_unlock(&q0->lock); + return IRQ_HANDLED; +} + +/* + * NAPI interrupt handler for legacy INTx interrupts for T3B-based cards. + * Handles data events from SGE response queues as well as error and other + * async events as they all use the same interrupt pin. We use one SGE + * response queue per port in this mode and protect all response queues with + * queue 0's lock. + */ +static irqreturn_t t3b_intr_napi(int irq, void *cookie) +{ + u32 map; + struct net_device *dev; + struct adapter *adap = cookie; + struct sge_rspq *q0 = &adap->sge.qs[0].rspq; + + t3_write_reg(adap, A_PL_CLI, 0); + map = t3_read_reg(adap, A_SG_DATA_INTR); + + if (unlikely(!map)) /* shared interrupt, most likely */ + return IRQ_NONE; + + spin_lock(&q0->lock); + + if (unlikely(map & F_ERRINTR)) + t3_slow_intr_handler(adap); + + if (likely(map & 1)) { + dev = adap->sge.qs[0].netdev; + + if (likely(__netif_rx_schedule_prep(dev))) + __netif_rx_schedule(dev); + } + if (map & 2) { + dev = adap->sge.qs[1].netdev; + + if (likely(__netif_rx_schedule_prep(dev))) + __netif_rx_schedule(dev); + } + + spin_unlock(&q0->lock); + return IRQ_HANDLED; +} + +/** + * t3_intr_handler - select the top-level interrupt handler + * @adap: the adapter + * @polling: whether using NAPI to service response queues + * + * Selects the top-level interrupt handler based on the type of interrupts + * (MSI-X, MSI, or legacy) and whether NAPI will be used to service the + * response queues. + */ +intr_handler_t t3_intr_handler(struct adapter *adap, int polling) +{ + if (adap->flags & USING_MSIX) + return polling ? t3_sge_intr_msix_napi : t3_sge_intr_msix; + if (adap->flags & USING_MSI) + return polling ? t3_intr_msi_napi : t3_intr_msi; + if (adap->params.rev > 0) + return polling ? t3b_intr_napi : t3b_intr; + return t3_intr; +} + +/** + * t3_sge_err_intr_handler - SGE async event interrupt handler + * @adapter: the adapter + * + * Interrupt handler for SGE asynchronous (non-data) events. + */ +void t3_sge_err_intr_handler(struct adapter *adapter) +{ + unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE); + + if (status & F_RSPQCREDITOVERFOW) + CH_ALERT(adapter, "SGE response queue credit overflow\n"); + + if (status & F_RSPQDISABLED) { + v = t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS); + + CH_ALERT(adapter, + "packet delivered to disabled response queue " + "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff); + } + + t3_write_reg(adapter, A_SG_INT_CAUSE, status); + if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED)) + t3_fatal_err(adapter); +} + +/** + * sge_timer_cb - perform periodic maintenance of an SGE qset + * @data: the SGE queue set to maintain + * + * Runs periodically from a timer to perform maintenance of an SGE queue + * set. It performs two tasks: + * + * a) Cleans up any completed Tx descriptors that may still be pending. + * Normal descriptor cleanup happens when new packets are added to a Tx + * queue so this timer is relatively infrequent and does any cleanup only + * if the Tx queue has not seen any new packets in a while. We make a + * best effort attempt to reclaim descriptors, in that we don't wait + * around if we cannot get a queue's lock (which most likely is because + * someone else is queueing new packets and so will also handle the clean + * up). Since control queues use immediate data exclusively we don't + * bother cleaning them up here. + * + * b) Replenishes Rx queues that have run out due to memory shortage. + * Normally new Rx buffers are added when existing ones are consumed but + * when out of memory a queue can become empty. We try to add only a few + * buffers here, the queue will be replenished fully as these new buffers + * are used up if memory shortage has subsided. + */ +static void sge_timer_cb(unsigned long data) +{ + spinlock_t *lock; + struct sge_qset *qs = (struct sge_qset *)data; + struct adapter *adap = qs->netdev->priv; + + if (spin_trylock(&qs->txq[TXQ_ETH].lock)) { + reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]); + spin_unlock(&qs->txq[TXQ_ETH].lock); + } + if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) { + reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD]); + spin_unlock(&qs->txq[TXQ_OFLD].lock); + } + lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock : + &adap->sge.qs[0].rspq.lock; + if (spin_trylock_irq(lock)) { + if (!napi_is_scheduled(qs->netdev)) { + if (qs->fl[0].credits < qs->fl[0].size) + __refill_fl(adap, &qs->fl[0]); + if (qs->fl[1].credits < qs->fl[1].size) + __refill_fl(adap, &qs->fl[1]); + } + spin_unlock_irq(lock); + } + mod_timer(&qs->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); +} + +/** + * t3_update_qset_coalesce - update coalescing settings for a queue set + * @qs: the SGE queue set + * @p: new queue set parameters + * + * Update the coalescing settings for an SGE queue set. Nothing is done + * if the queue set is not initialized yet. + */ +void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p) +{ + if (!qs->netdev) + return; + + qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */ + qs->rspq.polling = p->polling; + qs->netdev->poll = p->polling ? napi_rx_handler : ofld_poll; +} + +/** + * t3_sge_alloc_qset - initialize an SGE queue set + * @adapter: the adapter + * @id: the queue set id + * @nports: how many Ethernet ports will be using this queue set + * @irq_vec_idx: the IRQ vector index for response queue interrupts + * @p: configuration parameters for this queue set + * @ntxq: number of Tx queues for the queue set + * @netdev: net device associated with this queue set + * + * Allocate resources and initialize an SGE queue set. A queue set + * comprises a response queue, two Rx free-buffer queues, and up to 3 + * Tx queues. The Tx queues are assigned roles in the order Ethernet + * queue, offload queue, and control queue. + */ +int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, + int irq_vec_idx, const struct qset_params *p, + int ntxq, struct net_device *netdev) +{ + int i, ret = -ENOMEM; + struct sge_qset *q = &adapter->sge.qs[id]; + + init_qset_cntxt(q, id); + init_timer(&q->tx_reclaim_timer); + q->tx_reclaim_timer.data = (unsigned long)q; + q->tx_reclaim_timer.function = sge_timer_cb; + + q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size, + sizeof(struct rx_desc), + sizeof(struct rx_sw_desc), + &q->fl[0].phys_addr, &q->fl[0].sdesc); + if (!q->fl[0].desc) + goto err; + + q->fl[1].desc = alloc_ring(adapter->pdev, p->jumbo_size, + sizeof(struct rx_desc), + sizeof(struct rx_sw_desc), + &q->fl[1].phys_addr, &q->fl[1].sdesc); + if (!q->fl[1].desc) + goto err; + + q->rspq.desc = alloc_ring(adapter->pdev, p->rspq_size, + sizeof(struct rsp_desc), 0, + &q->rspq.phys_addr, NULL); + if (!q->rspq.desc) + goto err; + + for (i = 0; i < ntxq; ++i) { + /* + * The control queue always uses immediate data so does not + * need to keep track of any sk_buffs. + */ + size_t sz = i == TXQ_CTRL ? 0 : sizeof(struct tx_sw_desc); + + q->txq[i].desc = alloc_ring(adapter->pdev, p->txq_size[i], + sizeof(struct tx_desc), sz, + &q->txq[i].phys_addr, + &q->txq[i].sdesc); + if (!q->txq[i].desc) + goto err; + + q->txq[i].gen = 1; + q->txq[i].size = p->txq_size[i]; + spin_lock_init(&q->txq[i].lock); + skb_queue_head_init(&q->txq[i].sendq); + } + + tasklet_init(&q->txq[TXQ_OFLD].qresume_tsk, restart_offloadq, + (unsigned long)q); + tasklet_init(&q->txq[TXQ_CTRL].qresume_tsk, restart_ctrlq, + (unsigned long)q); + + q->fl[0].gen = q->fl[1].gen = 1; + q->fl[0].size = p->fl_size; + q->fl[1].size = p->jumbo_size; + + q->rspq.gen = 1; + q->rspq.size = p->rspq_size; + spin_lock_init(&q->rspq.lock); + + q->txq[TXQ_ETH].stop_thres = nports * + flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3); + + if (ntxq == 1) { + q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + 2 + + sizeof(struct cpl_rx_pkt); + q->fl[1].buf_size = MAX_FRAME_SIZE + 2 + + sizeof(struct cpl_rx_pkt); + } else { + q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + + sizeof(struct cpl_rx_data); + q->fl[1].buf_size = (16 * 1024) - + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + } + + spin_lock(&adapter->sge.reg_lock); + + /* FL threshold comparison uses < */ + ret = t3_sge_init_rspcntxt(adapter, q->rspq.cntxt_id, irq_vec_idx, + q->rspq.phys_addr, q->rspq.size, + q->fl[0].buf_size, 1, 0); + if (ret) + goto err_unlock; + + for (i = 0; i < SGE_RXQ_PER_SET; ++i) { + ret = t3_sge_init_flcntxt(adapter, q->fl[i].cntxt_id, 0, + q->fl[i].phys_addr, q->fl[i].size, + q->fl[i].buf_size, p->cong_thres, 1, + 0); + if (ret) + goto err_unlock; + } + + ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_ETH].cntxt_id, USE_GTS, + SGE_CNTXT_ETH, id, q->txq[TXQ_ETH].phys_addr, + q->txq[TXQ_ETH].size, q->txq[TXQ_ETH].token, + 1, 0); + if (ret) + goto err_unlock; + + if (ntxq > 1) { + ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_OFLD].cntxt_id, + USE_GTS, SGE_CNTXT_OFLD, id, + q->txq[TXQ_OFLD].phys_addr, + q->txq[TXQ_OFLD].size, 0, 1, 0); + if (ret) + goto err_unlock; + } + + if (ntxq > 2) { + ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_CTRL].cntxt_id, 0, + SGE_CNTXT_CTRL, id, + q->txq[TXQ_CTRL].phys_addr, + q->txq[TXQ_CTRL].size, + q->txq[TXQ_CTRL].token, 1, 0); + if (ret) + goto err_unlock; + } + + spin_unlock(&adapter->sge.reg_lock); + q->netdev = netdev; + t3_update_qset_coalesce(q, p); + + /* + * We use atalk_ptr as a backpointer to a qset. In case a device is + * associated with multiple queue sets only the first one sets + * atalk_ptr. + */ + if (netdev->atalk_ptr == NULL) + netdev->atalk_ptr = q; + + refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL); + refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL); + refill_rspq(adapter, &q->rspq, q->rspq.size - 1); + + t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) | + V_NEWTIMER(q->rspq.holdoff_tmr)); + + mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD); + return 0; + + err_unlock: + spin_unlock(&adapter->sge.reg_lock); + err: + t3_free_qset(adapter, q); + return ret; +} + +/** + * t3_free_sge_resources - free SGE resources + * @adap: the adapter + * + * Frees resources used by the SGE queue sets. + */ +void t3_free_sge_resources(struct adapter *adap) +{ + int i; + + for (i = 0; i < SGE_QSETS; ++i) + t3_free_qset(adap, &adap->sge.qs[i]); +} + +/** + * t3_sge_start - enable SGE + * @adap: the adapter + * + * Enables the SGE for DMAs. This is the last step in starting packet + * transfers. + */ +void t3_sge_start(struct adapter *adap) +{ + t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, F_GLOBALENABLE); +} + +/** + * t3_sge_stop - disable SGE operation + * @adap: the adapter + * + * Disables the DMA engine. This can be called in emeregencies (e.g., + * from error interrupts) or from normal process context. In the latter + * case it also disables any pending queue restart tasklets. Note that + * if it is called in interrupt context it cannot disable the restart + * tasklets as it cannot wait, however the tasklets will have no effect + * since the doorbells are disabled and the driver will call this again + * later from process context, at which time the tasklets will be stopped + * if they are still running. + */ +void t3_sge_stop(struct adapter *adap) +{ + t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, 0); + if (!in_interrupt()) { + int i; + + for (i = 0; i < SGE_QSETS; ++i) { + struct sge_qset *qs = &adap->sge.qs[i]; + + tasklet_kill(&qs->txq[TXQ_OFLD].qresume_tsk); + tasklet_kill(&qs->txq[TXQ_CTRL].qresume_tsk); + } + } +} + +/** + * t3_sge_init - initialize SGE + * @adap: the adapter + * @p: the SGE parameters + * + * Performs SGE initialization needed every time after a chip reset. + * We do not initialize any of the queue sets here, instead the driver + * top-level must request those individually. We also do not enable DMA + * here, that should be done after the queues have been set up. + */ +void t3_sge_init(struct adapter *adap, struct sge_params *p) +{ + unsigned int ctrl, ups = ffs(pci_resource_len(adap->pdev, 2) >> 12); + + ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL | + F_CQCRDTCTRL | + V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS | + V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING; +#if SGE_NUM_GENBITS == 1 + ctrl |= F_EGRGENCTRL; +#endif + if (adap->params.rev > 0) { + if (!(adap->flags & (USING_MSIX | USING_MSI))) + ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ; + ctrl |= F_CQCRDTCTRL | F_AVOIDCQOVFL; + } + t3_write_reg(adap, A_SG_CONTROL, ctrl); + t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) | + V_LORCQDRBTHRSH(512)); + t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10); + t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) | + V_TIMEOUT(200 * core_ticks_per_usec(adap))); + t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, 1000); + t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256); + t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000); + t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256); + t3_write_reg(adap, A_SG_OCO_BASE, V_BASE1(0xfff)); + t3_write_reg(adap, A_SG_DRB_PRI_THRESH, 63 * 1024); +} + +/** + * t3_sge_prep - one-time SGE initialization + * @adap: the associated adapter + * @p: SGE parameters + * + * Performs one-time initialization of SGE SW state. Includes determining + * defaults for the assorted SGE parameters, which admins can change until + * they are used to initialize the SGE. + */ +void __devinit t3_sge_prep(struct adapter *adap, struct sge_params *p) +{ + int i; + + p->max_pkt_size = (16 * 1024) - sizeof(struct cpl_rx_data) - + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + + for (i = 0; i < SGE_QSETS; ++i) { + struct qset_params *q = p->qset + i; + + q->polling = adap->params.rev > 0; + q->coalesce_usecs = 5; + q->rspq_size = 1024; + q->fl_size = 4096; + q->jumbo_size = 512; + q->txq_size[TXQ_ETH] = 1024; + q->txq_size[TXQ_OFLD] = 1024; + q->txq_size[TXQ_CTRL] = 256; + q->cong_thres = 0; + } + + spin_lock_init(&adap->sge.reg_lock); +} + +/** + * t3_get_desc - dump an SGE descriptor for debugging purposes + * @qs: the queue set + * @qnum: identifies the specific queue (0..2: Tx, 3:response, 4..5: Rx) + * @idx: the descriptor index in the queue + * @data: where to dump the descriptor contents + * + * Dumps the contents of a HW descriptor of an SGE queue. Returns the + * size of the descriptor. + */ +int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx, + unsigned char *data) +{ + if (qnum >= 6) + return -EINVAL; + + if (qnum < 3) { + if (!qs->txq[qnum].desc || idx >= qs->txq[qnum].size) + return -EINVAL; + memcpy(data, &qs->txq[qnum].desc[idx], sizeof(struct tx_desc)); + return sizeof(struct tx_desc); + } + + if (qnum == 3) { + if (!qs->rspq.desc || idx >= qs->rspq.size) + return -EINVAL; + memcpy(data, &qs->rspq.desc[idx], sizeof(struct rsp_desc)); + return sizeof(struct rsp_desc); + } + + qnum -= 4; + if (!qs->fl[qnum].desc || idx >= qs->fl[qnum].size) + return -EINVAL; + memcpy(data, &qs->fl[qnum].desc[idx], sizeof(struct rx_desc)); + return sizeof(struct rx_desc); +} diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/cxgb3/sge_defs.h new file mode 100644 index 000000000000..514869e26a76 --- /dev/null +++ b/drivers/net/cxgb3/sge_defs.h @@ -0,0 +1,251 @@ +/* + * This file is automatically generated --- any changes will be lost. + */ + +#ifndef _SGE_DEFS_H +#define _SGE_DEFS_H + +#define S_EC_CREDITS 0 +#define M_EC_CREDITS 0x7FFF +#define V_EC_CREDITS(x) ((x) << S_EC_CREDITS) +#define G_EC_CREDITS(x) (((x) >> S_EC_CREDITS) & M_EC_CREDITS) + +#define S_EC_GTS 15 +#define V_EC_GTS(x) ((x) << S_EC_GTS) +#define F_EC_GTS V_EC_GTS(1U) + +#define S_EC_INDEX 16 +#define M_EC_INDEX 0xFFFF +#define V_EC_INDEX(x) ((x) << S_EC_INDEX) +#define G_EC_INDEX(x) (((x) >> S_EC_INDEX) & M_EC_INDEX) + +#define S_EC_SIZE 0 +#define M_EC_SIZE 0xFFFF +#define V_EC_SIZE(x) ((x) << S_EC_SIZE) +#define G_EC_SIZE(x) (((x) >> S_EC_SIZE) & M_EC_SIZE) + +#define S_EC_BASE_LO 16 +#define M_EC_BASE_LO 0xFFFF +#define V_EC_BASE_LO(x) ((x) << S_EC_BASE_LO) +#define G_EC_BASE_LO(x) (((x) >> S_EC_BASE_LO) & M_EC_BASE_LO) + +#define S_EC_BASE_HI 0 +#define M_EC_BASE_HI 0xF +#define V_EC_BASE_HI(x) ((x) << S_EC_BASE_HI) +#define G_EC_BASE_HI(x) (((x) >> S_EC_BASE_HI) & M_EC_BASE_HI) + +#define S_EC_RESPQ 4 +#define M_EC_RESPQ 0x7 +#define V_EC_RESPQ(x) ((x) << S_EC_RESPQ) +#define G_EC_RESPQ(x) (((x) >> S_EC_RESPQ) & M_EC_RESPQ) + +#define S_EC_TYPE 7 +#define M_EC_TYPE 0x7 +#define V_EC_TYPE(x) ((x) << S_EC_TYPE) +#define G_EC_TYPE(x) (((x) >> S_EC_TYPE) & M_EC_TYPE) + +#define S_EC_GEN 10 +#define V_EC_GEN(x) ((x) << S_EC_GEN) +#define F_EC_GEN V_EC_GEN(1U) + +#define S_EC_UP_TOKEN 11 +#define M_EC_UP_TOKEN 0xFFFFF +#define V_EC_UP_TOKEN(x) ((x) << S_EC_UP_TOKEN) +#define G_EC_UP_TOKEN(x) (((x) >> S_EC_UP_TOKEN) & M_EC_UP_TOKEN) + +#define S_EC_VALID 31 +#define V_EC_VALID(x) ((x) << S_EC_VALID) +#define F_EC_VALID V_EC_VALID(1U) + +#define S_RQ_MSI_VEC 20 +#define M_RQ_MSI_VEC 0x3F +#define V_RQ_MSI_VEC(x) ((x) << S_RQ_MSI_VEC) +#define G_RQ_MSI_VEC(x) (((x) >> S_RQ_MSI_VEC) & M_RQ_MSI_VEC) + +#define S_RQ_INTR_EN 26 +#define V_RQ_INTR_EN(x) ((x) << S_RQ_INTR_EN) +#define F_RQ_INTR_EN V_RQ_INTR_EN(1U) + +#define S_RQ_GEN 28 +#define V_RQ_GEN(x) ((x) << S_RQ_GEN) +#define F_RQ_GEN V_RQ_GEN(1U) + +#define S_CQ_INDEX 0 +#define M_CQ_INDEX 0xFFFF +#define V_CQ_INDEX(x) ((x) << S_CQ_INDEX) +#define G_CQ_INDEX(x) (((x) >> S_CQ_INDEX) & M_CQ_INDEX) + +#define S_CQ_SIZE 16 +#define M_CQ_SIZE 0xFFFF +#define V_CQ_SIZE(x) ((x) << S_CQ_SIZE) +#define G_CQ_SIZE(x) (((x) >> S_CQ_SIZE) & M_CQ_SIZE) + +#define S_CQ_BASE_HI 0 +#define M_CQ_BASE_HI 0xFFFFF +#define V_CQ_BASE_HI(x) ((x) << S_CQ_BASE_HI) +#define G_CQ_BASE_HI(x) (((x) >> S_CQ_BASE_HI) & M_CQ_BASE_HI) + +#define S_CQ_RSPQ 20 +#define M_CQ_RSPQ 0x3F +#define V_CQ_RSPQ(x) ((x) << S_CQ_RSPQ) +#define G_CQ_RSPQ(x) (((x) >> S_CQ_RSPQ) & M_CQ_RSPQ) + +#define S_CQ_ASYNC_NOTIF 26 +#define V_CQ_ASYNC_NOTIF(x) ((x) << S_CQ_ASYNC_NOTIF) +#define F_CQ_ASYNC_NOTIF V_CQ_ASYNC_NOTIF(1U) + +#define S_CQ_ARMED 27 +#define V_CQ_ARMED(x) ((x) << S_CQ_ARMED) +#define F_CQ_ARMED V_CQ_ARMED(1U) + +#define S_CQ_ASYNC_NOTIF_SOL 28 +#define V_CQ_ASYNC_NOTIF_SOL(x) ((x) << S_CQ_ASYNC_NOTIF_SOL) +#define F_CQ_ASYNC_NOTIF_SOL V_CQ_ASYNC_NOTIF_SOL(1U) + +#define S_CQ_GEN 29 +#define V_CQ_GEN(x) ((x) << S_CQ_GEN) +#define F_CQ_GEN V_CQ_GEN(1U) + +#define S_CQ_OVERFLOW_MODE 31 +#define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE) +#define F_CQ_OVERFLOW_MODE V_CQ_OVERFLOW_MODE(1U) + +#define S_CQ_CREDITS 0 +#define M_CQ_CREDITS 0xFFFF +#define V_CQ_CREDITS(x) ((x) << S_CQ_CREDITS) +#define G_CQ_CREDITS(x) (((x) >> S_CQ_CREDITS) & M_CQ_CREDITS) + +#define S_CQ_CREDIT_THRES 16 +#define M_CQ_CREDIT_THRES 0x1FFF +#define V_CQ_CREDIT_THRES(x) ((x) << S_CQ_CREDIT_THRES) +#define G_CQ_CREDIT_THRES(x) (((x) >> S_CQ_CREDIT_THRES) & M_CQ_CREDIT_THRES) + +#define S_FL_BASE_HI 0 +#define M_FL_BASE_HI 0xFFFFF +#define V_FL_BASE_HI(x) ((x) << S_FL_BASE_HI) +#define G_FL_BASE_HI(x) (((x) >> S_FL_BASE_HI) & M_FL_BASE_HI) + +#define S_FL_INDEX_LO 20 +#define M_FL_INDEX_LO 0xFFF +#define V_FL_INDEX_LO(x) ((x) << S_FL_INDEX_LO) +#define G_FL_INDEX_LO(x) (((x) >> S_FL_INDEX_LO) & M_FL_INDEX_LO) + +#define S_FL_INDEX_HI 0 +#define M_FL_INDEX_HI 0xF +#define V_FL_INDEX_HI(x) ((x) << S_FL_INDEX_HI) +#define G_FL_INDEX_HI(x) (((x) >> S_FL_INDEX_HI) & M_FL_INDEX_HI) + +#define S_FL_SIZE 4 +#define M_FL_SIZE 0xFFFF +#define V_FL_SIZE(x) ((x) << S_FL_SIZE) +#define G_FL_SIZE(x) (((x) >> S_FL_SIZE) & M_FL_SIZE) + +#define S_FL_GEN 20 +#define V_FL_GEN(x) ((x) << S_FL_GEN) +#define F_FL_GEN V_FL_GEN(1U) + +#define S_FL_ENTRY_SIZE_LO 21 +#define M_FL_ENTRY_SIZE_LO 0x7FF +#define V_FL_ENTRY_SIZE_LO(x) ((x) << S_FL_ENTRY_SIZE_LO) +#define G_FL_ENTRY_SIZE_LO(x) (((x) >> S_FL_ENTRY_SIZE_LO) & M_FL_ENTRY_SIZE_LO) + +#define S_FL_ENTRY_SIZE_HI 0 +#define M_FL_ENTRY_SIZE_HI 0x1FFFFF +#define V_FL_ENTRY_SIZE_HI(x) ((x) << S_FL_ENTRY_SIZE_HI) +#define G_FL_ENTRY_SIZE_HI(x) (((x) >> S_FL_ENTRY_SIZE_HI) & M_FL_ENTRY_SIZE_HI) + +#define S_FL_CONG_THRES 21 +#define M_FL_CONG_THRES 0x3FF +#define V_FL_CONG_THRES(x) ((x) << S_FL_CONG_THRES) +#define G_FL_CONG_THRES(x) (((x) >> S_FL_CONG_THRES) & M_FL_CONG_THRES) + +#define S_FL_GTS 31 +#define V_FL_GTS(x) ((x) << S_FL_GTS) +#define F_FL_GTS V_FL_GTS(1U) + +#define S_FLD_GEN1 31 +#define V_FLD_GEN1(x) ((x) << S_FLD_GEN1) +#define F_FLD_GEN1 V_FLD_GEN1(1U) + +#define S_FLD_GEN2 0 +#define V_FLD_GEN2(x) ((x) << S_FLD_GEN2) +#define F_FLD_GEN2 V_FLD_GEN2(1U) + +#define S_RSPD_TXQ1_CR 0 +#define M_RSPD_TXQ1_CR 0x7F +#define V_RSPD_TXQ1_CR(x) ((x) << S_RSPD_TXQ1_CR) +#define G_RSPD_TXQ1_CR(x) (((x) >> S_RSPD_TXQ1_CR) & M_RSPD_TXQ1_CR) + +#define S_RSPD_TXQ1_GTS 7 +#define V_RSPD_TXQ1_GTS(x) ((x) << S_RSPD_TXQ1_GTS) +#define F_RSPD_TXQ1_GTS V_RSPD_TXQ1_GTS(1U) + +#define S_RSPD_TXQ2_CR 8 +#define M_RSPD_TXQ2_CR 0x7F +#define V_RSPD_TXQ2_CR(x) ((x) << S_RSPD_TXQ2_CR) +#define G_RSPD_TXQ2_CR(x) (((x) >> S_RSPD_TXQ2_CR) & M_RSPD_TXQ2_CR) + +#define S_RSPD_TXQ2_GTS 15 +#define V_RSPD_TXQ2_GTS(x) ((x) << S_RSPD_TXQ2_GTS) +#define F_RSPD_TXQ2_GTS V_RSPD_TXQ2_GTS(1U) + +#define S_RSPD_TXQ0_CR 16 +#define M_RSPD_TXQ0_CR 0x7F +#define V_RSPD_TXQ0_CR(x) ((x) << S_RSPD_TXQ0_CR) +#define G_RSPD_TXQ0_CR(x) (((x) >> S_RSPD_TXQ0_CR) & M_RSPD_TXQ0_CR) + +#define S_RSPD_TXQ0_GTS 23 +#define V_RSPD_TXQ0_GTS(x) ((x) << S_RSPD_TXQ0_GTS) +#define F_RSPD_TXQ0_GTS V_RSPD_TXQ0_GTS(1U) + +#define S_RSPD_EOP 24 +#define V_RSPD_EOP(x) ((x) << S_RSPD_EOP) +#define F_RSPD_EOP V_RSPD_EOP(1U) + +#define S_RSPD_SOP 25 +#define V_RSPD_SOP(x) ((x) << S_RSPD_SOP) +#define F_RSPD_SOP V_RSPD_SOP(1U) + +#define S_RSPD_ASYNC_NOTIF 26 +#define V_RSPD_ASYNC_NOTIF(x) ((x) << S_RSPD_ASYNC_NOTIF) +#define F_RSPD_ASYNC_NOTIF V_RSPD_ASYNC_NOTIF(1U) + +#define S_RSPD_FL0_GTS 27 +#define V_RSPD_FL0_GTS(x) ((x) << S_RSPD_FL0_GTS) +#define F_RSPD_FL0_GTS V_RSPD_FL0_GTS(1U) + +#define S_RSPD_FL1_GTS 28 +#define V_RSPD_FL1_GTS(x) ((x) << S_RSPD_FL1_GTS) +#define F_RSPD_FL1_GTS V_RSPD_FL1_GTS(1U) + +#define S_RSPD_IMM_DATA_VALID 29 +#define V_RSPD_IMM_DATA_VALID(x) ((x) << S_RSPD_IMM_DATA_VALID) +#define F_RSPD_IMM_DATA_VALID V_RSPD_IMM_DATA_VALID(1U) + +#define S_RSPD_OFFLOAD 30 +#define V_RSPD_OFFLOAD(x) ((x) << S_RSPD_OFFLOAD) +#define F_RSPD_OFFLOAD V_RSPD_OFFLOAD(1U) + +#define S_RSPD_GEN1 31 +#define V_RSPD_GEN1(x) ((x) << S_RSPD_GEN1) +#define F_RSPD_GEN1 V_RSPD_GEN1(1U) + +#define S_RSPD_LEN 0 +#define M_RSPD_LEN 0x7FFFFFFF +#define V_RSPD_LEN(x) ((x) << S_RSPD_LEN) +#define G_RSPD_LEN(x) (((x) >> S_RSPD_LEN) & M_RSPD_LEN) + +#define S_RSPD_FLQ 31 +#define V_RSPD_FLQ(x) ((x) << S_RSPD_FLQ) +#define F_RSPD_FLQ V_RSPD_FLQ(1U) + +#define S_RSPD_GEN2 0 +#define V_RSPD_GEN2(x) ((x) << S_RSPD_GEN2) +#define F_RSPD_GEN2 V_RSPD_GEN2(1U) + +#define S_RSPD_INR_VEC 1 +#define M_RSPD_INR_VEC 0x7F +#define V_RSPD_INR_VEC(x) ((x) << S_RSPD_INR_VEC) +#define G_RSPD_INR_VEC(x) (((x) >> S_RSPD_INR_VEC) & M_RSPD_INR_VEC) + +#endif /* _SGE_DEFS_H */ diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h new file mode 100644 index 000000000000..b7a1a310dfd4 --- /dev/null +++ b/drivers/net/cxgb3/t3_cpl.h @@ -0,0 +1,1444 @@ +/* + * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef T3_CPL_H +#define T3_CPL_H + +#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD) +# include +#endif + +enum CPL_opcode { + CPL_PASS_OPEN_REQ = 0x1, + CPL_PASS_ACCEPT_RPL = 0x2, + CPL_ACT_OPEN_REQ = 0x3, + CPL_SET_TCB = 0x4, + CPL_SET_TCB_FIELD = 0x5, + CPL_GET_TCB = 0x6, + CPL_PCMD = 0x7, + CPL_CLOSE_CON_REQ = 0x8, + CPL_CLOSE_LISTSRV_REQ = 0x9, + CPL_ABORT_REQ = 0xA, + CPL_ABORT_RPL = 0xB, + CPL_TX_DATA = 0xC, + CPL_RX_DATA_ACK = 0xD, + CPL_TX_PKT = 0xE, + CPL_RTE_DELETE_REQ = 0xF, + CPL_RTE_WRITE_REQ = 0x10, + CPL_RTE_READ_REQ = 0x11, + CPL_L2T_WRITE_REQ = 0x12, + CPL_L2T_READ_REQ = 0x13, + CPL_SMT_WRITE_REQ = 0x14, + CPL_SMT_READ_REQ = 0x15, + CPL_TX_PKT_LSO = 0x16, + CPL_PCMD_READ = 0x17, + CPL_BARRIER = 0x18, + CPL_TID_RELEASE = 0x1A, + + CPL_CLOSE_LISTSRV_RPL = 0x20, + CPL_ERROR = 0x21, + CPL_GET_TCB_RPL = 0x22, + CPL_L2T_WRITE_RPL = 0x23, + CPL_PCMD_READ_RPL = 0x24, + CPL_PCMD_RPL = 0x25, + CPL_PEER_CLOSE = 0x26, + CPL_RTE_DELETE_RPL = 0x27, + CPL_RTE_WRITE_RPL = 0x28, + CPL_RX_DDP_COMPLETE = 0x29, + CPL_RX_PHYS_ADDR = 0x2A, + CPL_RX_PKT = 0x2B, + CPL_RX_URG_NOTIFY = 0x2C, + CPL_SET_TCB_RPL = 0x2D, + CPL_SMT_WRITE_RPL = 0x2E, + CPL_TX_DATA_ACK = 0x2F, + + CPL_ABORT_REQ_RSS = 0x30, + CPL_ABORT_RPL_RSS = 0x31, + CPL_CLOSE_CON_RPL = 0x32, + CPL_ISCSI_HDR = 0x33, + CPL_L2T_READ_RPL = 0x34, + CPL_RDMA_CQE = 0x35, + CPL_RDMA_CQE_READ_RSP = 0x36, + CPL_RDMA_CQE_ERR = 0x37, + CPL_RTE_READ_RPL = 0x38, + CPL_RX_DATA = 0x39, + + CPL_ACT_OPEN_RPL = 0x40, + CPL_PASS_OPEN_RPL = 0x41, + CPL_RX_DATA_DDP = 0x42, + CPL_SMT_READ_RPL = 0x43, + + CPL_ACT_ESTABLISH = 0x50, + CPL_PASS_ESTABLISH = 0x51, + + CPL_PASS_ACCEPT_REQ = 0x70, + + CPL_ASYNC_NOTIF = 0x80, /* fake opcode for async notifications */ + + CPL_TX_DMA_ACK = 0xA0, + CPL_RDMA_READ_REQ = 0xA1, + CPL_RDMA_TERMINATE = 0xA2, + CPL_TRACE_PKT = 0xA3, + CPL_RDMA_EC_STATUS = 0xA5, + + NUM_CPL_CMDS /* must be last and previous entries must be sorted */ +}; + +enum CPL_error { + CPL_ERR_NONE = 0, + CPL_ERR_TCAM_PARITY = 1, + CPL_ERR_TCAM_FULL = 3, + CPL_ERR_CONN_RESET = 20, + CPL_ERR_CONN_EXIST = 22, + CPL_ERR_ARP_MISS = 23, + CPL_ERR_BAD_SYN = 24, + CPL_ERR_CONN_TIMEDOUT = 30, + CPL_ERR_XMIT_TIMEDOUT = 31, + CPL_ERR_PERSIST_TIMEDOUT = 32, + CPL_ERR_FINWAIT2_TIMEDOUT = 33, + CPL_ERR_KEEPALIVE_TIMEDOUT = 34, + CPL_ERR_RTX_NEG_ADVICE = 35, + CPL_ERR_PERSIST_NEG_ADVICE = 36, + CPL_ERR_ABORT_FAILED = 42, + CPL_ERR_GENERAL = 99 +}; + +enum { + CPL_CONN_POLICY_AUTO = 0, + CPL_CONN_POLICY_ASK = 1, + CPL_CONN_POLICY_DENY = 3 +}; + +enum { + ULP_MODE_NONE = 0, + ULP_MODE_ISCSI = 2, + ULP_MODE_RDMA = 4, + ULP_MODE_TCPDDP = 5 +}; + +enum { + ULP_CRC_HEADER = 1 << 0, + ULP_CRC_DATA = 1 << 1 +}; + +enum { + CPL_PASS_OPEN_ACCEPT, + CPL_PASS_OPEN_REJECT +}; + +enum { + CPL_ABORT_SEND_RST = 0, + CPL_ABORT_NO_RST, + CPL_ABORT_POST_CLOSE_REQ = 2 +}; + +enum { /* TX_PKT_LSO ethernet types */ + CPL_ETH_II, + CPL_ETH_II_VLAN, + CPL_ETH_802_3, + CPL_ETH_802_3_VLAN +}; + +enum { /* TCP congestion control algorithms */ + CONG_ALG_RENO, + CONG_ALG_TAHOE, + CONG_ALG_NEWRENO, + CONG_ALG_HIGHSPEED +}; + +union opcode_tid { + __be32 opcode_tid; + __u8 opcode; +}; + +#define S_OPCODE 24 +#define V_OPCODE(x) ((x) << S_OPCODE) +#define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF) +#define G_TID(x) ((x) & 0xFFFFFF) + +/* tid is assumed to be 24-bits */ +#define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid)) + +#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid) + +/* extract the TID from a CPL command */ +#define GET_TID(cmd) (G_TID(ntohl(OPCODE_TID(cmd)))) + +struct tcp_options { + __be16 mss; + __u8 wsf; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:5; + __u8 ecn:1; + __u8 sack:1; + __u8 tstamp:1; +#else + __u8 tstamp:1; + __u8 sack:1; + __u8 ecn:1; + __u8:5; +#endif +}; + +struct rss_header { + __u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 cpu_idx:6; + __u8 hash_type:2; +#else + __u8 hash_type:2; + __u8 cpu_idx:6; +#endif + __be16 cq_idx; + __be32 rss_hash_val; +}; + +#ifndef CHELSIO_FW +struct work_request_hdr { + __be32 wr_hi; + __be32 wr_lo; +}; + +/* wr_hi fields */ +#define S_WR_SGE_CREDITS 0 +#define M_WR_SGE_CREDITS 0xFF +#define V_WR_SGE_CREDITS(x) ((x) << S_WR_SGE_CREDITS) +#define G_WR_SGE_CREDITS(x) (((x) >> S_WR_SGE_CREDITS) & M_WR_SGE_CREDITS) + +#define S_WR_SGLSFLT 8 +#define M_WR_SGLSFLT 0xFF +#define V_WR_SGLSFLT(x) ((x) << S_WR_SGLSFLT) +#define G_WR_SGLSFLT(x) (((x) >> S_WR_SGLSFLT) & M_WR_SGLSFLT) + +#define S_WR_BCNTLFLT 16 +#define M_WR_BCNTLFLT 0xF +#define V_WR_BCNTLFLT(x) ((x) << S_WR_BCNTLFLT) +#define G_WR_BCNTLFLT(x) (((x) >> S_WR_BCNTLFLT) & M_WR_BCNTLFLT) + +#define S_WR_DATATYPE 20 +#define V_WR_DATATYPE(x) ((x) << S_WR_DATATYPE) +#define F_WR_DATATYPE V_WR_DATATYPE(1U) + +#define S_WR_COMPL 21 +#define V_WR_COMPL(x) ((x) << S_WR_COMPL) +#define F_WR_COMPL V_WR_COMPL(1U) + +#define S_WR_EOP 22 +#define V_WR_EOP(x) ((x) << S_WR_EOP) +#define F_WR_EOP V_WR_EOP(1U) + +#define S_WR_SOP 23 +#define V_WR_SOP(x) ((x) << S_WR_SOP) +#define F_WR_SOP V_WR_SOP(1U) + +#define S_WR_OP 24 +#define M_WR_OP 0xFF +#define V_WR_OP(x) ((x) << S_WR_OP) +#define G_WR_OP(x) (((x) >> S_WR_OP) & M_WR_OP) + +/* wr_lo fields */ +#define S_WR_LEN 0 +#define M_WR_LEN 0xFF +#define V_WR_LEN(x) ((x) << S_WR_LEN) +#define G_WR_LEN(x) (((x) >> S_WR_LEN) & M_WR_LEN) + +#define S_WR_TID 8 +#define M_WR_TID 0xFFFFF +#define V_WR_TID(x) ((x) << S_WR_TID) +#define G_WR_TID(x) (((x) >> S_WR_TID) & M_WR_TID) + +#define S_WR_CR_FLUSH 30 +#define V_WR_CR_FLUSH(x) ((x) << S_WR_CR_FLUSH) +#define F_WR_CR_FLUSH V_WR_CR_FLUSH(1U) + +#define S_WR_GEN 31 +#define V_WR_GEN(x) ((x) << S_WR_GEN) +#define F_WR_GEN V_WR_GEN(1U) + +# define WR_HDR struct work_request_hdr wr +# define RSS_HDR +#else +# define WR_HDR +# define RSS_HDR struct rss_header rss_hdr; +#endif + +/* option 0 lower-half fields */ +#define S_CPL_STATUS 0 +#define M_CPL_STATUS 0xFF +#define V_CPL_STATUS(x) ((x) << S_CPL_STATUS) +#define G_CPL_STATUS(x) (((x) >> S_CPL_STATUS) & M_CPL_STATUS) + +#define S_INJECT_TIMER 6 +#define V_INJECT_TIMER(x) ((x) << S_INJECT_TIMER) +#define F_INJECT_TIMER V_INJECT_TIMER(1U) + +#define S_NO_OFFLOAD 7 +#define V_NO_OFFLOAD(x) ((x) << S_NO_OFFLOAD) +#define F_NO_OFFLOAD V_NO_OFFLOAD(1U) + +#define S_ULP_MODE 8 +#define M_ULP_MODE 0xF +#define V_ULP_MODE(x) ((x) << S_ULP_MODE) +#define G_ULP_MODE(x) (((x) >> S_ULP_MODE) & M_ULP_MODE) + +#define S_RCV_BUFSIZ 12 +#define M_RCV_BUFSIZ 0x3FFF +#define V_RCV_BUFSIZ(x) ((x) << S_RCV_BUFSIZ) +#define G_RCV_BUFSIZ(x) (((x) >> S_RCV_BUFSIZ) & M_RCV_BUFSIZ) + +#define S_TOS 26 +#define M_TOS 0x3F +#define V_TOS(x) ((x) << S_TOS) +#define G_TOS(x) (((x) >> S_TOS) & M_TOS) + +/* option 0 upper-half fields */ +#define S_DELACK 0 +#define V_DELACK(x) ((x) << S_DELACK) +#define F_DELACK V_DELACK(1U) + +#define S_NO_CONG 1 +#define V_NO_CONG(x) ((x) << S_NO_CONG) +#define F_NO_CONG V_NO_CONG(1U) + +#define S_SRC_MAC_SEL 2 +#define M_SRC_MAC_SEL 0x3 +#define V_SRC_MAC_SEL(x) ((x) << S_SRC_MAC_SEL) +#define G_SRC_MAC_SEL(x) (((x) >> S_SRC_MAC_SEL) & M_SRC_MAC_SEL) + +#define S_L2T_IDX 4 +#define M_L2T_IDX 0x7FF +#define V_L2T_IDX(x) ((x) << S_L2T_IDX) +#define G_L2T_IDX(x) (((x) >> S_L2T_IDX) & M_L2T_IDX) + +#define S_TX_CHANNEL 15 +#define V_TX_CHANNEL(x) ((x) << S_TX_CHANNEL) +#define F_TX_CHANNEL V_TX_CHANNEL(1U) + +#define S_TCAM_BYPASS 16 +#define V_TCAM_BYPASS(x) ((x) << S_TCAM_BYPASS) +#define F_TCAM_BYPASS V_TCAM_BYPASS(1U) + +#define S_NAGLE 17 +#define V_NAGLE(x) ((x) << S_NAGLE) +#define F_NAGLE V_NAGLE(1U) + +#define S_WND_SCALE 18 +#define M_WND_SCALE 0xF +#define V_WND_SCALE(x) ((x) << S_WND_SCALE) +#define G_WND_SCALE(x) (((x) >> S_WND_SCALE) & M_WND_SCALE) + +#define S_KEEP_ALIVE 22 +#define V_KEEP_ALIVE(x) ((x) << S_KEEP_ALIVE) +#define F_KEEP_ALIVE V_KEEP_ALIVE(1U) + +#define S_MAX_RETRANS 23 +#define M_MAX_RETRANS 0xF +#define V_MAX_RETRANS(x) ((x) << S_MAX_RETRANS) +#define G_MAX_RETRANS(x) (((x) >> S_MAX_RETRANS) & M_MAX_RETRANS) + +#define S_MAX_RETRANS_OVERRIDE 27 +#define V_MAX_RETRANS_OVERRIDE(x) ((x) << S_MAX_RETRANS_OVERRIDE) +#define F_MAX_RETRANS_OVERRIDE V_MAX_RETRANS_OVERRIDE(1U) + +#define S_MSS_IDX 28 +#define M_MSS_IDX 0xF +#define V_MSS_IDX(x) ((x) << S_MSS_IDX) +#define G_MSS_IDX(x) (((x) >> S_MSS_IDX) & M_MSS_IDX) + +/* option 1 fields */ +#define S_RSS_ENABLE 0 +#define V_RSS_ENABLE(x) ((x) << S_RSS_ENABLE) +#define F_RSS_ENABLE V_RSS_ENABLE(1U) + +#define S_RSS_MASK_LEN 1 +#define M_RSS_MASK_LEN 0x7 +#define V_RSS_MASK_LEN(x) ((x) << S_RSS_MASK_LEN) +#define G_RSS_MASK_LEN(x) (((x) >> S_RSS_MASK_LEN) & M_RSS_MASK_LEN) + +#define S_CPU_IDX 4 +#define M_CPU_IDX 0x3F +#define V_CPU_IDX(x) ((x) << S_CPU_IDX) +#define G_CPU_IDX(x) (((x) >> S_CPU_IDX) & M_CPU_IDX) + +#define S_MAC_MATCH_VALID 18 +#define V_MAC_MATCH_VALID(x) ((x) << S_MAC_MATCH_VALID) +#define F_MAC_MATCH_VALID V_MAC_MATCH_VALID(1U) + +#define S_CONN_POLICY 19 +#define M_CONN_POLICY 0x3 +#define V_CONN_POLICY(x) ((x) << S_CONN_POLICY) +#define G_CONN_POLICY(x) (((x) >> S_CONN_POLICY) & M_CONN_POLICY) + +#define S_SYN_DEFENSE 21 +#define V_SYN_DEFENSE(x) ((x) << S_SYN_DEFENSE) +#define F_SYN_DEFENSE V_SYN_DEFENSE(1U) + +#define S_VLAN_PRI 22 +#define M_VLAN_PRI 0x3 +#define V_VLAN_PRI(x) ((x) << S_VLAN_PRI) +#define G_VLAN_PRI(x) (((x) >> S_VLAN_PRI) & M_VLAN_PRI) + +#define S_VLAN_PRI_VALID 24 +#define V_VLAN_PRI_VALID(x) ((x) << S_VLAN_PRI_VALID) +#define F_VLAN_PRI_VALID V_VLAN_PRI_VALID(1U) + +#define S_PKT_TYPE 25 +#define M_PKT_TYPE 0x3 +#define V_PKT_TYPE(x) ((x) << S_PKT_TYPE) +#define G_PKT_TYPE(x) (((x) >> S_PKT_TYPE) & M_PKT_TYPE) + +#define S_MAC_MATCH 27 +#define M_MAC_MATCH 0x1F +#define V_MAC_MATCH(x) ((x) << S_MAC_MATCH) +#define G_MAC_MATCH(x) (((x) >> S_MAC_MATCH) & M_MAC_MATCH) + +/* option 2 fields */ +#define S_CPU_INDEX 0 +#define M_CPU_INDEX 0x7F +#define V_CPU_INDEX(x) ((x) << S_CPU_INDEX) +#define G_CPU_INDEX(x) (((x) >> S_CPU_INDEX) & M_CPU_INDEX) + +#define S_CPU_INDEX_VALID 7 +#define V_CPU_INDEX_VALID(x) ((x) << S_CPU_INDEX_VALID) +#define F_CPU_INDEX_VALID V_CPU_INDEX_VALID(1U) + +#define S_RX_COALESCE 8 +#define M_RX_COALESCE 0x3 +#define V_RX_COALESCE(x) ((x) << S_RX_COALESCE) +#define G_RX_COALESCE(x) (((x) >> S_RX_COALESCE) & M_RX_COALESCE) + +#define S_RX_COALESCE_VALID 10 +#define V_RX_COALESCE_VALID(x) ((x) << S_RX_COALESCE_VALID) +#define F_RX_COALESCE_VALID V_RX_COALESCE_VALID(1U) + +#define S_CONG_CONTROL_FLAVOR 11 +#define M_CONG_CONTROL_FLAVOR 0x3 +#define V_CONG_CONTROL_FLAVOR(x) ((x) << S_CONG_CONTROL_FLAVOR) +#define G_CONG_CONTROL_FLAVOR(x) (((x) >> S_CONG_CONTROL_FLAVOR) & M_CONG_CONTROL_FLAVOR) + +#define S_PACING_FLAVOR 13 +#define M_PACING_FLAVOR 0x3 +#define V_PACING_FLAVOR(x) ((x) << S_PACING_FLAVOR) +#define G_PACING_FLAVOR(x) (((x) >> S_PACING_FLAVOR) & M_PACING_FLAVOR) + +#define S_FLAVORS_VALID 15 +#define V_FLAVORS_VALID(x) ((x) << S_FLAVORS_VALID) +#define F_FLAVORS_VALID V_FLAVORS_VALID(1U) + +#define S_RX_FC_DISABLE 16 +#define V_RX_FC_DISABLE(x) ((x) << S_RX_FC_DISABLE) +#define F_RX_FC_DISABLE V_RX_FC_DISABLE(1U) + +#define S_RX_FC_VALID 17 +#define V_RX_FC_VALID(x) ((x) << S_RX_FC_VALID) +#define F_RX_FC_VALID V_RX_FC_VALID(1U) + +struct cpl_pass_open_req { + WR_HDR; + union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 opt0h; + __be32 opt0l; + __be32 peer_netmask; + __be32 opt1; +}; + +struct cpl_pass_open_rpl { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __u8 resvd[7]; + __u8 status; +}; + +struct cpl_pass_establish { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 tos_tid; + __be16 l2t_idx; + __be16 tcp_opt; + __be32 snd_isn; + __be32 rcv_isn; +}; + +/* cpl_pass_establish.tos_tid fields */ +#define S_PASS_OPEN_TID 0 +#define M_PASS_OPEN_TID 0xFFFFFF +#define V_PASS_OPEN_TID(x) ((x) << S_PASS_OPEN_TID) +#define G_PASS_OPEN_TID(x) (((x) >> S_PASS_OPEN_TID) & M_PASS_OPEN_TID) + +#define S_PASS_OPEN_TOS 24 +#define M_PASS_OPEN_TOS 0xFF +#define V_PASS_OPEN_TOS(x) ((x) << S_PASS_OPEN_TOS) +#define G_PASS_OPEN_TOS(x) (((x) >> S_PASS_OPEN_TOS) & M_PASS_OPEN_TOS) + +/* cpl_pass_establish.l2t_idx fields */ +#define S_L2T_IDX16 5 +#define M_L2T_IDX16 0x7FF +#define V_L2T_IDX16(x) ((x) << S_L2T_IDX16) +#define G_L2T_IDX16(x) (((x) >> S_L2T_IDX16) & M_L2T_IDX16) + +/* cpl_pass_establish.tcp_opt fields (also applies act_open_establish) */ +#define G_TCPOPT_WSCALE_OK(x) (((x) >> 5) & 1) +#define G_TCPOPT_SACK(x) (((x) >> 6) & 1) +#define G_TCPOPT_TSTAMP(x) (((x) >> 7) & 1) +#define G_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf) +#define G_TCPOPT_MSS(x) (((x) >> 12) & 0xf) + +struct cpl_pass_accept_req { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 tos_tid; + struct tcp_options tcp_options; + __u8 dst_mac[6]; + __be16 vlan_tag; + __u8 src_mac[6]; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:3; + __u8 addr_idx:3; + __u8 port_idx:1; + __u8 exact_match:1; +#else + __u8 exact_match:1; + __u8 port_idx:1; + __u8 addr_idx:3; + __u8:3; +#endif + __u8 rsvd; + __be32 rcv_isn; + __be32 rsvd2; +}; + +struct cpl_pass_accept_rpl { + WR_HDR; + union opcode_tid ot; + __be32 opt2; + __be32 rsvd; + __be32 peer_ip; + __be32 opt0h; + __be32 opt0l_status; +}; + +struct cpl_act_open_req { + WR_HDR; + union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 opt0h; + __be32 opt0l; + __be32 params; + __be32 opt2; +}; + +/* cpl_act_open_req.params fields */ +#define S_AOPEN_VLAN_PRI 9 +#define M_AOPEN_VLAN_PRI 0x3 +#define V_AOPEN_VLAN_PRI(x) ((x) << S_AOPEN_VLAN_PRI) +#define G_AOPEN_VLAN_PRI(x) (((x) >> S_AOPEN_VLAN_PRI) & M_AOPEN_VLAN_PRI) + +#define S_AOPEN_VLAN_PRI_VALID 11 +#define V_AOPEN_VLAN_PRI_VALID(x) ((x) << S_AOPEN_VLAN_PRI_VALID) +#define F_AOPEN_VLAN_PRI_VALID V_AOPEN_VLAN_PRI_VALID(1U) + +#define S_AOPEN_PKT_TYPE 12 +#define M_AOPEN_PKT_TYPE 0x3 +#define V_AOPEN_PKT_TYPE(x) ((x) << S_AOPEN_PKT_TYPE) +#define G_AOPEN_PKT_TYPE(x) (((x) >> S_AOPEN_PKT_TYPE) & M_AOPEN_PKT_TYPE) + +#define S_AOPEN_MAC_MATCH 14 +#define M_AOPEN_MAC_MATCH 0x1F +#define V_AOPEN_MAC_MATCH(x) ((x) << S_AOPEN_MAC_MATCH) +#define G_AOPEN_MAC_MATCH(x) (((x) >> S_AOPEN_MAC_MATCH) & M_AOPEN_MAC_MATCH) + +#define S_AOPEN_MAC_MATCH_VALID 19 +#define V_AOPEN_MAC_MATCH_VALID(x) ((x) << S_AOPEN_MAC_MATCH_VALID) +#define F_AOPEN_MAC_MATCH_VALID V_AOPEN_MAC_MATCH_VALID(1U) + +#define S_AOPEN_IFF_VLAN 20 +#define M_AOPEN_IFF_VLAN 0xFFF +#define V_AOPEN_IFF_VLAN(x) ((x) << S_AOPEN_IFF_VLAN) +#define G_AOPEN_IFF_VLAN(x) (((x) >> S_AOPEN_IFF_VLAN) & M_AOPEN_IFF_VLAN) + +struct cpl_act_open_rpl { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 atid; + __u8 rsvd[3]; + __u8 status; +}; + +struct cpl_act_establish { + RSS_HDR union opcode_tid ot; + __be16 local_port; + __be16 peer_port; + __be32 local_ip; + __be32 peer_ip; + __be32 tos_tid; + __be16 l2t_idx; + __be16 tcp_opt; + __be32 snd_isn; + __be32 rcv_isn; +}; + +struct cpl_get_tcb { + WR_HDR; + union opcode_tid ot; + __be16 cpuno; + __be16 rsvd; +}; + +struct cpl_get_tcb_rpl { + RSS_HDR union opcode_tid ot; + __u8 rsvd; + __u8 status; + __be16 len; +}; + +struct cpl_set_tcb { + WR_HDR; + union opcode_tid ot; + __u8 reply; + __u8 cpu_idx; + __be16 len; +}; + +/* cpl_set_tcb.reply fields */ +#define S_NO_REPLY 7 +#define V_NO_REPLY(x) ((x) << S_NO_REPLY) +#define F_NO_REPLY V_NO_REPLY(1U) + +struct cpl_set_tcb_field { + WR_HDR; + union opcode_tid ot; + __u8 reply; + __u8 cpu_idx; + __be16 word; + __be64 mask; + __be64 val; +}; + +struct cpl_set_tcb_rpl { + RSS_HDR union opcode_tid ot; + __u8 rsvd[3]; + __u8 status; +}; + +struct cpl_pcmd { + WR_HDR; + union opcode_tid ot; + __u8 rsvd[3]; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 src:1; + __u8 bundle:1; + __u8 channel:1; + __u8:5; +#else + __u8:5; + __u8 channel:1; + __u8 bundle:1; + __u8 src:1; +#endif + __be32 pcmd_parm[2]; +}; + +struct cpl_pcmd_reply { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd; + __be16 len; +}; + +struct cpl_close_con_req { + WR_HDR; + union opcode_tid ot; + __be32 rsvd; +}; + +struct cpl_close_con_rpl { + RSS_HDR union opcode_tid ot; + __u8 rsvd[3]; + __u8 status; + __be32 snd_nxt; + __be32 rcv_nxt; +}; + +struct cpl_close_listserv_req { + WR_HDR; + union opcode_tid ot; + __u8 rsvd0; + __u8 cpu_idx; + __be16 rsvd1; +}; + +struct cpl_close_listserv_rpl { + RSS_HDR union opcode_tid ot; + __u8 rsvd[3]; + __u8 status; +}; + +struct cpl_abort_req_rss { + RSS_HDR union opcode_tid ot; + __be32 rsvd0; + __u8 rsvd1; + __u8 status; + __u8 rsvd2[6]; +}; + +struct cpl_abort_req { + WR_HDR; + union opcode_tid ot; + __be32 rsvd0; + __u8 rsvd1; + __u8 cmd; + __u8 rsvd2[6]; +}; + +struct cpl_abort_rpl_rss { + RSS_HDR union opcode_tid ot; + __be32 rsvd0; + __u8 rsvd1; + __u8 status; + __u8 rsvd2[6]; +}; + +struct cpl_abort_rpl { + WR_HDR; + union opcode_tid ot; + __be32 rsvd0; + __u8 rsvd1; + __u8 cmd; + __u8 rsvd2[6]; +}; + +struct cpl_peer_close { + RSS_HDR union opcode_tid ot; + __be32 rcv_nxt; +}; + +struct tx_data_wr { + __be32 wr_hi; + __be32 wr_lo; + __be32 len; + __be32 flags; + __be32 sndseq; + __be32 param; +}; + +/* tx_data_wr.param fields */ +#define S_TX_PORT 0 +#define M_TX_PORT 0x7 +#define V_TX_PORT(x) ((x) << S_TX_PORT) +#define G_TX_PORT(x) (((x) >> S_TX_PORT) & M_TX_PORT) + +#define S_TX_MSS 4 +#define M_TX_MSS 0xF +#define V_TX_MSS(x) ((x) << S_TX_MSS) +#define G_TX_MSS(x) (((x) >> S_TX_MSS) & M_TX_MSS) + +#define S_TX_QOS 8 +#define M_TX_QOS 0xFF +#define V_TX_QOS(x) ((x) << S_TX_QOS) +#define G_TX_QOS(x) (((x) >> S_TX_QOS) & M_TX_QOS) + +#define S_TX_SNDBUF 16 +#define M_TX_SNDBUF 0xFFFF +#define V_TX_SNDBUF(x) ((x) << S_TX_SNDBUF) +#define G_TX_SNDBUF(x) (((x) >> S_TX_SNDBUF) & M_TX_SNDBUF) + +struct cpl_tx_data { + union opcode_tid ot; + __be32 len; + __be32 rsvd; + __be16 urg; + __be16 flags; +}; + +/* cpl_tx_data.flags fields */ +#define S_TX_ULP_SUBMODE 6 +#define M_TX_ULP_SUBMODE 0xF +#define V_TX_ULP_SUBMODE(x) ((x) << S_TX_ULP_SUBMODE) +#define G_TX_ULP_SUBMODE(x) (((x) >> S_TX_ULP_SUBMODE) & M_TX_ULP_SUBMODE) + +#define S_TX_ULP_MODE 10 +#define M_TX_ULP_MODE 0xF +#define V_TX_ULP_MODE(x) ((x) << S_TX_ULP_MODE) +#define G_TX_ULP_MODE(x) (((x) >> S_TX_ULP_MODE) & M_TX_ULP_MODE) + +#define S_TX_SHOVE 14 +#define V_TX_SHOVE(x) ((x) << S_TX_SHOVE) +#define F_TX_SHOVE V_TX_SHOVE(1U) + +#define S_TX_MORE 15 +#define V_TX_MORE(x) ((x) << S_TX_MORE) +#define F_TX_MORE V_TX_MORE(1U) + +/* additional tx_data_wr.flags fields */ +#define S_TX_CPU_IDX 0 +#define M_TX_CPU_IDX 0x3F +#define V_TX_CPU_IDX(x) ((x) << S_TX_CPU_IDX) +#define G_TX_CPU_IDX(x) (((x) >> S_TX_CPU_IDX) & M_TX_CPU_IDX) + +#define S_TX_URG 16 +#define V_TX_URG(x) ((x) << S_TX_URG) +#define F_TX_URG V_TX_URG(1U) + +#define S_TX_CLOSE 17 +#define V_TX_CLOSE(x) ((x) << S_TX_CLOSE) +#define F_TX_CLOSE V_TX_CLOSE(1U) + +#define S_TX_INIT 18 +#define V_TX_INIT(x) ((x) << S_TX_INIT) +#define F_TX_INIT V_TX_INIT(1U) + +#define S_TX_IMM_ACK 19 +#define V_TX_IMM_ACK(x) ((x) << S_TX_IMM_ACK) +#define F_TX_IMM_ACK V_TX_IMM_ACK(1U) + +#define S_TX_IMM_DMA 20 +#define V_TX_IMM_DMA(x) ((x) << S_TX_IMM_DMA) +#define F_TX_IMM_DMA V_TX_IMM_DMA(1U) + +struct cpl_tx_data_ack { + RSS_HDR union opcode_tid ot; + __be32 ack_seq; +}; + +struct cpl_wr_ack { + RSS_HDR union opcode_tid ot; + __be16 credits; + __be16 rsvd; + __be32 snd_nxt; + __be32 snd_una; +}; + +struct cpl_rdma_ec_status { + RSS_HDR union opcode_tid ot; + __u8 rsvd[3]; + __u8 status; +}; + +struct mngt_pktsched_wr { + __be32 wr_hi; + __be32 wr_lo; + __u8 mngt_opcode; + __u8 rsvd[7]; + __u8 sched; + __u8 idx; + __u8 min; + __u8 max; + __u8 binding; + __u8 rsvd1[3]; +}; + +struct cpl_iscsi_hdr { + RSS_HDR union opcode_tid ot; + __be16 pdu_len_ddp; + __be16 len; + __be32 seq; + __be16 urg; + __u8 rsvd; + __u8 status; +}; + +/* cpl_iscsi_hdr.pdu_len_ddp fields */ +#define S_ISCSI_PDU_LEN 0 +#define M_ISCSI_PDU_LEN 0x7FFF +#define V_ISCSI_PDU_LEN(x) ((x) << S_ISCSI_PDU_LEN) +#define G_ISCSI_PDU_LEN(x) (((x) >> S_ISCSI_PDU_LEN) & M_ISCSI_PDU_LEN) + +#define S_ISCSI_DDP 15 +#define V_ISCSI_DDP(x) ((x) << S_ISCSI_DDP) +#define F_ISCSI_DDP V_ISCSI_DDP(1U) + +struct cpl_rx_data { + RSS_HDR union opcode_tid ot; + __be16 rsvd; + __be16 len; + __be32 seq; + __be16 urg; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 dack_mode:2; + __u8 psh:1; + __u8 heartbeat:1; + __u8:4; +#else + __u8:4; + __u8 heartbeat:1; + __u8 psh:1; + __u8 dack_mode:2; +#endif + __u8 status; +}; + +struct cpl_rx_data_ack { + WR_HDR; + union opcode_tid ot; + __be32 credit_dack; +}; + +/* cpl_rx_data_ack.ack_seq fields */ +#define S_RX_CREDITS 0 +#define M_RX_CREDITS 0x7FFFFFF +#define V_RX_CREDITS(x) ((x) << S_RX_CREDITS) +#define G_RX_CREDITS(x) (((x) >> S_RX_CREDITS) & M_RX_CREDITS) + +#define S_RX_MODULATE 27 +#define V_RX_MODULATE(x) ((x) << S_RX_MODULATE) +#define F_RX_MODULATE V_RX_MODULATE(1U) + +#define S_RX_FORCE_ACK 28 +#define V_RX_FORCE_ACK(x) ((x) << S_RX_FORCE_ACK) +#define F_RX_FORCE_ACK V_RX_FORCE_ACK(1U) + +#define S_RX_DACK_MODE 29 +#define M_RX_DACK_MODE 0x3 +#define V_RX_DACK_MODE(x) ((x) << S_RX_DACK_MODE) +#define G_RX_DACK_MODE(x) (((x) >> S_RX_DACK_MODE) & M_RX_DACK_MODE) + +#define S_RX_DACK_CHANGE 31 +#define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE) +#define F_RX_DACK_CHANGE V_RX_DACK_CHANGE(1U) + +struct cpl_rx_urg_notify { + RSS_HDR union opcode_tid ot; + __be32 seq; +}; + +struct cpl_rx_ddp_complete { + RSS_HDR union opcode_tid ot; + __be32 ddp_report; +}; + +struct cpl_rx_data_ddp { + RSS_HDR union opcode_tid ot; + __be16 urg; + __be16 len; + __be32 seq; + union { + __be32 nxt_seq; + __be32 ddp_report; + }; + __be32 ulp_crc; + __be32 ddpvld_status; +}; + +/* cpl_rx_data_ddp.ddpvld_status fields */ +#define S_DDP_STATUS 0 +#define M_DDP_STATUS 0xFF +#define V_DDP_STATUS(x) ((x) << S_DDP_STATUS) +#define G_DDP_STATUS(x) (((x) >> S_DDP_STATUS) & M_DDP_STATUS) + +#define S_DDP_VALID 15 +#define M_DDP_VALID 0x1FFFF +#define V_DDP_VALID(x) ((x) << S_DDP_VALID) +#define G_DDP_VALID(x) (((x) >> S_DDP_VALID) & M_DDP_VALID) + +#define S_DDP_PPOD_MISMATCH 15 +#define V_DDP_PPOD_MISMATCH(x) ((x) << S_DDP_PPOD_MISMATCH) +#define F_DDP_PPOD_MISMATCH V_DDP_PPOD_MISMATCH(1U) + +#define S_DDP_PDU 16 +#define V_DDP_PDU(x) ((x) << S_DDP_PDU) +#define F_DDP_PDU V_DDP_PDU(1U) + +#define S_DDP_LLIMIT_ERR 17 +#define V_DDP_LLIMIT_ERR(x) ((x) << S_DDP_LLIMIT_ERR) +#define F_DDP_LLIMIT_ERR V_DDP_LLIMIT_ERR(1U) + +#define S_DDP_PPOD_PARITY_ERR 18 +#define V_DDP_PPOD_PARITY_ERR(x) ((x) << S_DDP_PPOD_PARITY_ERR) +#define F_DDP_PPOD_PARITY_ERR V_DDP_PPOD_PARITY_ERR(1U) + +#define S_DDP_PADDING_ERR 19 +#define V_DDP_PADDING_ERR(x) ((x) << S_DDP_PADDING_ERR) +#define F_DDP_PADDING_ERR V_DDP_PADDING_ERR(1U) + +#define S_DDP_HDRCRC_ERR 20 +#define V_DDP_HDRCRC_ERR(x) ((x) << S_DDP_HDRCRC_ERR) +#define F_DDP_HDRCRC_ERR V_DDP_HDRCRC_ERR(1U) + +#define S_DDP_DATACRC_ERR 21 +#define V_DDP_DATACRC_ERR(x) ((x) << S_DDP_DATACRC_ERR) +#define F_DDP_DATACRC_ERR V_DDP_DATACRC_ERR(1U) + +#define S_DDP_INVALID_TAG 22 +#define V_DDP_INVALID_TAG(x) ((x) << S_DDP_INVALID_TAG) +#define F_DDP_INVALID_TAG V_DDP_INVALID_TAG(1U) + +#define S_DDP_ULIMIT_ERR 23 +#define V_DDP_ULIMIT_ERR(x) ((x) << S_DDP_ULIMIT_ERR) +#define F_DDP_ULIMIT_ERR V_DDP_ULIMIT_ERR(1U) + +#define S_DDP_OFFSET_ERR 24 +#define V_DDP_OFFSET_ERR(x) ((x) << S_DDP_OFFSET_ERR) +#define F_DDP_OFFSET_ERR V_DDP_OFFSET_ERR(1U) + +#define S_DDP_COLOR_ERR 25 +#define V_DDP_COLOR_ERR(x) ((x) << S_DDP_COLOR_ERR) +#define F_DDP_COLOR_ERR V_DDP_COLOR_ERR(1U) + +#define S_DDP_TID_MISMATCH 26 +#define V_DDP_TID_MISMATCH(x) ((x) << S_DDP_TID_MISMATCH) +#define F_DDP_TID_MISMATCH V_DDP_TID_MISMATCH(1U) + +#define S_DDP_INVALID_PPOD 27 +#define V_DDP_INVALID_PPOD(x) ((x) << S_DDP_INVALID_PPOD) +#define F_DDP_INVALID_PPOD V_DDP_INVALID_PPOD(1U) + +#define S_DDP_ULP_MODE 28 +#define M_DDP_ULP_MODE 0xF +#define V_DDP_ULP_MODE(x) ((x) << S_DDP_ULP_MODE) +#define G_DDP_ULP_MODE(x) (((x) >> S_DDP_ULP_MODE) & M_DDP_ULP_MODE) + +/* cpl_rx_data_ddp.ddp_report fields */ +#define S_DDP_OFFSET 0 +#define M_DDP_OFFSET 0x3FFFFF +#define V_DDP_OFFSET(x) ((x) << S_DDP_OFFSET) +#define G_DDP_OFFSET(x) (((x) >> S_DDP_OFFSET) & M_DDP_OFFSET) + +#define S_DDP_URG 24 +#define V_DDP_URG(x) ((x) << S_DDP_URG) +#define F_DDP_URG V_DDP_URG(1U) + +#define S_DDP_PSH 25 +#define V_DDP_PSH(x) ((x) << S_DDP_PSH) +#define F_DDP_PSH V_DDP_PSH(1U) + +#define S_DDP_BUF_COMPLETE 26 +#define V_DDP_BUF_COMPLETE(x) ((x) << S_DDP_BUF_COMPLETE) +#define F_DDP_BUF_COMPLETE V_DDP_BUF_COMPLETE(1U) + +#define S_DDP_BUF_TIMED_OUT 27 +#define V_DDP_BUF_TIMED_OUT(x) ((x) << S_DDP_BUF_TIMED_OUT) +#define F_DDP_BUF_TIMED_OUT V_DDP_BUF_TIMED_OUT(1U) + +#define S_DDP_BUF_IDX 28 +#define V_DDP_BUF_IDX(x) ((x) << S_DDP_BUF_IDX) +#define F_DDP_BUF_IDX V_DDP_BUF_IDX(1U) + +struct cpl_tx_pkt { + WR_HDR; + __be32 cntrl; + __be32 len; +}; + +struct cpl_tx_pkt_lso { + WR_HDR; + __be32 cntrl; + __be32 len; + + __be32 rsvd; + __be32 lso_info; +}; + +/* cpl_tx_pkt*.cntrl fields */ +#define S_TXPKT_VLAN 0 +#define M_TXPKT_VLAN 0xFFFF +#define V_TXPKT_VLAN(x) ((x) << S_TXPKT_VLAN) +#define G_TXPKT_VLAN(x) (((x) >> S_TXPKT_VLAN) & M_TXPKT_VLAN) + +#define S_TXPKT_INTF 16 +#define M_TXPKT_INTF 0xF +#define V_TXPKT_INTF(x) ((x) << S_TXPKT_INTF) +#define G_TXPKT_INTF(x) (((x) >> S_TXPKT_INTF) & M_TXPKT_INTF) + +#define S_TXPKT_IPCSUM_DIS 20 +#define V_TXPKT_IPCSUM_DIS(x) ((x) << S_TXPKT_IPCSUM_DIS) +#define F_TXPKT_IPCSUM_DIS V_TXPKT_IPCSUM_DIS(1U) + +#define S_TXPKT_L4CSUM_DIS 21 +#define V_TXPKT_L4CSUM_DIS(x) ((x) << S_TXPKT_L4CSUM_DIS) +#define F_TXPKT_L4CSUM_DIS V_TXPKT_L4CSUM_DIS(1U) + +#define S_TXPKT_VLAN_VLD 22 +#define V_TXPKT_VLAN_VLD(x) ((x) << S_TXPKT_VLAN_VLD) +#define F_TXPKT_VLAN_VLD V_TXPKT_VLAN_VLD(1U) + +#define S_TXPKT_LOOPBACK 23 +#define V_TXPKT_LOOPBACK(x) ((x) << S_TXPKT_LOOPBACK) +#define F_TXPKT_LOOPBACK V_TXPKT_LOOPBACK(1U) + +#define S_TXPKT_OPCODE 24 +#define M_TXPKT_OPCODE 0xFF +#define V_TXPKT_OPCODE(x) ((x) << S_TXPKT_OPCODE) +#define G_TXPKT_OPCODE(x) (((x) >> S_TXPKT_OPCODE) & M_TXPKT_OPCODE) + +/* cpl_tx_pkt_lso.lso_info fields */ +#define S_LSO_MSS 0 +#define M_LSO_MSS 0x3FFF +#define V_LSO_MSS(x) ((x) << S_LSO_MSS) +#define G_LSO_MSS(x) (((x) >> S_LSO_MSS) & M_LSO_MSS) + +#define S_LSO_ETH_TYPE 14 +#define M_LSO_ETH_TYPE 0x3 +#define V_LSO_ETH_TYPE(x) ((x) << S_LSO_ETH_TYPE) +#define G_LSO_ETH_TYPE(x) (((x) >> S_LSO_ETH_TYPE) & M_LSO_ETH_TYPE) + +#define S_LSO_TCPHDR_WORDS 16 +#define M_LSO_TCPHDR_WORDS 0xF +#define V_LSO_TCPHDR_WORDS(x) ((x) << S_LSO_TCPHDR_WORDS) +#define G_LSO_TCPHDR_WORDS(x) (((x) >> S_LSO_TCPHDR_WORDS) & M_LSO_TCPHDR_WORDS) + +#define S_LSO_IPHDR_WORDS 20 +#define M_LSO_IPHDR_WORDS 0xF +#define V_LSO_IPHDR_WORDS(x) ((x) << S_LSO_IPHDR_WORDS) +#define G_LSO_IPHDR_WORDS(x) (((x) >> S_LSO_IPHDR_WORDS) & M_LSO_IPHDR_WORDS) + +#define S_LSO_IPV6 24 +#define V_LSO_IPV6(x) ((x) << S_LSO_IPV6) +#define F_LSO_IPV6 V_LSO_IPV6(1U) + +struct cpl_trace_pkt { +#ifdef CHELSIO_FW + __u8 rss_opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 err:1; + __u8:7; +#else + __u8:7; + __u8 err:1; +#endif + __u8 rsvd0; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 qid:4; + __u8:4; +#else + __u8:4; + __u8 qid:4; +#endif + __be32 tstamp; +#endif /* CHELSIO_FW */ + + __u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 iff:4; + __u8:4; +#else + __u8:4; + __u8 iff:4; +#endif + __u8 rsvd[4]; + __be16 len; +}; + +struct cpl_rx_pkt { + RSS_HDR __u8 opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 iff:4; + __u8 csum_valid:1; + __u8 ipmi_pkt:1; + __u8 vlan_valid:1; + __u8 fragment:1; +#else + __u8 fragment:1; + __u8 vlan_valid:1; + __u8 ipmi_pkt:1; + __u8 csum_valid:1; + __u8 iff:4; +#endif + __be16 csum; + __be16 vlan; + __be16 len; +}; + +struct cpl_l2t_write_req { + WR_HDR; + union opcode_tid ot; + __be32 params; + __u8 rsvd[2]; + __u8 dst_mac[6]; +}; + +/* cpl_l2t_write_req.params fields */ +#define S_L2T_W_IDX 0 +#define M_L2T_W_IDX 0x7FF +#define V_L2T_W_IDX(x) ((x) << S_L2T_W_IDX) +#define G_L2T_W_IDX(x) (((x) >> S_L2T_W_IDX) & M_L2T_W_IDX) + +#define S_L2T_W_VLAN 11 +#define M_L2T_W_VLAN 0xFFF +#define V_L2T_W_VLAN(x) ((x) << S_L2T_W_VLAN) +#define G_L2T_W_VLAN(x) (((x) >> S_L2T_W_VLAN) & M_L2T_W_VLAN) + +#define S_L2T_W_IFF 23 +#define M_L2T_W_IFF 0xF +#define V_L2T_W_IFF(x) ((x) << S_L2T_W_IFF) +#define G_L2T_W_IFF(x) (((x) >> S_L2T_W_IFF) & M_L2T_W_IFF) + +#define S_L2T_W_PRIO 27 +#define M_L2T_W_PRIO 0x7 +#define V_L2T_W_PRIO(x) ((x) << S_L2T_W_PRIO) +#define G_L2T_W_PRIO(x) (((x) >> S_L2T_W_PRIO) & M_L2T_W_PRIO) + +struct cpl_l2t_write_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd[3]; +}; + +struct cpl_l2t_read_req { + WR_HDR; + union opcode_tid ot; + __be16 rsvd; + __be16 l2t_idx; +}; + +struct cpl_l2t_read_rpl { + RSS_HDR union opcode_tid ot; + __be32 params; + __u8 rsvd[2]; + __u8 dst_mac[6]; +}; + +/* cpl_l2t_read_rpl.params fields */ +#define S_L2T_R_PRIO 0 +#define M_L2T_R_PRIO 0x7 +#define V_L2T_R_PRIO(x) ((x) << S_L2T_R_PRIO) +#define G_L2T_R_PRIO(x) (((x) >> S_L2T_R_PRIO) & M_L2T_R_PRIO) + +#define S_L2T_R_VLAN 8 +#define M_L2T_R_VLAN 0xFFF +#define V_L2T_R_VLAN(x) ((x) << S_L2T_R_VLAN) +#define G_L2T_R_VLAN(x) (((x) >> S_L2T_R_VLAN) & M_L2T_R_VLAN) + +#define S_L2T_R_IFF 20 +#define M_L2T_R_IFF 0xF +#define V_L2T_R_IFF(x) ((x) << S_L2T_R_IFF) +#define G_L2T_R_IFF(x) (((x) >> S_L2T_R_IFF) & M_L2T_R_IFF) + +#define S_L2T_STATUS 24 +#define M_L2T_STATUS 0xFF +#define V_L2T_STATUS(x) ((x) << S_L2T_STATUS) +#define G_L2T_STATUS(x) (((x) >> S_L2T_STATUS) & M_L2T_STATUS) + +struct cpl_smt_write_req { + WR_HDR; + union opcode_tid ot; + __u8 rsvd0; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 mtu_idx:4; + __u8 iff:4; +#else + __u8 iff:4; + __u8 mtu_idx:4; +#endif + __be16 rsvd2; + __be16 rsvd3; + __u8 src_mac1[6]; + __be16 rsvd4; + __u8 src_mac0[6]; +}; + +struct cpl_smt_write_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd[3]; +}; + +struct cpl_smt_read_req { + WR_HDR; + union opcode_tid ot; + __u8 rsvd0; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:4; + __u8 iff:4; +#else + __u8 iff:4; + __u8:4; +#endif + __be16 rsvd2; +}; + +struct cpl_smt_read_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 mtu_idx:4; + __u8:4; +#else + __u8:4; + __u8 mtu_idx:4; +#endif + __be16 rsvd2; + __be16 rsvd3; + __u8 src_mac1[6]; + __be16 rsvd4; + __u8 src_mac0[6]; +}; + +struct cpl_rte_delete_req { + WR_HDR; + union opcode_tid ot; + __be32 params; +}; + +/* { cpl_rte_delete_req, cpl_rte_read_req }.params fields */ +#define S_RTE_REQ_LUT_IX 8 +#define M_RTE_REQ_LUT_IX 0x7FF +#define V_RTE_REQ_LUT_IX(x) ((x) << S_RTE_REQ_LUT_IX) +#define G_RTE_REQ_LUT_IX(x) (((x) >> S_RTE_REQ_LUT_IX) & M_RTE_REQ_LUT_IX) + +#define S_RTE_REQ_LUT_BASE 19 +#define M_RTE_REQ_LUT_BASE 0x7FF +#define V_RTE_REQ_LUT_BASE(x) ((x) << S_RTE_REQ_LUT_BASE) +#define G_RTE_REQ_LUT_BASE(x) (((x) >> S_RTE_REQ_LUT_BASE) & M_RTE_REQ_LUT_BASE) + +#define S_RTE_READ_REQ_SELECT 31 +#define V_RTE_READ_REQ_SELECT(x) ((x) << S_RTE_READ_REQ_SELECT) +#define F_RTE_READ_REQ_SELECT V_RTE_READ_REQ_SELECT(1U) + +struct cpl_rte_delete_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd[3]; +}; + +struct cpl_rte_write_req { + WR_HDR; + union opcode_tid ot; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:6; + __u8 write_tcam:1; + __u8 write_l2t_lut:1; +#else + __u8 write_l2t_lut:1; + __u8 write_tcam:1; + __u8:6; +#endif + __u8 rsvd[3]; + __be32 lut_params; + __be16 rsvd2; + __be16 l2t_idx; + __be32 netmask; + __be32 faddr; +}; + +/* cpl_rte_write_req.lut_params fields */ +#define S_RTE_WRITE_REQ_LUT_IX 10 +#define M_RTE_WRITE_REQ_LUT_IX 0x7FF +#define V_RTE_WRITE_REQ_LUT_IX(x) ((x) << S_RTE_WRITE_REQ_LUT_IX) +#define G_RTE_WRITE_REQ_LUT_IX(x) (((x) >> S_RTE_WRITE_REQ_LUT_IX) & M_RTE_WRITE_REQ_LUT_IX) + +#define S_RTE_WRITE_REQ_LUT_BASE 21 +#define M_RTE_WRITE_REQ_LUT_BASE 0x7FF +#define V_RTE_WRITE_REQ_LUT_BASE(x) ((x) << S_RTE_WRITE_REQ_LUT_BASE) +#define G_RTE_WRITE_REQ_LUT_BASE(x) (((x) >> S_RTE_WRITE_REQ_LUT_BASE) & M_RTE_WRITE_REQ_LUT_BASE) + +struct cpl_rte_write_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd[3]; +}; + +struct cpl_rte_read_req { + WR_HDR; + union opcode_tid ot; + __be32 params; +}; + +struct cpl_rte_read_rpl { + RSS_HDR union opcode_tid ot; + __u8 status; + __u8 rsvd0; + __be16 l2t_idx; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8:7; + __u8 select:1; +#else + __u8 select:1; + __u8:7; +#endif + __u8 rsvd2[3]; + __be32 addr; +}; + +struct cpl_tid_release { + WR_HDR; + union opcode_tid ot; + __be32 rsvd; +}; + +struct cpl_barrier { + WR_HDR; + __u8 opcode; + __u8 rsvd[7]; +}; + +struct cpl_rdma_read_req { + __u8 opcode; + __u8 rsvd[15]; +}; + +struct cpl_rdma_terminate { +#ifdef CHELSIO_FW + __u8 opcode; + __u8 rsvd[2]; +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 rspq:3; + __u8:5; +#else + __u8:5; + __u8 rspq:3; +#endif + __be32 tid_len; +#endif + __be32 msn; + __be32 mo; + __u8 data[0]; +}; + +/* cpl_rdma_terminate.tid_len fields */ +#define S_FLIT_CNT 0 +#define M_FLIT_CNT 0xFF +#define V_FLIT_CNT(x) ((x) << S_FLIT_CNT) +#define G_FLIT_CNT(x) (((x) >> S_FLIT_CNT) & M_FLIT_CNT) + +#define S_TERM_TID 8 +#define M_TERM_TID 0xFFFFF +#define V_TERM_TID(x) ((x) << S_TERM_TID) +#define G_TERM_TID(x) (((x) >> S_TERM_TID) & M_TERM_TID) +#endif /* T3_CPL_H */ diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c new file mode 100644 index 000000000000..365a7f5b1f94 --- /dev/null +++ b/drivers/net/cxgb3/t3_hw.c @@ -0,0 +1,3375 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" +#include "regs.h" +#include "sge_defs.h" +#include "firmware_exports.h" + +/** + * t3_wait_op_done_val - wait until an operation is completed + * @adapter: the adapter performing the operation + * @reg: the register to check for completion + * @mask: a single-bit field within @reg that indicates completion + * @polarity: the value of the field when the operation is completed + * @attempts: number of check iterations + * @delay: delay in usecs between iterations + * @valp: where to store the value of the register at completion time + * + * Wait until an operation is completed by checking a bit in a register + * up to @attempts times. If @valp is not NULL the value of the register + * at the time it indicated completion is stored there. Returns 0 if the + * operation completes and -EAGAIN otherwise. + */ + +int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, + int polarity, int attempts, int delay, u32 *valp) +{ + while (1) { + u32 val = t3_read_reg(adapter, reg); + + if (!!(val & mask) == polarity) { + if (valp) + *valp = val; + return 0; + } + if (--attempts == 0) + return -EAGAIN; + if (delay) + udelay(delay); + } +} + +/** + * t3_write_regs - write a bunch of registers + * @adapter: the adapter to program + * @p: an array of register address/register value pairs + * @n: the number of address/value pairs + * @offset: register address offset + * + * Takes an array of register address/register value pairs and writes each + * value to the corresponding register. Register addresses are adjusted + * by the supplied offset. + */ +void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p, + int n, unsigned int offset) +{ + while (n--) { + t3_write_reg(adapter, p->reg_addr + offset, p->val); + p++; + } +} + +/** + * t3_set_reg_field - set a register field to a value + * @adapter: the adapter to program + * @addr: the register address + * @mask: specifies the portion of the register to modify + * @val: the new value for the register field + * + * Sets a register field specified by the supplied mask to the + * given value. + */ +void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask, + u32 val) +{ + u32 v = t3_read_reg(adapter, addr) & ~mask; + + t3_write_reg(adapter, addr, v | val); + t3_read_reg(adapter, addr); /* flush */ +} + +/** + * t3_read_indirect - read indirectly addressed registers + * @adap: the adapter + * @addr_reg: register holding the indirect address + * @data_reg: register holding the value of the indirect register + * @vals: where the read register values are stored + * @start_idx: index of first indirect register to read + * @nregs: how many indirect registers to read + * + * Reads registers that are accessed indirectly through an address/data + * register pair. + */ +void t3_read_indirect(struct adapter *adap, unsigned int addr_reg, + unsigned int data_reg, u32 *vals, unsigned int nregs, + unsigned int start_idx) +{ + while (nregs--) { + t3_write_reg(adap, addr_reg, start_idx); + *vals++ = t3_read_reg(adap, data_reg); + start_idx++; + } +} + +/** + * t3_mc7_bd_read - read from MC7 through backdoor accesses + * @mc7: identifies MC7 to read from + * @start: index of first 64-bit word to read + * @n: number of 64-bit words to read + * @buf: where to store the read result + * + * Read n 64-bit words from MC7 starting at word start, using backdoor + * accesses. + */ +int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, + u64 *buf) +{ + static const int shift[] = { 0, 0, 16, 24 }; + static const int step[] = { 0, 32, 16, 8 }; + + unsigned int size64 = mc7->size / 8; /* # of 64-bit words */ + struct adapter *adap = mc7->adapter; + + if (start >= size64 || start + n > size64) + return -EINVAL; + + start *= (8 << mc7->width); + while (n--) { + int i; + u64 val64 = 0; + + for (i = (1 << mc7->width) - 1; i >= 0; --i) { + int attempts = 10; + u32 val; + + t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR, start); + t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0); + val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP); + while ((val & F_BUSY) && attempts--) + val = t3_read_reg(adap, + mc7->offset + A_MC7_BD_OP); + if (val & F_BUSY) + return -EIO; + + val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1); + if (mc7->width == 0) { + val64 = t3_read_reg(adap, + mc7->offset + + A_MC7_BD_DATA0); + val64 |= (u64) val << 32; + } else { + if (mc7->width > 1) + val >>= shift[mc7->width]; + val64 |= (u64) val << (step[mc7->width] * i); + } + start += 8; + } + *buf++ = val64; + } + return 0; +} + +/* + * Initialize MI1. + */ +static void mi1_init(struct adapter *adap, const struct adapter_info *ai) +{ + u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1; + u32 val = F_PREEN | V_MDIINV(ai->mdiinv) | V_MDIEN(ai->mdien) | + V_CLKDIV(clkdiv); + + if (!(ai->caps & SUPPORTED_10000baseT_Full)) + val |= V_ST(1); + t3_write_reg(adap, A_MI1_CFG, val); +} + +#define MDIO_ATTEMPTS 10 + +/* + * MI1 read/write operations for direct-addressed PHYs. + */ +static int mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int *valp) +{ + int ret; + u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); + + if (mmd_addr) + return -EINVAL; + + mutex_lock(&adapter->mdio_lock); + t3_write_reg(adapter, A_MI1_ADDR, addr); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + if (!ret) + *valp = t3_read_reg(adapter, A_MI1_DATA); + mutex_unlock(&adapter->mdio_lock); + return ret; +} + +static int mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int val) +{ + int ret; + u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr); + + if (mmd_addr) + return -EINVAL; + + mutex_lock(&adapter->mdio_lock); + t3_write_reg(adapter, A_MI1_ADDR, addr); + t3_write_reg(adapter, A_MI1_DATA, val); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + mutex_unlock(&adapter->mdio_lock); + return ret; +} + +static const struct mdio_ops mi1_mdio_ops = { + mi1_read, + mi1_write +}; + +/* + * MI1 read/write operations for indirect-addressed PHYs. + */ +static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int *valp) +{ + int ret; + u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); + + mutex_lock(&adapter->mdio_lock); + t3_write_reg(adapter, A_MI1_ADDR, addr); + t3_write_reg(adapter, A_MI1_DATA, reg_addr); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + if (!ret) { + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, + MDIO_ATTEMPTS, 20); + if (!ret) + *valp = t3_read_reg(adapter, A_MI1_DATA); + } + mutex_unlock(&adapter->mdio_lock); + return ret; +} + +static int mi1_ext_write(struct adapter *adapter, int phy_addr, int mmd_addr, + int reg_addr, unsigned int val) +{ + int ret; + u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr); + + mutex_lock(&adapter->mdio_lock); + t3_write_reg(adapter, A_MI1_ADDR, addr); + t3_write_reg(adapter, A_MI1_DATA, reg_addr); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20); + if (!ret) { + t3_write_reg(adapter, A_MI1_DATA, val); + t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1)); + ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, + MDIO_ATTEMPTS, 20); + } + mutex_unlock(&adapter->mdio_lock); + return ret; +} + +static const struct mdio_ops mi1_mdio_ext_ops = { + mi1_ext_read, + mi1_ext_write +}; + +/** + * t3_mdio_change_bits - modify the value of a PHY register + * @phy: the PHY to operate on + * @mmd: the device address + * @reg: the register address + * @clear: what part of the register value to mask off + * @set: what part of the register value to set + * + * Changes the value of a PHY register by applying a mask to its current + * value and ORing the result with a new value. + */ +int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear, + unsigned int set) +{ + int ret; + unsigned int val; + + ret = mdio_read(phy, mmd, reg, &val); + if (!ret) { + val &= ~clear; + ret = mdio_write(phy, mmd, reg, val | set); + } + return ret; +} + +/** + * t3_phy_reset - reset a PHY block + * @phy: the PHY to operate on + * @mmd: the device address of the PHY block to reset + * @wait: how long to wait for the reset to complete in 1ms increments + * + * Resets a PHY block and optionally waits for the reset to complete. + * @mmd should be 0 for 10/100/1000 PHYs and the device address to reset + * for 10G PHYs. + */ +int t3_phy_reset(struct cphy *phy, int mmd, int wait) +{ + int err; + unsigned int ctl; + + err = t3_mdio_change_bits(phy, mmd, MII_BMCR, BMCR_PDOWN, BMCR_RESET); + if (err || !wait) + return err; + + do { + err = mdio_read(phy, mmd, MII_BMCR, &ctl); + if (err) + return err; + ctl &= BMCR_RESET; + if (ctl) + msleep(1); + } while (ctl && --wait); + + return ctl ? -1 : 0; +} + +/** + * t3_phy_advertise - set the PHY advertisement registers for autoneg + * @phy: the PHY to operate on + * @advert: bitmap of capabilities the PHY should advertise + * + * Sets a 10/100/1000 PHY's advertisement registers to advertise the + * requested capabilities. + */ +int t3_phy_advertise(struct cphy *phy, unsigned int advert) +{ + int err; + unsigned int val = 0; + + err = mdio_read(phy, 0, MII_CTRL1000, &val); + if (err) + return err; + + val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); + if (advert & ADVERTISED_1000baseT_Half) + val |= ADVERTISE_1000HALF; + if (advert & ADVERTISED_1000baseT_Full) + val |= ADVERTISE_1000FULL; + + err = mdio_write(phy, 0, MII_CTRL1000, val); + if (err) + return err; + + val = 1; + if (advert & ADVERTISED_10baseT_Half) + val |= ADVERTISE_10HALF; + if (advert & ADVERTISED_10baseT_Full) + val |= ADVERTISE_10FULL; + if (advert & ADVERTISED_100baseT_Half) + val |= ADVERTISE_100HALF; + if (advert & ADVERTISED_100baseT_Full) + val |= ADVERTISE_100FULL; + if (advert & ADVERTISED_Pause) + val |= ADVERTISE_PAUSE_CAP; + if (advert & ADVERTISED_Asym_Pause) + val |= ADVERTISE_PAUSE_ASYM; + return mdio_write(phy, 0, MII_ADVERTISE, val); +} + +/** + * t3_set_phy_speed_duplex - force PHY speed and duplex + * @phy: the PHY to operate on + * @speed: requested PHY speed + * @duplex: requested PHY duplex + * + * Force a 10/100/1000 PHY's speed and duplex. This also disables + * auto-negotiation except for GigE, where auto-negotiation is mandatory. + */ +int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex) +{ + int err; + unsigned int ctl; + + err = mdio_read(phy, 0, MII_BMCR, &ctl); + if (err) + return err; + + if (speed >= 0) { + ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); + if (speed == SPEED_100) + ctl |= BMCR_SPEED100; + else if (speed == SPEED_1000) + ctl |= BMCR_SPEED1000; + } + if (duplex >= 0) { + ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE); + if (duplex == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + } + if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */ + ctl |= BMCR_ANENABLE; + return mdio_write(phy, 0, MII_BMCR, ctl); +} + +static const struct adapter_info t3_adap_info[] = { + {2, 0, 0, 0, + F_GPIO2_OEN | F_GPIO4_OEN | + F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5, + SUPPORTED_OFFLOAD, + &mi1_mdio_ops, "Chelsio PE9000"}, + {2, 0, 0, 0, + F_GPIO2_OEN | F_GPIO4_OEN | + F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5, + SUPPORTED_OFFLOAD, + &mi1_mdio_ops, "Chelsio T302"}, + {1, 0, 0, 0, + F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN | + F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD, + &mi1_mdio_ext_ops, "Chelsio T310"}, + {2, 0, 0, 0, + F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN | + F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL | + F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0, + SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD, + &mi1_mdio_ext_ops, "Chelsio T320"}, +}; + +/* + * Return the adapter_info structure with a given index. Out-of-range indices + * return NULL. + */ +const struct adapter_info *t3_get_adapter_info(unsigned int id) +{ + return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL; +} + +#define CAPS_1G (SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | \ + SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII) +#define CAPS_10G (SUPPORTED_10000baseT_Full | SUPPORTED_AUI) + +static const struct port_type_info port_types[] = { + {NULL}, + {t3_ael1002_phy_prep, CAPS_10G | SUPPORTED_FIBRE, + "10GBASE-XR"}, + {t3_vsc8211_phy_prep, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ, + "10/100/1000BASE-T"}, + {NULL, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ, + "10/100/1000BASE-T"}, + {t3_xaui_direct_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"}, + {NULL, CAPS_10G, "10GBASE-KX4"}, + {t3_qt2045_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"}, + {t3_ael1006_phy_prep, CAPS_10G | SUPPORTED_FIBRE, + "10GBASE-SR"}, + {NULL, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"}, +}; + +#undef CAPS_1G +#undef CAPS_10G + +#define VPD_ENTRY(name, len) \ + u8 name##_kword[2]; u8 name##_len; u8 name##_data[len] + +/* + * Partial EEPROM Vital Product Data structure. Includes only the ID and + * VPD-R sections. + */ +struct t3_vpd { + u8 id_tag; + u8 id_len[2]; + u8 id_data[16]; + u8 vpdr_tag; + u8 vpdr_len[2]; + VPD_ENTRY(pn, 16); /* part number */ + VPD_ENTRY(ec, 16); /* EC level */ + VPD_ENTRY(sn, 16); /* serial number */ + VPD_ENTRY(na, 12); /* MAC address base */ + VPD_ENTRY(cclk, 6); /* core clock */ + VPD_ENTRY(mclk, 6); /* mem clock */ + VPD_ENTRY(uclk, 6); /* uP clk */ + VPD_ENTRY(mdc, 6); /* MDIO clk */ + VPD_ENTRY(mt, 2); /* mem timing */ + VPD_ENTRY(xaui0cfg, 6); /* XAUI0 config */ + VPD_ENTRY(xaui1cfg, 6); /* XAUI1 config */ + VPD_ENTRY(port0, 2); /* PHY0 complex */ + VPD_ENTRY(port1, 2); /* PHY1 complex */ + VPD_ENTRY(port2, 2); /* PHY2 complex */ + VPD_ENTRY(port3, 2); /* PHY3 complex */ + VPD_ENTRY(rv, 1); /* csum */ + u32 pad; /* for multiple-of-4 sizing and alignment */ +}; + +#define EEPROM_MAX_POLL 4 +#define EEPROM_STAT_ADDR 0x4000 +#define VPD_BASE 0xc00 + +/** + * t3_seeprom_read - read a VPD EEPROM location + * @adapter: adapter to read + * @addr: EEPROM address + * @data: where to store the read data + * + * Read a 32-bit word from a location in VPD EEPROM using the card's PCI + * VPD ROM capability. A zero is written to the flag bit when the + * addres is written to the control register. The hardware device will + * set the flag to 1 when 4 bytes have been read into the data register. + */ +int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data) +{ + u16 val; + int attempts = EEPROM_MAX_POLL; + unsigned int base = adapter->params.pci.vpd_cap_addr; + + if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3)) + return -EINVAL; + + pci_write_config_word(adapter->pdev, base + PCI_VPD_ADDR, addr); + do { + udelay(10); + pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val); + } while (!(val & PCI_VPD_ADDR_F) && --attempts); + + if (!(val & PCI_VPD_ADDR_F)) { + CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr); + return -EIO; + } + pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, data); + *data = le32_to_cpu(*data); + return 0; +} + +/** + * t3_seeprom_write - write a VPD EEPROM location + * @adapter: adapter to write + * @addr: EEPROM address + * @data: value to write + * + * Write a 32-bit word to a location in VPD EEPROM using the card's PCI + * VPD ROM capability. + */ +int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data) +{ + u16 val; + int attempts = EEPROM_MAX_POLL; + unsigned int base = adapter->params.pci.vpd_cap_addr; + + if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3)) + return -EINVAL; + + pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA, + cpu_to_le32(data)); + pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR, + addr | PCI_VPD_ADDR_F); + do { + msleep(1); + pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val); + } while ((val & PCI_VPD_ADDR_F) && --attempts); + + if (val & PCI_VPD_ADDR_F) { + CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr); + return -EIO; + } + return 0; +} + +/** + * t3_seeprom_wp - enable/disable EEPROM write protection + * @adapter: the adapter + * @enable: 1 to enable write protection, 0 to disable it + * + * Enables or disables write protection on the serial EEPROM. + */ +int t3_seeprom_wp(struct adapter *adapter, int enable) +{ + return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0); +} + +/* + * Convert a character holding a hex digit to a number. + */ +static unsigned int hex2int(unsigned char c) +{ + return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10; +} + +/** + * get_vpd_params - read VPD parameters from VPD EEPROM + * @adapter: adapter to read + * @p: where to store the parameters + * + * Reads card parameters stored in VPD EEPROM. + */ +static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) +{ + int i, addr, ret; + struct t3_vpd vpd; + + /* + * Card information is normally at VPD_BASE but some early cards had + * it at 0. + */ + ret = t3_seeprom_read(adapter, VPD_BASE, (u32 *)&vpd); + if (ret) + return ret; + addr = vpd.id_tag == 0x82 ? VPD_BASE : 0; + + for (i = 0; i < sizeof(vpd); i += 4) { + ret = t3_seeprom_read(adapter, addr + i, + (u32 *)((u8 *)&vpd + i)); + if (ret) + return ret; + } + + p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10); + p->mclk = simple_strtoul(vpd.mclk_data, NULL, 10); + p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10); + p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10); + p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10); + + /* Old eeproms didn't have port information */ + if (adapter->params.rev == 0 && !vpd.port0_data[0]) { + p->port_type[0] = uses_xaui(adapter) ? 1 : 2; + p->port_type[1] = uses_xaui(adapter) ? 6 : 2; + } else { + p->port_type[0] = hex2int(vpd.port0_data[0]); + p->port_type[1] = hex2int(vpd.port1_data[0]); + p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16); + p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16); + } + + for (i = 0; i < 6; i++) + p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 + + hex2int(vpd.na_data[2 * i + 1]); + return 0; +} + +/* serial flash and firmware constants */ +enum { + SF_ATTEMPTS = 5, /* max retries for SF1 operations */ + SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */ + SF_SIZE = SF_SEC_SIZE * 8, /* serial flash size */ + + /* flash command opcodes */ + SF_PROG_PAGE = 2, /* program page */ + SF_WR_DISABLE = 4, /* disable writes */ + SF_RD_STATUS = 5, /* read status register */ + SF_WR_ENABLE = 6, /* enable writes */ + SF_RD_DATA_FAST = 0xb, /* read flash */ + SF_ERASE_SECTOR = 0xd8, /* erase sector */ + + FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */ + FW_VERS_ADDR = 0x77ffc /* flash address holding FW version */ +}; + +/** + * sf1_read - read data from the serial flash + * @adapter: the adapter + * @byte_cnt: number of bytes to read + * @cont: whether another operation will be chained + * @valp: where to store the read data + * + * Reads up to 4 bytes of data from the serial flash. The location of + * the read needs to be specified prior to calling this by issuing the + * appropriate commands to the serial flash. + */ +static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont, + u32 *valp) +{ + int ret; + + if (!byte_cnt || byte_cnt > 4) + return -EINVAL; + if (t3_read_reg(adapter, A_SF_OP) & F_BUSY) + return -EBUSY; + t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1)); + ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10); + if (!ret) + *valp = t3_read_reg(adapter, A_SF_DATA); + return ret; +} + +/** + * sf1_write - write data to the serial flash + * @adapter: the adapter + * @byte_cnt: number of bytes to write + * @cont: whether another operation will be chained + * @val: value to write + * + * Writes up to 4 bytes of data to the serial flash. The location of + * the write needs to be specified prior to calling this by issuing the + * appropriate commands to the serial flash. + */ +static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont, + u32 val) +{ + if (!byte_cnt || byte_cnt > 4) + return -EINVAL; + if (t3_read_reg(adapter, A_SF_OP) & F_BUSY) + return -EBUSY; + t3_write_reg(adapter, A_SF_DATA, val); + t3_write_reg(adapter, A_SF_OP, + V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1)); + return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10); +} + +/** + * flash_wait_op - wait for a flash operation to complete + * @adapter: the adapter + * @attempts: max number of polls of the status register + * @delay: delay between polls in ms + * + * Wait for a flash operation to complete by polling the status register. + */ +static int flash_wait_op(struct adapter *adapter, int attempts, int delay) +{ + int ret; + u32 status; + + while (1) { + if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 || + (ret = sf1_read(adapter, 1, 0, &status)) != 0) + return ret; + if (!(status & 1)) + return 0; + if (--attempts == 0) + return -EAGAIN; + if (delay) + msleep(delay); + } +} + +/** + * t3_read_flash - read words from serial flash + * @adapter: the adapter + * @addr: the start address for the read + * @nwords: how many 32-bit words to read + * @data: where to store the read data + * @byte_oriented: whether to store data as bytes or as words + * + * Read the specified number of 32-bit words from the serial flash. + * If @byte_oriented is set the read data is stored as a byte array + * (i.e., big-endian), otherwise as 32-bit words in the platform's + * natural endianess. + */ +int t3_read_flash(struct adapter *adapter, unsigned int addr, + unsigned int nwords, u32 *data, int byte_oriented) +{ + int ret; + + if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3)) + return -EINVAL; + + addr = swab32(addr) | SF_RD_DATA_FAST; + + if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 || + (ret = sf1_read(adapter, 1, 1, data)) != 0) + return ret; + + for (; nwords; nwords--, data++) { + ret = sf1_read(adapter, 4, nwords > 1, data); + if (ret) + return ret; + if (byte_oriented) + *data = htonl(*data); + } + return 0; +} + +/** + * t3_write_flash - write up to a page of data to the serial flash + * @adapter: the adapter + * @addr: the start address to write + * @n: length of data to write + * @data: the data to write + * + * Writes up to a page of data (256 bytes) to the serial flash starting + * at the given address. + */ +static int t3_write_flash(struct adapter *adapter, unsigned int addr, + unsigned int n, const u8 *data) +{ + int ret; + u32 buf[64]; + unsigned int i, c, left, val, offset = addr & 0xff; + + if (addr + n > SF_SIZE || offset + n > 256) + return -EINVAL; + + val = swab32(addr) | SF_PROG_PAGE; + + if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 || + (ret = sf1_write(adapter, 4, 1, val)) != 0) + return ret; + + for (left = n; left; left -= c) { + c = min(left, 4U); + for (val = 0, i = 0; i < c; ++i) + val = (val << 8) + *data++; + + ret = sf1_write(adapter, c, c != left, val); + if (ret) + return ret; + } + if ((ret = flash_wait_op(adapter, 5, 1)) != 0) + return ret; + + /* Read the page to verify the write succeeded */ + ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1); + if (ret) + return ret; + + if (memcmp(data - n, (u8 *) buf + offset, n)) + return -EIO; + return 0; +} + +enum fw_version_type { + FW_VERSION_N3, + FW_VERSION_T3 +}; + +/** + * t3_get_fw_version - read the firmware version + * @adapter: the adapter + * @vers: where to place the version + * + * Reads the FW version from flash. + */ +int t3_get_fw_version(struct adapter *adapter, u32 *vers) +{ + return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0); +} + +/** + * t3_check_fw_version - check if the FW is compatible with this driver + * @adapter: the adapter + * + * Checks if an adapter's FW is compatible with the driver. Returns 0 + * if the versions are compatible, a negative error otherwise. + */ +int t3_check_fw_version(struct adapter *adapter) +{ + int ret; + u32 vers; + unsigned int type, major, minor; + + ret = t3_get_fw_version(adapter, &vers); + if (ret) + return ret; + + type = G_FW_VERSION_TYPE(vers); + major = G_FW_VERSION_MAJOR(vers); + minor = G_FW_VERSION_MINOR(vers); + + if (type == FW_VERSION_T3 && major == 3 && minor == 1) + return 0; + + CH_ERR(adapter, "found wrong FW version(%u.%u), " + "driver needs version 3.1\n", major, minor); + return -EINVAL; +} + +/** + * t3_flash_erase_sectors - erase a range of flash sectors + * @adapter: the adapter + * @start: the first sector to erase + * @end: the last sector to erase + * + * Erases the sectors in the given range. + */ +static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end) +{ + while (start <= end) { + int ret; + + if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 || + (ret = sf1_write(adapter, 4, 0, + SF_ERASE_SECTOR | (start << 8))) != 0 || + (ret = flash_wait_op(adapter, 5, 500)) != 0) + return ret; + start++; + } + return 0; +} + +/* + * t3_load_fw - download firmware + * @adapter: the adapter + * @fw_data: the firrware image to write + * @size: image size + * + * Write the supplied firmware image to the card's serial flash. + * The FW image has the following sections: @size - 8 bytes of code and + * data, followed by 4 bytes of FW version, followed by the 32-bit + * 1's complement checksum of the whole image. + */ +int t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size) +{ + u32 csum; + unsigned int i; + const u32 *p = (const u32 *)fw_data; + int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16; + + if (size & 3) + return -EINVAL; + if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR) + return -EFBIG; + + for (csum = 0, i = 0; i < size / sizeof(csum); i++) + csum += ntohl(p[i]); + if (csum != 0xffffffff) { + CH_ERR(adapter, "corrupted firmware image, checksum %u\n", + csum); + return -EINVAL; + } + + ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector); + if (ret) + goto out; + + size -= 8; /* trim off version and checksum */ + for (addr = FW_FLASH_BOOT_ADDR; size;) { + unsigned int chunk_size = min(size, 256U); + + ret = t3_write_flash(adapter, addr, chunk_size, fw_data); + if (ret) + goto out; + + addr += chunk_size; + fw_data += chunk_size; + size -= chunk_size; + } + + ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data); +out: + if (ret) + CH_ERR(adapter, "firmware download failed, error %d\n", ret); + return ret; +} + +#define CIM_CTL_BASE 0x2000 + +/** + * t3_cim_ctl_blk_read - read a block from CIM control region + * + * @adap: the adapter + * @addr: the start address within the CIM control region + * @n: number of words to read + * @valp: where to store the result + * + * Reads a block of 4-byte words from the CIM control region. + */ +int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr, + unsigned int n, unsigned int *valp) +{ + int ret = 0; + + if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY) + return -EBUSY; + + for ( ; !ret && n--; addr += 4) { + t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr); + ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY, + 0, 5, 2); + if (!ret) + *valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA); + } + return ret; +} + + +/** + * t3_link_changed - handle interface link changes + * @adapter: the adapter + * @port_id: the port index that changed link state + * + * Called when a port's link settings change to propagate the new values + * to the associated PHY and MAC. After performing the common tasks it + * invokes an OS-specific handler. + */ +void t3_link_changed(struct adapter *adapter, int port_id) +{ + int link_ok, speed, duplex, fc; + struct port_info *pi = adap2pinfo(adapter, port_id); + struct cphy *phy = &pi->phy; + struct cmac *mac = &pi->mac; + struct link_config *lc = &pi->link_config; + + phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); + + if (link_ok != lc->link_ok && adapter->params.rev > 0 && + uses_xaui(adapter)) { + if (link_ok) + t3b_pcs_reset(mac); + t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, + link_ok ? F_TXACTENABLE | F_RXEN : 0); + } + lc->link_ok = link_ok; + lc->speed = speed < 0 ? SPEED_INVALID : speed; + lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex; + if (lc->requested_fc & PAUSE_AUTONEG) + fc &= lc->requested_fc; + else + fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + + if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) { + /* Set MAC speed, duplex, and flow control to match PHY. */ + t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc); + lc->fc = fc; + } + + t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc); +} + +/** + * t3_link_start - apply link configuration to MAC/PHY + * @phy: the PHY to setup + * @mac: the MAC to setup + * @lc: the requested link configuration + * + * Set up a port's MAC and PHY according to a desired link configuration. + * - If the PHY can auto-negotiate first decide what to advertise, then + * enable/disable auto-negotiation as desired, and reset. + * - If the PHY does not auto-negotiate just reset it. + * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC, + * otherwise do it later based on the outcome of auto-negotiation. + */ +int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc) +{ + unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX); + + lc->link_ok = 0; + if (lc->supported & SUPPORTED_Autoneg) { + lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause); + if (fc) { + lc->advertising |= ADVERTISED_Asym_Pause; + if (fc & PAUSE_RX) + lc->advertising |= ADVERTISED_Pause; + } + phy->ops->advertise(phy, lc->advertising); + + if (lc->autoneg == AUTONEG_DISABLE) { + lc->speed = lc->requested_speed; + lc->duplex = lc->requested_duplex; + lc->fc = (unsigned char)fc; + t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex, + fc); + /* Also disables autoneg */ + phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex); + phy->ops->reset(phy, 0); + } else + phy->ops->autoneg_enable(phy); + } else { + t3_mac_set_speed_duplex_fc(mac, -1, -1, fc); + lc->fc = (unsigned char)fc; + phy->ops->reset(phy, 0); + } + return 0; +} + +/** + * t3_set_vlan_accel - control HW VLAN extraction + * @adapter: the adapter + * @ports: bitmap of adapter ports to operate on + * @on: enable (1) or disable (0) HW VLAN extraction + * + * Enables or disables HW extraction of VLAN tags for the given port. + */ +void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on) +{ + t3_set_reg_field(adapter, A_TP_OUT_CONFIG, + ports << S_VLANEXTRACTIONENABLE, + on ? (ports << S_VLANEXTRACTIONENABLE) : 0); +} + +struct intr_info { + unsigned int mask; /* bits to check in interrupt status */ + const char *msg; /* message to print or NULL */ + short stat_idx; /* stat counter to increment or -1 */ + unsigned short fatal:1; /* whether the condition reported is fatal */ +}; + +/** + * t3_handle_intr_status - table driven interrupt handler + * @adapter: the adapter that generated the interrupt + * @reg: the interrupt status register to process + * @mask: a mask to apply to the interrupt status + * @acts: table of interrupt actions + * @stats: statistics counters tracking interrupt occurences + * + * A table driven interrupt handler that applies a set of masks to an + * interrupt status word and performs the corresponding actions if the + * interrupts described by the mask have occured. The actions include + * optionally printing a warning or alert message, and optionally + * incrementing a stat counter. The table is terminated by an entry + * specifying mask 0. Returns the number of fatal interrupt conditions. + */ +static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg, + unsigned int mask, + const struct intr_info *acts, + unsigned long *stats) +{ + int fatal = 0; + unsigned int status = t3_read_reg(adapter, reg) & mask; + + for (; acts->mask; ++acts) { + if (!(status & acts->mask)) + continue; + if (acts->fatal) { + fatal++; + CH_ALERT(adapter, "%s (0x%x)\n", + acts->msg, status & acts->mask); + } else if (acts->msg) + CH_WARN(adapter, "%s (0x%x)\n", + acts->msg, status & acts->mask); + if (acts->stat_idx >= 0) + stats[acts->stat_idx]++; + } + if (status) /* clear processed interrupts */ + t3_write_reg(adapter, reg, status); + return fatal; +} + +#define SGE_INTR_MASK (F_RSPQDISABLED) +#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \ + F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \ + F_NFASRCHFAIL) +#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE)) +#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ + V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \ + F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW) +#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \ + F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \ + F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \ + F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \ + V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \ + V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */) +#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\ + F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \ + /* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \ + V_BISTERR(M_BISTERR) | F_PEXERR) +#define ULPRX_INTR_MASK F_PARERR +#define ULPTX_INTR_MASK 0 +#define CPLSW_INTR_MASK (F_TP_FRAMING_ERROR | \ + F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \ + F_ZERO_SWITCH_ERROR) +#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \ + F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \ + F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \ + F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT) +#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \ + V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \ + V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR)) +#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \ + V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \ + V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR)) +#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \ + V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \ + V_RXTPPARERRENB(M_RXTPPARERRENB) | \ + V_MCAPARERRENB(M_MCAPARERRENB)) +#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \ + F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \ + F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \ + F_MPS0 | F_CPL_SWITCH) + +/* + * Interrupt handler for the PCIX1 module. + */ +static void pci_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pcix1_intr_info[] = { + {F_MSTDETPARERR, "PCI master detected parity error", -1, 1}, + {F_SIGTARABT, "PCI signaled target abort", -1, 1}, + {F_RCVTARABT, "PCI received target abort", -1, 1}, + {F_RCVMSTABT, "PCI received master abort", -1, 1}, + {F_SIGSYSERR, "PCI signaled system error", -1, 1}, + {F_DETPARERR, "PCI detected parity error", -1, 1}, + {F_SPLCMPDIS, "PCI split completion discarded", -1, 1}, + {F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1}, + {F_RCVSPLCMPERR, "PCI received split completion error", -1, + 1}, + {F_DETCORECCERR, "PCI correctable ECC error", + STAT_PCI_CORR_ECC, 0}, + {F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1}, + {F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1}, + {V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1, + 1}, + {V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1, + 1}, + {V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1, + 1}, + {V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity " + "error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK, + pcix1_intr_info, adapter->irq_stats)) + t3_fatal_err(adapter); +} + +/* + * Interrupt handler for the PCIE module. + */ +static void pcie_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pcie_intr_info[] = { + {F_PEXERR, "PCI PEX error", -1, 1}, + {F_UNXSPLCPLERRR, + "PCI unexpected split completion DMA read error", -1, 1}, + {F_UNXSPLCPLERRC, + "PCI unexpected split completion DMA command error", -1, 1}, + {F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1}, + {F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1}, + {F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1}, + {F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1}, + {V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR), + "PCI MSI-X table/PBA parity error", -1, 1}, + {V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK, + pcie_intr_info, adapter->irq_stats)) + t3_fatal_err(adapter); +} + +/* + * TP interrupt handler. + */ +static void tp_intr_handler(struct adapter *adapter) +{ + static const struct intr_info tp_intr_info[] = { + {0xffffff, "TP parity error", -1, 1}, + {0x1000000, "TP out of Rx pages", -1, 1}, + {0x2000000, "TP out of Tx pages", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff, + tp_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * CIM interrupt handler. + */ +static void cim_intr_handler(struct adapter *adapter) +{ + static const struct intr_info cim_intr_info[] = { + {F_RSVDSPACEINT, "CIM reserved space write", -1, 1}, + {F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1}, + {F_FLASHRANGEINT, "CIM flash address out of range", -1, 1}, + {F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1}, + {F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1}, + {F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1}, + {F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1}, + {F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1}, + {F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1}, + {F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1}, + {F_BLKRDPLINT, "CIM block read from PL space", -1, 1}, + {F_BLKWRPLINT, "CIM block write to PL space", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, 0xffffffff, + cim_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * ULP RX interrupt handler. + */ +static void ulprx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info ulprx_intr_info[] = { + {F_PARERR, "ULP RX parity error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff, + ulprx_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * ULP TX interrupt handler. + */ +static void ulptx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info ulptx_intr_info[] = { + {F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds", + STAT_ULP_CH0_PBL_OOB, 0}, + {F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds", + STAT_ULP_CH1_PBL_OOB, 0}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff, + ulptx_intr_info, adapter->irq_stats)) + t3_fatal_err(adapter); +} + +#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \ + F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \ + F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \ + F_ICSPI1_TX_FRAMING_ERROR) +#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \ + F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \ + F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \ + F_OESPI1_OFIFO2X_TX_FRAMING_ERROR) + +/* + * PM TX interrupt handler. + */ +static void pmtx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pmtx_intr_info[] = { + {F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1}, + {ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1}, + {OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1}, + {V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR), + "PMTX ispi parity error", -1, 1}, + {V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR), + "PMTX ospi parity error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff, + pmtx_intr_info, NULL)) + t3_fatal_err(adapter); +} + +#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \ + F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \ + F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \ + F_IESPI1_TX_FRAMING_ERROR) +#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \ + F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \ + F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \ + F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR) + +/* + * PM RX interrupt handler. + */ +static void pmrx_intr_handler(struct adapter *adapter) +{ + static const struct intr_info pmrx_intr_info[] = { + {F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1}, + {IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1}, + {OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1}, + {V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR), + "PMRX ispi parity error", -1, 1}, + {V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR), + "PMRX ospi parity error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff, + pmrx_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * CPL switch interrupt handler. + */ +static void cplsw_intr_handler(struct adapter *adapter) +{ + static const struct intr_info cplsw_intr_info[] = { +/* { F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 }, */ + {F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1}, + {F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1}, + {F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1}, + {F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff, + cplsw_intr_info, NULL)) + t3_fatal_err(adapter); +} + +/* + * MPS interrupt handler. + */ +static void mps_intr_handler(struct adapter *adapter) +{ + static const struct intr_info mps_intr_info[] = { + {0x1ff, "MPS parity error", -1, 1}, + {0} + }; + + if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff, + mps_intr_info, NULL)) + t3_fatal_err(adapter); +} + +#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE) + +/* + * MC7 interrupt handler. + */ +static void mc7_intr_handler(struct mc7 *mc7) +{ + struct adapter *adapter = mc7->adapter; + u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE); + + if (cause & F_CE) { + mc7->stats.corr_err++; + CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, " + "data 0x%x 0x%x 0x%x\n", mc7->name, + t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR), + t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0), + t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1), + t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2)); + } + + if (cause & F_UE) { + mc7->stats.uncorr_err++; + CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, " + "data 0x%x 0x%x 0x%x\n", mc7->name, + t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR), + t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0), + t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1), + t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2)); + } + + if (G_PE(cause)) { + mc7->stats.parity_err++; + CH_ALERT(adapter, "%s MC7 parity error 0x%x\n", + mc7->name, G_PE(cause)); + } + + if (cause & F_AE) { + u32 addr = 0; + + if (adapter->params.rev > 0) + addr = t3_read_reg(adapter, + mc7->offset + A_MC7_ERR_ADDR); + mc7->stats.addr_err++; + CH_ALERT(adapter, "%s MC7 address error: 0x%x\n", + mc7->name, addr); + } + + if (cause & MC7_INTR_FATAL) + t3_fatal_err(adapter); + + t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause); +} + +#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \ + V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) +/* + * XGMAC interrupt handler. + */ +static int mac_intr_handler(struct adapter *adap, unsigned int idx) +{ + struct cmac *mac = &adap2pinfo(adap, idx)->mac; + u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset); + + if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) { + mac->stats.tx_fifo_parity_err++; + CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx); + } + if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) { + mac->stats.rx_fifo_parity_err++; + CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx); + } + if (cause & F_TXFIFO_UNDERRUN) + mac->stats.tx_fifo_urun++; + if (cause & F_RXFIFO_OVERFLOW) + mac->stats.rx_fifo_ovfl++; + if (cause & V_SERDES_LOS(M_SERDES_LOS)) + mac->stats.serdes_signal_loss++; + if (cause & F_XAUIPCSCTCERR) + mac->stats.xaui_pcs_ctc_err++; + if (cause & F_XAUIPCSALIGNCHANGE) + mac->stats.xaui_pcs_align_change++; + + t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause); + if (cause & XGM_INTR_FATAL) + t3_fatal_err(adap); + return cause != 0; +} + +/* + * Interrupt handler for PHY events. + */ +int t3_phy_intr_handler(struct adapter *adapter) +{ + static const int intr_gpio_bits[] = { 8, 0x20 }; + + u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE); + + for_each_port(adapter, i) { + if (cause & intr_gpio_bits[i]) { + struct cphy *phy = &adap2pinfo(adapter, i)->phy; + int phy_cause = phy->ops->intr_handler(phy); + + if (phy_cause & cphy_cause_link_change) + t3_link_changed(adapter, i); + if (phy_cause & cphy_cause_fifo_error) + phy->fifo_errors++; + } + } + + t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause); + return 0; +} + +/* + * T3 slow path (non-data) interrupt handler. + */ +int t3_slow_intr_handler(struct adapter *adapter) +{ + u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0); + + cause &= adapter->slow_intr_mask; + if (!cause) + return 0; + if (cause & F_PCIM0) { + if (is_pcie(adapter)) + pcie_intr_handler(adapter); + else + pci_intr_handler(adapter); + } + if (cause & F_SGE3) + t3_sge_err_intr_handler(adapter); + if (cause & F_MC7_PMRX) + mc7_intr_handler(&adapter->pmrx); + if (cause & F_MC7_PMTX) + mc7_intr_handler(&adapter->pmtx); + if (cause & F_MC7_CM) + mc7_intr_handler(&adapter->cm); + if (cause & F_CIM) + cim_intr_handler(adapter); + if (cause & F_TP1) + tp_intr_handler(adapter); + if (cause & F_ULP2_RX) + ulprx_intr_handler(adapter); + if (cause & F_ULP2_TX) + ulptx_intr_handler(adapter); + if (cause & F_PM1_RX) + pmrx_intr_handler(adapter); + if (cause & F_PM1_TX) + pmtx_intr_handler(adapter); + if (cause & F_CPL_SWITCH) + cplsw_intr_handler(adapter); + if (cause & F_MPS0) + mps_intr_handler(adapter); + if (cause & F_MC5A) + t3_mc5_intr_handler(&adapter->mc5); + if (cause & F_XGMAC0_0) + mac_intr_handler(adapter, 0); + if (cause & F_XGMAC0_1) + mac_intr_handler(adapter, 1); + if (cause & F_T3DBG) + t3_os_ext_intr_handler(adapter); + + /* Clear the interrupts just processed. */ + t3_write_reg(adapter, A_PL_INT_CAUSE0, cause); + t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ + return 1; +} + +/** + * t3_intr_enable - enable interrupts + * @adapter: the adapter whose interrupts should be enabled + * + * Enable interrupts by setting the interrupt enable registers of the + * various HW modules and then enabling the top-level interrupt + * concentrator. + */ +void t3_intr_enable(struct adapter *adapter) +{ + static const struct addr_val_pair intr_en_avp[] = { + {A_SG_INT_ENABLE, SGE_INTR_MASK}, + {A_MC7_INT_ENABLE, MC7_INTR_MASK}, + {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, + MC7_INTR_MASK}, + {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, + MC7_INTR_MASK}, + {A_MC5_DB_INT_ENABLE, MC5_INTR_MASK}, + {A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK}, + {A_TP_INT_ENABLE, 0x3bfffff}, + {A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK}, + {A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK}, + {A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK}, + {A_MPS_INT_ENABLE, MPS_INTR_MASK}, + }; + + adapter->slow_intr_mask = PL_INTR_MASK; + + t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0); + + if (adapter->params.rev > 0) { + t3_write_reg(adapter, A_CPL_INTR_ENABLE, + CPLSW_INTR_MASK | F_CIM_OVFL_ERROR); + t3_write_reg(adapter, A_ULPTX_INT_ENABLE, + ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 | + F_PBL_BOUND_ERR_CH1); + } else { + t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK); + t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK); + } + + t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, + adapter_info(adapter)->gpio_intr); + t3_write_reg(adapter, A_T3DBG_INT_ENABLE, + adapter_info(adapter)->gpio_intr); + if (is_pcie(adapter)) + t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK); + else + t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK); + t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask); + t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ +} + +/** + * t3_intr_disable - disable a card's interrupts + * @adapter: the adapter whose interrupts should be disabled + * + * Disable interrupts. We only disable the top-level interrupt + * concentrator and the SGE data interrupts. + */ +void t3_intr_disable(struct adapter *adapter) +{ + t3_write_reg(adapter, A_PL_INT_ENABLE0, 0); + t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */ + adapter->slow_intr_mask = 0; +} + +/** + * t3_intr_clear - clear all interrupts + * @adapter: the adapter whose interrupts should be cleared + * + * Clears all interrupts. + */ +void t3_intr_clear(struct adapter *adapter) +{ + static const unsigned int cause_reg_addr[] = { + A_SG_INT_CAUSE, + A_SG_RSPQ_FL_STATUS, + A_PCIX_INT_CAUSE, + A_MC7_INT_CAUSE, + A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR, + A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR, + A_CIM_HOST_INT_CAUSE, + A_TP_INT_CAUSE, + A_MC5_DB_INT_CAUSE, + A_ULPRX_INT_CAUSE, + A_ULPTX_INT_CAUSE, + A_CPL_INTR_CAUSE, + A_PM1_TX_INT_CAUSE, + A_PM1_RX_INT_CAUSE, + A_MPS_INT_CAUSE, + A_T3DBG_INT_CAUSE, + }; + unsigned int i; + + /* Clear PHY and MAC interrupts for each port. */ + for_each_port(adapter, i) + t3_port_intr_clear(adapter, i); + + for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i) + t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff); + + t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff); + t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */ +} + +/** + * t3_port_intr_enable - enable port-specific interrupts + * @adapter: associated adapter + * @idx: index of port whose interrupts should be enabled + * + * Enable port-specific (i.e., MAC and PHY) interrupts for the given + * adapter port. + */ +void t3_port_intr_enable(struct adapter *adapter, int idx) +{ + struct cphy *phy = &adap2pinfo(adapter, idx)->phy; + + t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), XGM_INTR_MASK); + t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */ + phy->ops->intr_enable(phy); +} + +/** + * t3_port_intr_disable - disable port-specific interrupts + * @adapter: associated adapter + * @idx: index of port whose interrupts should be disabled + * + * Disable port-specific (i.e., MAC and PHY) interrupts for the given + * adapter port. + */ +void t3_port_intr_disable(struct adapter *adapter, int idx) +{ + struct cphy *phy = &adap2pinfo(adapter, idx)->phy; + + t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), 0); + t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */ + phy->ops->intr_disable(phy); +} + +/** + * t3_port_intr_clear - clear port-specific interrupts + * @adapter: associated adapter + * @idx: index of port whose interrupts to clear + * + * Clear port-specific (i.e., MAC and PHY) interrupts for the given + * adapter port. + */ +void t3_port_intr_clear(struct adapter *adapter, int idx) +{ + struct cphy *phy = &adap2pinfo(adapter, idx)->phy; + + t3_write_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx), 0xffffffff); + t3_read_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx)); /* flush */ + phy->ops->intr_clear(phy); +} + +/** + * t3_sge_write_context - write an SGE context + * @adapter: the adapter + * @id: the context id + * @type: the context type + * + * Program an SGE context with the values already loaded in the + * CONTEXT_DATA? registers. + */ +static int t3_sge_write_context(struct adapter *adapter, unsigned int id, + unsigned int type) +{ + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, 5, 1); +} + +/** + * t3_sge_init_ecntxt - initialize an SGE egress context + * @adapter: the adapter to configure + * @id: the context id + * @gts_enable: whether to enable GTS for the context + * @type: the egress context type + * @respq: associated response queue + * @base_addr: base address of queue + * @size: number of queue entries + * @token: uP token + * @gen: initial generation value for the context + * @cidx: consumer pointer + * + * Initialize an SGE egress context and make it ready for use. If the + * platform allows concurrent context operations, the caller is + * responsible for appropriate locking. + */ +int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable, + enum sge_context_type type, int respq, u64 base_addr, + unsigned int size, unsigned int token, int gen, + unsigned int cidx) +{ + unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM; + + if (base_addr & 0xfff) /* must be 4K aligned */ + return -EINVAL; + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + base_addr >>= 12; + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) | + V_EC_CREDITS(credits) | V_EC_GTS(gts_enable)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) | + V_EC_BASE_LO(base_addr & 0xffff)); + base_addr >>= 16; + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, base_addr); + base_addr >>= 32; + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, + V_EC_BASE_HI(base_addr & 0xf) | V_EC_RESPQ(respq) | + V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) | + F_EC_VALID); + return t3_sge_write_context(adapter, id, F_EGRESS); +} + +/** + * t3_sge_init_flcntxt - initialize an SGE free-buffer list context + * @adapter: the adapter to configure + * @id: the context id + * @gts_enable: whether to enable GTS for the context + * @base_addr: base address of queue + * @size: number of queue entries + * @bsize: size of each buffer for this queue + * @cong_thres: threshold to signal congestion to upstream producers + * @gen: initial generation value for the context + * @cidx: consumer pointer + * + * Initialize an SGE free list context and make it ready for use. The + * caller is responsible for ensuring only one context operation occurs + * at a time. + */ +int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id, + int gts_enable, u64 base_addr, unsigned int size, + unsigned int bsize, unsigned int cong_thres, int gen, + unsigned int cidx) +{ + if (base_addr & 0xfff) /* must be 4K aligned */ + return -EINVAL; + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + base_addr >>= 12; + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, base_addr); + base_addr >>= 32; + t3_write_reg(adapter, A_SG_CONTEXT_DATA1, + V_FL_BASE_HI((u32) base_addr) | + V_FL_INDEX_LO(cidx & M_FL_INDEX_LO)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) | + V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) | + V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, + V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) | + V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable)); + return t3_sge_write_context(adapter, id, F_FREELIST); +} + +/** + * t3_sge_init_rspcntxt - initialize an SGE response queue context + * @adapter: the adapter to configure + * @id: the context id + * @irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ + * @base_addr: base address of queue + * @size: number of queue entries + * @fl_thres: threshold for selecting the normal or jumbo free list + * @gen: initial generation value for the context + * @cidx: consumer pointer + * + * Initialize an SGE response queue context and make it ready for use. + * The caller is responsible for ensuring only one context operation + * occurs at a time. + */ +int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id, + int irq_vec_idx, u64 base_addr, unsigned int size, + unsigned int fl_thres, int gen, unsigned int cidx) +{ + unsigned int intr = 0; + + if (base_addr & 0xfff) /* must be 4K aligned */ + return -EINVAL; + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + base_addr >>= 12; + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) | + V_CQ_INDEX(cidx)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr); + base_addr >>= 32; + if (irq_vec_idx >= 0) + intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN; + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, + V_CQ_BASE_HI((u32) base_addr) | intr | V_RQ_GEN(gen)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres); + return t3_sge_write_context(adapter, id, F_RESPONSEQ); +} + +/** + * t3_sge_init_cqcntxt - initialize an SGE completion queue context + * @adapter: the adapter to configure + * @id: the context id + * @base_addr: base address of queue + * @size: number of queue entries + * @rspq: response queue for async notifications + * @ovfl_mode: CQ overflow mode + * @credits: completion queue credits + * @credit_thres: the credit threshold + * + * Initialize an SGE completion queue context and make it ready for use. + * The caller is responsible for ensuring only one context operation + * occurs at a time. + */ +int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr, + unsigned int size, int rspq, int ovfl_mode, + unsigned int credits, unsigned int credit_thres) +{ + if (base_addr & 0xfff) /* must be 4K aligned */ + return -EINVAL; + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + base_addr >>= 12; + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr); + base_addr >>= 32; + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, + V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) | + V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode)); + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) | + V_CQ_CREDIT_THRES(credit_thres)); + return t3_sge_write_context(adapter, id, F_CQ); +} + +/** + * t3_sge_enable_ecntxt - enable/disable an SGE egress context + * @adapter: the adapter + * @id: the egress context id + * @enable: enable (1) or disable (0) the context + * + * Enable or disable an SGE egress context. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID); + t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable)); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, 5, 1); +} + +/** + * t3_sge_disable_fl - disable an SGE free-buffer list + * @adapter: the adapter + * @id: the free list context id + * + * Disable an SGE free-buffer list. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_disable_fl(struct adapter *adapter, unsigned int id) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE)); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); + t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, 5, 1); +} + +/** + * t3_sge_disable_rspcntxt - disable an SGE response queue + * @adapter: the adapter + * @id: the response queue context id + * + * Disable an SGE response queue. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, 5, 1); +} + +/** + * t3_sge_disable_cqcntxt - disable an SGE completion queue + * @adapter: the adapter + * @id: the completion queue context id + * + * Disable an SGE completion queue. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE)); + t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0); + t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0); + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id)); + return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, 5, 1); +} + +/** + * t3_sge_cqcntxt_op - perform an operation on a completion queue context + * @adapter: the adapter + * @id: the context id + * @op: the operation to perform + * + * Perform the selected operation on an SGE completion queue context. + * The caller is responsible for ensuring only one context operation + * occurs at a time. + */ +int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op, + unsigned int credits) +{ + u32 val; + + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16); + t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) | + V_CONTEXT(id) | F_CQ); + if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, + 0, 5, 1, &val)) + return -EIO; + + if (op >= 2 && op < 7) { + if (adapter->params.rev > 0) + return G_CQ_INDEX(val); + + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id)); + if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, + F_CONTEXT_CMD_BUSY, 0, 5, 1)) + return -EIO; + return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0)); + } + return 0; +} + +/** + * t3_sge_read_context - read an SGE context + * @type: the context type + * @adapter: the adapter + * @id: the context id + * @data: holds the retrieved context + * + * Read an SGE egress context. The caller is responsible for ensuring + * only one context operation occurs at a time. + */ +static int t3_sge_read_context(unsigned int type, struct adapter *adapter, + unsigned int id, u32 data[4]) +{ + if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + t3_write_reg(adapter, A_SG_CONTEXT_CMD, + V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id)); + if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0, + 5, 1)) + return -EIO; + data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0); + data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1); + data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2); + data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3); + return 0; +} + +/** + * t3_sge_read_ecntxt - read an SGE egress context + * @adapter: the adapter + * @id: the context id + * @data: holds the retrieved context + * + * Read an SGE egress context. The caller is responsible for ensuring + * only one context operation occurs at a time. + */ +int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4]) +{ + if (id >= 65536) + return -EINVAL; + return t3_sge_read_context(F_EGRESS, adapter, id, data); +} + +/** + * t3_sge_read_cq - read an SGE CQ context + * @adapter: the adapter + * @id: the context id + * @data: holds the retrieved context + * + * Read an SGE CQ context. The caller is responsible for ensuring + * only one context operation occurs at a time. + */ +int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4]) +{ + if (id >= 65536) + return -EINVAL; + return t3_sge_read_context(F_CQ, adapter, id, data); +} + +/** + * t3_sge_read_fl - read an SGE free-list context + * @adapter: the adapter + * @id: the context id + * @data: holds the retrieved context + * + * Read an SGE free-list context. The caller is responsible for ensuring + * only one context operation occurs at a time. + */ +int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4]) +{ + if (id >= SGE_QSETS * 2) + return -EINVAL; + return t3_sge_read_context(F_FREELIST, adapter, id, data); +} + +/** + * t3_sge_read_rspq - read an SGE response queue context + * @adapter: the adapter + * @id: the context id + * @data: holds the retrieved context + * + * Read an SGE response queue context. The caller is responsible for + * ensuring only one context operation occurs at a time. + */ +int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4]) +{ + if (id >= SGE_QSETS) + return -EINVAL; + return t3_sge_read_context(F_RESPONSEQ, adapter, id, data); +} + +/** + * t3_config_rss - configure Rx packet steering + * @adapter: the adapter + * @rss_config: RSS settings (written to TP_RSS_CONFIG) + * @cpus: values for the CPU lookup table (0xff terminated) + * @rspq: values for the response queue lookup table (0xffff terminated) + * + * Programs the receive packet steering logic. @cpus and @rspq provide + * the values for the CPU and response queue lookup tables. If they + * provide fewer values than the size of the tables the supplied values + * are used repeatedly until the tables are fully populated. + */ +void t3_config_rss(struct adapter *adapter, unsigned int rss_config, + const u8 * cpus, const u16 *rspq) +{ + int i, j, cpu_idx = 0, q_idx = 0; + + if (cpus) + for (i = 0; i < RSS_TABLE_SIZE; ++i) { + u32 val = i << 16; + + for (j = 0; j < 2; ++j) { + val |= (cpus[cpu_idx++] & 0x3f) << (8 * j); + if (cpus[cpu_idx] == 0xff) + cpu_idx = 0; + } + t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val); + } + + if (rspq) + for (i = 0; i < RSS_TABLE_SIZE; ++i) { + t3_write_reg(adapter, A_TP_RSS_MAP_TABLE, + (i << 16) | rspq[q_idx++]); + if (rspq[q_idx] == 0xffff) + q_idx = 0; + } + + t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config); +} + +/** + * t3_read_rss - read the contents of the RSS tables + * @adapter: the adapter + * @lkup: holds the contents of the RSS lookup table + * @map: holds the contents of the RSS map table + * + * Reads the contents of the receive packet steering tables. + */ +int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map) +{ + int i; + u32 val; + + if (lkup) + for (i = 0; i < RSS_TABLE_SIZE; ++i) { + t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, + 0xffff0000 | i); + val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE); + if (!(val & 0x80000000)) + return -EAGAIN; + *lkup++ = val; + *lkup++ = (val >> 8); + } + + if (map) + for (i = 0; i < RSS_TABLE_SIZE; ++i) { + t3_write_reg(adapter, A_TP_RSS_MAP_TABLE, + 0xffff0000 | i); + val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE); + if (!(val & 0x80000000)) + return -EAGAIN; + *map++ = val; + } + return 0; +} + +/** + * t3_tp_set_offload_mode - put TP in NIC/offload mode + * @adap: the adapter + * @enable: 1 to select offload mode, 0 for regular NIC + * + * Switches TP to NIC/offload mode. + */ +void t3_tp_set_offload_mode(struct adapter *adap, int enable) +{ + if (is_offload(adap) || !enable) + t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, + V_NICMODE(!enable)); +} + +/** + * pm_num_pages - calculate the number of pages of the payload memory + * @mem_size: the size of the payload memory + * @pg_size: the size of each payload memory page + * + * Calculate the number of pages, each of the given size, that fit in a + * memory of the specified size, respecting the HW requirement that the + * number of pages must be a multiple of 24. + */ +static inline unsigned int pm_num_pages(unsigned int mem_size, + unsigned int pg_size) +{ + unsigned int n = mem_size / pg_size; + + return n - n % 24; +} + +#define mem_region(adap, start, size, reg) \ + t3_write_reg((adap), A_ ## reg, (start)); \ + start += size + +/* + * partition_mem - partition memory and configure TP memory settings + * @adap: the adapter + * @p: the TP parameters + * + * Partitions context and payload memory and configures TP's memory + * registers. + */ +static void partition_mem(struct adapter *adap, const struct tp_params *p) +{ + unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5); + unsigned int timers = 0, timers_shift = 22; + + if (adap->params.rev > 0) { + if (tids <= 16 * 1024) { + timers = 1; + timers_shift = 16; + } else if (tids <= 64 * 1024) { + timers = 2; + timers_shift = 18; + } else if (tids <= 256 * 1024) { + timers = 3; + timers_shift = 20; + } + } + + t3_write_reg(adap, A_TP_PMM_SIZE, + p->chan_rx_size | (p->chan_tx_size >> 16)); + + t3_write_reg(adap, A_TP_PMM_TX_BASE, 0); + t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size); + t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs); + t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX), + V_TXDATAACKIDX(fls(p->tx_pg_size) - 12)); + + t3_write_reg(adap, A_TP_PMM_RX_BASE, 0); + t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size); + t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs); + + pstructs = p->rx_num_pgs + p->tx_num_pgs; + /* Add a bit of headroom and make multiple of 24 */ + pstructs += 48; + pstructs -= pstructs % 24; + t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs); + + m = tids * TCB_SIZE; + mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR); + mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR); + t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m); + m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22); + mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE); + mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE); + mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE); + mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE); + + m = (m + 4095) & ~0xfff; + t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m); + t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m); + + tids = (p->cm_size - m - (3 << 20)) / 3072 - 32; + m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers - + adap->params.mc5.nfilters - adap->params.mc5.nroutes; + if (tids < m) + adap->params.mc5.nservers += m - tids; +} + +static inline void tp_wr_indirect(struct adapter *adap, unsigned int addr, + u32 val) +{ + t3_write_reg(adap, A_TP_PIO_ADDR, addr); + t3_write_reg(adap, A_TP_PIO_DATA, val); +} + +static void tp_config(struct adapter *adap, const struct tp_params *p) +{ + t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU | + F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD | + F_TCPCHECKSUMOFFLOAD | V_IPTTL(64)); + t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) | + F_MTUENABLE | V_WINDOWSCALEMODE(1) | + V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1)); + t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) | + V_AUTOSTATE2(1) | V_AUTOSTATE1(0) | + V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) | + F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1)); + t3_set_reg_field(adap, A_TP_IN_CONFIG, F_IPV6ENABLE | F_NICMODE, + F_IPV6ENABLE | F_NICMODE); + t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814); + t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105); + t3_set_reg_field(adap, A_TP_PARA_REG6, + adap->params.rev > 0 ? F_ENABLEESND : F_T3A_ENABLEESND, + 0); + + t3_set_reg_field(adap, A_TP_PC_CONFIG, + F_ENABLEEPCMDAFULL | F_ENABLEOCSPIFULL, + F_TXDEFERENABLE | F_HEARBEATDACK | F_TXCONGESTIONMODE | + F_RXCONGESTIONMODE); + t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 0); + + if (adap->params.rev > 0) { + tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE); + t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO, + F_TXPACEAUTO); + t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID); + t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEAUTOSTRICT); + } else + t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED); + + t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0x12121212); + t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0x12121212); + t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0x1212); +} + +/* Desired TP timer resolution in usec */ +#define TP_TMR_RES 50 + +/* TCP timer values in ms */ +#define TP_DACK_TIMER 50 +#define TP_RTO_MIN 250 + +/** + * tp_set_timers - set TP timing parameters + * @adap: the adapter to set + * @core_clk: the core clock frequency in Hz + * + * Set TP's timing parameters, such as the various timer resolutions and + * the TCP timer values. + */ +static void tp_set_timers(struct adapter *adap, unsigned int core_clk) +{ + unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1; + unsigned int dack_re = fls(core_clk / 5000) - 1; /* 200us */ + unsigned int tstamp_re = fls(core_clk / 1000); /* 1ms, at least */ + unsigned int tps = core_clk >> tre; + + t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) | + V_DELAYEDACKRESOLUTION(dack_re) | + V_TIMESTAMPRESOLUTION(tstamp_re)); + t3_write_reg(adap, A_TP_DACK_TIMER, + (core_clk >> dack_re) / (1000 / TP_DACK_TIMER)); + t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100); + t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504); + t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908); + t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c); + t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) | + V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) | + V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) | + V_KEEPALIVEMAX(9)); + +#define SECONDS * tps + + t3_write_reg(adap, A_TP_MSL, adap->params.rev > 0 ? 0 : 2 SECONDS); + t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN)); + t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS); + t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS); + t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS); + t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS); + t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS); + t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS); + t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS); + +#undef SECONDS +} + +/** + * t3_tp_set_coalescing_size - set receive coalescing size + * @adap: the adapter + * @size: the receive coalescing size + * @psh: whether a set PSH bit should deliver coalesced data + * + * Set the receive coalescing size and PSH bit handling. + */ +int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh) +{ + u32 val; + + if (size > MAX_RX_COALESCING_LEN) + return -EINVAL; + + val = t3_read_reg(adap, A_TP_PARA_REG3); + val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN); + + if (size) { + val |= F_RXCOALESCEENABLE; + if (psh) + val |= F_RXCOALESCEPSHEN; + t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) | + V_MAXRXDATA(MAX_RX_COALESCING_LEN)); + } + t3_write_reg(adap, A_TP_PARA_REG3, val); + return 0; +} + +/** + * t3_tp_set_max_rxsize - set the max receive size + * @adap: the adapter + * @size: the max receive size + * + * Set TP's max receive size. This is the limit that applies when + * receive coalescing is disabled. + */ +void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size) +{ + t3_write_reg(adap, A_TP_PARA_REG7, + V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size)); +} + +static void __devinit init_mtus(unsigned short mtus[]) +{ + /* + * See draft-mathis-plpmtud-00.txt for the values. The min is 88 so + * it can accomodate max size TCP/IP headers when SACK and timestamps + * are enabled and still have at least 8 bytes of payload. + */ + mtus[0] = 88; + mtus[1] = 256; + mtus[2] = 512; + mtus[3] = 576; + mtus[4] = 808; + mtus[5] = 1024; + mtus[6] = 1280; + mtus[7] = 1492; + mtus[8] = 1500; + mtus[9] = 2002; + mtus[10] = 2048; + mtus[11] = 4096; + mtus[12] = 4352; + mtus[13] = 8192; + mtus[14] = 9000; + mtus[15] = 9600; +} + +/* + * Initial congestion control parameters. + */ +static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b) +{ + a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1; + a[9] = 2; + a[10] = 3; + a[11] = 4; + a[12] = 5; + a[13] = 6; + a[14] = 7; + a[15] = 8; + a[16] = 9; + a[17] = 10; + a[18] = 14; + a[19] = 17; + a[20] = 21; + a[21] = 25; + a[22] = 30; + a[23] = 35; + a[24] = 45; + a[25] = 60; + a[26] = 80; + a[27] = 100; + a[28] = 200; + a[29] = 300; + a[30] = 400; + a[31] = 500; + + b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0; + b[9] = b[10] = 1; + b[11] = b[12] = 2; + b[13] = b[14] = b[15] = b[16] = 3; + b[17] = b[18] = b[19] = b[20] = b[21] = 4; + b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5; + b[28] = b[29] = 6; + b[30] = b[31] = 7; +} + +/* The minimum additive increment value for the congestion control table */ +#define CC_MIN_INCR 2U + +/** + * t3_load_mtus - write the MTU and congestion control HW tables + * @adap: the adapter + * @mtus: the unrestricted values for the MTU table + * @alphs: the values for the congestion control alpha parameter + * @beta: the values for the congestion control beta parameter + * @mtu_cap: the maximum permitted effective MTU + * + * Write the MTU table with the supplied MTUs capping each at &mtu_cap. + * Update the high-speed congestion control table with the supplied alpha, + * beta, and MTUs. + */ +void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS], + unsigned short alpha[NCCTRL_WIN], + unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap) +{ + static const unsigned int avg_pkts[NCCTRL_WIN] = { + 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640, + 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480, + 28672, 40960, 57344, 81920, 114688, 163840, 229376 + }; + + unsigned int i, w; + + for (i = 0; i < NMTUS; ++i) { + unsigned int mtu = min(mtus[i], mtu_cap); + unsigned int log2 = fls(mtu); + + if (!(mtu & ((1 << log2) >> 2))) /* round */ + log2--; + t3_write_reg(adap, A_TP_MTU_TABLE, + (i << 24) | (log2 << 16) | mtu); + + for (w = 0; w < NCCTRL_WIN; ++w) { + unsigned int inc; + + inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w], + CC_MIN_INCR); + + t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) | + (w << 16) | (beta[w] << 13) | inc); + } + } +} + +/** + * t3_read_hw_mtus - returns the values in the HW MTU table + * @adap: the adapter + * @mtus: where to store the HW MTU values + * + * Reads the HW MTU table. + */ +void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS]) +{ + int i; + + for (i = 0; i < NMTUS; ++i) { + unsigned int val; + + t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i); + val = t3_read_reg(adap, A_TP_MTU_TABLE); + mtus[i] = val & 0x3fff; + } +} + +/** + * t3_get_cong_cntl_tab - reads the congestion control table + * @adap: the adapter + * @incr: where to store the alpha values + * + * Reads the additive increments programmed into the HW congestion + * control table. + */ +void t3_get_cong_cntl_tab(struct adapter *adap, + unsigned short incr[NMTUS][NCCTRL_WIN]) +{ + unsigned int mtu, w; + + for (mtu = 0; mtu < NMTUS; ++mtu) + for (w = 0; w < NCCTRL_WIN; ++w) { + t3_write_reg(adap, A_TP_CCTRL_TABLE, + 0xffff0000 | (mtu << 5) | w); + incr[mtu][w] = t3_read_reg(adap, A_TP_CCTRL_TABLE) & + 0x1fff; + } +} + +/** + * t3_tp_get_mib_stats - read TP's MIB counters + * @adap: the adapter + * @tps: holds the returned counter values + * + * Returns the values of TP's MIB counters. + */ +void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps) +{ + t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *) tps, + sizeof(*tps) / sizeof(u32), 0); +} + +#define ulp_region(adap, name, start, len) \ + t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \ + t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \ + (start) + (len) - 1); \ + start += len + +#define ulptx_region(adap, name, start, len) \ + t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \ + t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \ + (start) + (len) - 1) + +static void ulp_config(struct adapter *adap, const struct tp_params *p) +{ + unsigned int m = p->chan_rx_size; + + ulp_region(adap, ISCSI, m, p->chan_rx_size / 8); + ulp_region(adap, TDDP, m, p->chan_rx_size / 8); + ulptx_region(adap, TPT, m, p->chan_rx_size / 4); + ulp_region(adap, STAG, m, p->chan_rx_size / 4); + ulp_region(adap, RQ, m, p->chan_rx_size / 4); + ulptx_region(adap, PBL, m, p->chan_rx_size / 4); + ulp_region(adap, PBL, m, p->chan_rx_size / 4); + t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff); +} + +void t3_config_trace_filter(struct adapter *adapter, + const struct trace_params *tp, int filter_index, + int invert, int enable) +{ + u32 addr, key[4], mask[4]; + + key[0] = tp->sport | (tp->sip << 16); + key[1] = (tp->sip >> 16) | (tp->dport << 16); + key[2] = tp->dip; + key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20); + + mask[0] = tp->sport_mask | (tp->sip_mask << 16); + mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16); + mask[2] = tp->dip_mask; + mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20); + + if (invert) + key[3] |= (1 << 29); + if (enable) + key[3] |= (1 << 28); + + addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0; + tp_wr_indirect(adapter, addr++, key[0]); + tp_wr_indirect(adapter, addr++, mask[0]); + tp_wr_indirect(adapter, addr++, key[1]); + tp_wr_indirect(adapter, addr++, mask[1]); + tp_wr_indirect(adapter, addr++, key[2]); + tp_wr_indirect(adapter, addr++, mask[2]); + tp_wr_indirect(adapter, addr++, key[3]); + tp_wr_indirect(adapter, addr, mask[3]); + t3_read_reg(adapter, A_TP_PIO_DATA); +} + +/** + * t3_config_sched - configure a HW traffic scheduler + * @adap: the adapter + * @kbps: target rate in Kbps + * @sched: the scheduler index + * + * Configure a HW scheduler for the target rate + */ +int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched) +{ + unsigned int v, tps, cpt, bpt, delta, mindelta = ~0; + unsigned int clk = adap->params.vpd.cclk * 1000; + unsigned int selected_cpt = 0, selected_bpt = 0; + + if (kbps > 0) { + kbps *= 125; /* -> bytes */ + for (cpt = 1; cpt <= 255; cpt++) { + tps = clk / cpt; + bpt = (kbps + tps / 2) / tps; + if (bpt > 0 && bpt <= 255) { + v = bpt * tps; + delta = v >= kbps ? v - kbps : kbps - v; + if (delta <= mindelta) { + mindelta = delta; + selected_cpt = cpt; + selected_bpt = bpt; + } + } else if (selected_cpt) + break; + } + if (!selected_cpt) + return -EINVAL; + } + t3_write_reg(adap, A_TP_TM_PIO_ADDR, + A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2); + v = t3_read_reg(adap, A_TP_TM_PIO_DATA); + if (sched & 1) + v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24); + else + v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8); + t3_write_reg(adap, A_TP_TM_PIO_DATA, v); + return 0; +} + +static int tp_init(struct adapter *adap, const struct tp_params *p) +{ + int busy = 0; + + tp_config(adap, p); + t3_set_vlan_accel(adap, 3, 0); + + if (is_offload(adap)) { + tp_set_timers(adap, adap->params.vpd.cclk * 1000); + t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE); + busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE, + 0, 1000, 5); + if (busy) + CH_ERR(adap, "TP initialization timed out\n"); + } + + if (!busy) + t3_write_reg(adap, A_TP_RESET, F_TPRESET); + return busy; +} + +int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask) +{ + if (port_mask & ~((1 << adap->params.nports) - 1)) + return -EINVAL; + t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE, + port_mask << S_PORT0ACTIVE); + return 0; +} + +/* + * Perform the bits of HW initialization that are dependent on the number + * of available ports. + */ +static void init_hw_for_avail_ports(struct adapter *adap, int nports) +{ + int i; + + if (nports == 1) { + t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0); + t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0); + t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_TPTXPORT0EN | + F_PORT0ACTIVE | F_ENFORCEPKT); + t3_write_reg(adap, A_PM1_TX_CFG, 0xc000c000); + } else { + t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN); + t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB); + t3_write_reg(adap, A_ULPTX_DMA_WEIGHT, + V_D1_WEIGHT(16) | V_D0_WEIGHT(16)); + t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN | + F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE | + F_ENFORCEPKT); + t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000); + t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE); + t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP, + V_TX_MOD_QUEUE_REQ_MAP(0xaa)); + for (i = 0; i < 16; i++) + t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, + (i << 16) | 0x1010); + } +} + +static int calibrate_xgm(struct adapter *adapter) +{ + if (uses_xaui(adapter)) { + unsigned int v, i; + + for (i = 0; i < 5; ++i) { + t3_write_reg(adapter, A_XGM_XAUI_IMP, 0); + t3_read_reg(adapter, A_XGM_XAUI_IMP); + msleep(1); + v = t3_read_reg(adapter, A_XGM_XAUI_IMP); + if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) { + t3_write_reg(adapter, A_XGM_XAUI_IMP, + V_XAUIIMP(G_CALIMP(v) >> 2)); + return 0; + } + } + CH_ERR(adapter, "MAC calibration failed\n"); + return -1; + } else { + t3_write_reg(adapter, A_XGM_RGMII_IMP, + V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, + F_XGM_IMPSETUPDATE); + } + return 0; +} + +static void calibrate_xgm_t3b(struct adapter *adapter) +{ + if (!uses_xaui(adapter)) { + t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET | + F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3)); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, + F_XGM_IMPSETUPDATE); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE, + 0); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0); + t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE); + } +} + +struct mc7_timing_params { + unsigned char ActToPreDly; + unsigned char ActToRdWrDly; + unsigned char PreCyc; + unsigned char RefCyc[5]; + unsigned char BkCyc; + unsigned char WrToRdDly; + unsigned char RdToWrDly; +}; + +/* + * Write a value to a register and check that the write completed. These + * writes normally complete in a cycle or two, so one read should suffice. + * The very first read exists to flush the posted write to the device. + */ +static int wrreg_wait(struct adapter *adapter, unsigned int addr, u32 val) +{ + t3_write_reg(adapter, addr, val); + t3_read_reg(adapter, addr); /* flush */ + if (!(t3_read_reg(adapter, addr) & F_BUSY)) + return 0; + CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr); + return -EIO; +} + +static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type) +{ + static const unsigned int mc7_mode[] = { + 0x632, 0x642, 0x652, 0x432, 0x442 + }; + static const struct mc7_timing_params mc7_timings[] = { + {12, 3, 4, {20, 28, 34, 52, 0}, 15, 6, 4}, + {12, 4, 5, {20, 28, 34, 52, 0}, 16, 7, 4}, + {12, 5, 6, {20, 28, 34, 52, 0}, 17, 8, 4}, + {9, 3, 4, {15, 21, 26, 39, 0}, 12, 6, 4}, + {9, 4, 5, {15, 21, 26, 39, 0}, 13, 7, 4} + }; + + u32 val; + unsigned int width, density, slow, attempts; + struct adapter *adapter = mc7->adapter; + const struct mc7_timing_params *p = &mc7_timings[mem_type]; + + val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); + slow = val & F_SLOW; + width = G_WIDTH(val); + density = G_DEN(val); + + t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN); + val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ + msleep(1); + + if (!slow) { + t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN); + t3_read_reg(adapter, mc7->offset + A_MC7_CAL); + msleep(1); + if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) & + (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) { + CH_ERR(adapter, "%s MC7 calibration timed out\n", + mc7->name); + goto out_fail; + } + } + + t3_write_reg(adapter, mc7->offset + A_MC7_PARM, + V_ACTTOPREDLY(p->ActToPreDly) | + V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) | + V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) | + V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly)); + + t3_write_reg(adapter, mc7->offset + A_MC7_CFG, + val | F_CLKEN | F_TERM150); + t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */ + + if (!slow) + t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB, + F_DLLENB); + udelay(1); + + val = slow ? 3 : 6; + if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) + goto out_fail; + + if (!slow) { + t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100); + t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLRST, 0); + udelay(5); + } + + if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) || + wrreg_wait(adapter, mc7->offset + A_MC7_MODE, + mc7_mode[mem_type]) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) || + wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val)) + goto out_fail; + + /* clock value is in KHz */ + mc7_clock = mc7_clock * 7812 + mc7_clock / 2; /* ns */ + mc7_clock /= 1000000; /* KHz->MHz, ns->us */ + + t3_write_reg(adapter, mc7->offset + A_MC7_REF, + F_PERREFEN | V_PREREFDIV(mc7_clock)); + t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */ + + t3_write_reg(adapter, mc7->offset + A_MC7_ECC, F_ECCGENEN | F_ECCCHKEN); + t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0); + t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0); + t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END, + (mc7->size << width) - 1); + t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1)); + t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */ + + attempts = 50; + do { + msleep(250); + val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); + } while ((val & F_BUSY) && --attempts); + if (val & F_BUSY) { + CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name); + goto out_fail; + } + + /* Enable normal memory accesses. */ + t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY); + return 0; + +out_fail: + return -1; +} + +static void config_pcie(struct adapter *adap) +{ + static const u16 ack_lat[4][6] = { + {237, 416, 559, 1071, 2095, 4143}, + {128, 217, 289, 545, 1057, 2081}, + {73, 118, 154, 282, 538, 1050}, + {67, 107, 86, 150, 278, 534} + }; + static const u16 rpl_tmr[4][6] = { + {711, 1248, 1677, 3213, 6285, 12429}, + {384, 651, 867, 1635, 3171, 6243}, + {219, 354, 462, 846, 1614, 3150}, + {201, 321, 258, 450, 834, 1602} + }; + + u16 val; + unsigned int log2_width, pldsize; + unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt; + + pci_read_config_word(adap->pdev, + adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL, + &val); + pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5; + pci_read_config_word(adap->pdev, + adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL, + &val); + + fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0)); + fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx : + G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE)); + log2_width = fls(adap->params.pci.width) - 1; + acklat = ack_lat[log2_width][pldsize]; + if (val & 1) /* check LOsEnable */ + acklat += fst_trn_tx * 4; + rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4; + + if (adap->params.rev == 0) + t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, + V_T3A_ACKLAT(M_T3A_ACKLAT), + V_T3A_ACKLAT(acklat)); + else + t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT), + V_ACKLAT(acklat)); + + t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT), + V_REPLAYLMT(rpllmt)); + + t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff); + t3_set_reg_field(adap, A_PCIE_CFG, F_PCIE_CLIDECEN, F_PCIE_CLIDECEN); +} + +/* + * Initialize and configure T3 HW modules. This performs the + * initialization steps that need to be done once after a card is reset. + * MAC and PHY initialization is handled separarely whenever a port is enabled. + * + * fw_params are passed to FW and their value is platform dependent. Only the + * top 8 bits are available for use, the rest must be 0. + */ +int t3_init_hw(struct adapter *adapter, u32 fw_params) +{ + int err = -EIO, attempts = 100; + const struct vpd_params *vpd = &adapter->params.vpd; + + if (adapter->params.rev > 0) + calibrate_xgm_t3b(adapter); + else if (calibrate_xgm(adapter)) + goto out_err; + + if (vpd->mclk) { + partition_mem(adapter, &adapter->params.tp); + + if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) || + mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) || + mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) || + t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers, + adapter->params.mc5.nfilters, + adapter->params.mc5.nroutes)) + goto out_err; + } + + if (tp_init(adapter, &adapter->params.tp)) + goto out_err; + + t3_tp_set_coalescing_size(adapter, + min(adapter->params.sge.max_pkt_size, + MAX_RX_COALESCING_LEN), 1); + t3_tp_set_max_rxsize(adapter, + min(adapter->params.sge.max_pkt_size, 16384U)); + ulp_config(adapter, &adapter->params.tp); + + if (is_pcie(adapter)) + config_pcie(adapter); + else + t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN); + + t3_write_reg(adapter, A_PM1_RX_CFG, 0xf000f000); + init_hw_for_avail_ports(adapter, adapter->params.nports); + t3_sge_init(adapter, &adapter->params.sge); + + t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params); + t3_write_reg(adapter, A_CIM_BOOT_CFG, + V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2)); + t3_read_reg(adapter, A_CIM_BOOT_CFG); /* flush */ + + do { /* wait for uP to initialize */ + msleep(20); + } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts); + if (!attempts) + goto out_err; + + err = 0; +out_err: + return err; +} + +/** + * get_pci_mode - determine a card's PCI mode + * @adapter: the adapter + * @p: where to store the PCI settings + * + * Determines a card's PCI mode and associated parameters, such as speed + * and width. + */ +static void __devinit get_pci_mode(struct adapter *adapter, + struct pci_params *p) +{ + static unsigned short speed_map[] = { 33, 66, 100, 133 }; + u32 pci_mode, pcie_cap; + + pcie_cap = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); + if (pcie_cap) { + u16 val; + + p->variant = PCI_VARIANT_PCIE; + p->pcie_cap_addr = pcie_cap; + pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA, + &val); + p->width = (val >> 4) & 0x3f; + return; + } + + pci_mode = t3_read_reg(adapter, A_PCIX_MODE); + p->speed = speed_map[G_PCLKRANGE(pci_mode)]; + p->width = (pci_mode & F_64BIT) ? 64 : 32; + pci_mode = G_PCIXINITPAT(pci_mode); + if (pci_mode == 0) + p->variant = PCI_VARIANT_PCI; + else if (pci_mode < 4) + p->variant = PCI_VARIANT_PCIX_MODE1_PARITY; + else if (pci_mode < 8) + p->variant = PCI_VARIANT_PCIX_MODE1_ECC; + else + p->variant = PCI_VARIANT_PCIX_266_MODE2; +} + +/** + * init_link_config - initialize a link's SW state + * @lc: structure holding the link state + * @ai: information about the current card + * + * Initializes the SW state maintained for each link, including the link's + * capabilities and default speed/duplex/flow-control/autonegotiation + * settings. + */ +static void __devinit init_link_config(struct link_config *lc, + unsigned int caps) +{ + lc->supported = caps; + lc->requested_speed = lc->speed = SPEED_INVALID; + lc->requested_duplex = lc->duplex = DUPLEX_INVALID; + lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX; + if (lc->supported & SUPPORTED_Autoneg) { + lc->advertising = lc->supported; + lc->autoneg = AUTONEG_ENABLE; + lc->requested_fc |= PAUSE_AUTONEG; + } else { + lc->advertising = 0; + lc->autoneg = AUTONEG_DISABLE; + } +} + +/** + * mc7_calc_size - calculate MC7 memory size + * @cfg: the MC7 configuration + * + * Calculates the size of an MC7 memory in bytes from the value of its + * configuration register. + */ +static unsigned int __devinit mc7_calc_size(u32 cfg) +{ + unsigned int width = G_WIDTH(cfg); + unsigned int banks = !!(cfg & F_BKS) + 1; + unsigned int org = !!(cfg & F_ORG) + 1; + unsigned int density = G_DEN(cfg); + unsigned int MBs = ((256 << density) * banks) / (org << width); + + return MBs << 20; +} + +static void __devinit mc7_prep(struct adapter *adapter, struct mc7 *mc7, + unsigned int base_addr, const char *name) +{ + u32 cfg; + + mc7->adapter = adapter; + mc7->name = name; + mc7->offset = base_addr - MC7_PMRX_BASE_ADDR; + cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); + mc7->size = mc7_calc_size(cfg); + mc7->width = G_WIDTH(cfg); +} + +void mac_prep(struct cmac *mac, struct adapter *adapter, int index) +{ + mac->adapter = adapter; + mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index; + mac->nucast = 1; + + if (adapter->params.rev == 0 && uses_xaui(adapter)) { + t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset, + is_10G(adapter) ? 0x2901c04 : 0x2301c04); + t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset, + F_ENRGMII, 0); + } +} + +void early_hw_init(struct adapter *adapter, const struct adapter_info *ai) +{ + u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2); + + mi1_init(adapter, ai); + t3_write_reg(adapter, A_I2C_CFG, /* set for 80KHz */ + V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1)); + t3_write_reg(adapter, A_T3DBG_GPIO_EN, + ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL); + + if (adapter->params.rev == 0 || !uses_xaui(adapter)) + val |= F_ENRGMII; + + /* Enable MAC clocks so we can access the registers */ + t3_write_reg(adapter, A_XGM_PORT_CFG, val); + t3_read_reg(adapter, A_XGM_PORT_CFG); + + val |= F_CLKDIVRESET_; + t3_write_reg(adapter, A_XGM_PORT_CFG, val); + t3_read_reg(adapter, A_XGM_PORT_CFG); + t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val); + t3_read_reg(adapter, A_XGM_PORT_CFG); +} + +/* + * Reset the adapter. PCIe cards lose their config space during reset, PCI-X + * ones don't. + */ +int t3_reset_adapter(struct adapter *adapter) +{ + int i; + uint16_t devid = 0; + + if (is_pcie(adapter)) + pci_save_state(adapter->pdev); + t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE); + + /* + * Delay. Give Some time to device to reset fully. + * XXX The delay time should be modified. + */ + for (i = 0; i < 10; i++) { + msleep(50); + pci_read_config_word(adapter->pdev, 0x00, &devid); + if (devid == 0x1425) + break; + } + + if (devid != 0x1425) + return -1; + + if (is_pcie(adapter)) + pci_restore_state(adapter->pdev); + return 0; +} + +/* + * Initialize adapter SW state for the various HW modules, set initial values + * for some adapter tunables, take PHYs out of reset, and initialize the MDIO + * interface. + */ +int __devinit t3_prep_adapter(struct adapter *adapter, + const struct adapter_info *ai, int reset) +{ + int ret; + unsigned int i, j = 0; + + get_pci_mode(adapter, &adapter->params.pci); + + adapter->params.info = ai; + adapter->params.nports = ai->nports; + adapter->params.rev = t3_read_reg(adapter, A_PL_REV); + adapter->params.linkpoll_period = 0; + adapter->params.stats_update_period = is_10G(adapter) ? + MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10); + adapter->params.pci.vpd_cap_addr = + pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD); + ret = get_vpd_params(adapter, &adapter->params.vpd); + if (ret < 0) + return ret; + + if (reset && t3_reset_adapter(adapter)) + return -1; + + t3_sge_prep(adapter, &adapter->params.sge); + + if (adapter->params.vpd.mclk) { + struct tp_params *p = &adapter->params.tp; + + mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX"); + mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX"); + mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM"); + + p->nchan = ai->nports; + p->pmrx_size = t3_mc7_size(&adapter->pmrx); + p->pmtx_size = t3_mc7_size(&adapter->pmtx); + p->cm_size = t3_mc7_size(&adapter->cm); + p->chan_rx_size = p->pmrx_size / 2; /* only 1 Rx channel */ + p->chan_tx_size = p->pmtx_size / p->nchan; + p->rx_pg_size = 64 * 1024; + p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024; + p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size); + p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size); + p->ntimer_qs = p->cm_size >= (128 << 20) || + adapter->params.rev > 0 ? 12 : 6; + + adapter->params.mc5.nservers = DEFAULT_NSERVERS; + adapter->params.mc5.nfilters = adapter->params.rev > 0 ? + DEFAULT_NFILTERS : 0; + adapter->params.mc5.nroutes = 0; + t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT); + + init_mtus(adapter->params.mtus); + init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd); + } + + early_hw_init(adapter, ai); + + for_each_port(adapter, i) { + u8 hw_addr[6]; + struct port_info *p = adap2pinfo(adapter, i); + + while (!adapter->params.vpd.port_type[j]) + ++j; + + p->port_type = &port_types[adapter->params.vpd.port_type[j]]; + p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j, + ai->mdio_ops); + mac_prep(&p->mac, adapter, j); + ++j; + + /* + * The VPD EEPROM stores the base Ethernet address for the + * card. A port's address is derived from the base by adding + * the port's index to the base's low octet. + */ + memcpy(hw_addr, adapter->params.vpd.eth_base, 5); + hw_addr[5] = adapter->params.vpd.eth_base[5] + i; + + memcpy(adapter->port[i]->dev_addr, hw_addr, + ETH_ALEN); + memcpy(adapter->port[i]->perm_addr, hw_addr, + ETH_ALEN); + init_link_config(&p->link_config, p->port_type->caps); + p->phy.ops->power_down(&p->phy, 1); + if (!(p->port_type->caps & SUPPORTED_IRQ)) + adapter->params.linkpoll_period = 10; + } + + return 0; +} + +void t3_led_ready(struct adapter *adapter) +{ + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, + F_GPIO0_OUT_VAL); +} diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h new file mode 100644 index 000000000000..9af3bcd64b3b --- /dev/null +++ b/drivers/net/cxgb3/t3cdev.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2006-2007 Chelsio Communications. All rights reserved. + * Copyright (C) 2006-2007 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _T3CDEV_H_ +#define _T3CDEV_H_ + +#include +#include +#include +#include +#include +#include +#include + +#define T3CNAMSIZ 16 + +/* Get the t3cdev associated with a net_device */ +#define T3CDEV(netdev) (struct t3cdev *)(netdev->priv) + +struct cxgb3_client; + +enum t3ctype { + T3A = 0, + T3B +}; + +struct t3cdev { + char name[T3CNAMSIZ]; /* T3C device name */ + enum t3ctype type; + struct list_head ofld_dev_list; /* for list linking */ + struct net_device *lldev; /* LL dev associated with T3C messages */ + struct proc_dir_entry *proc_dir; /* root of proc dir for this T3C */ + int (*send)(struct t3cdev *dev, struct sk_buff *skb); + int (*recv)(struct t3cdev *dev, struct sk_buff **skb, int n); + int (*ctl)(struct t3cdev *dev, unsigned int req, void *data); + void (*neigh_update)(struct t3cdev *dev, struct neighbour *neigh); + void *priv; /* driver private data */ + void *l2opt; /* optional layer 2 data */ + void *l3opt; /* optional layer 3 data */ + void *l4opt; /* optional layer 4 data */ + void *ulp; /* ulp stuff */ +}; + +#endif /* _T3CDEV_H_ */ diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h new file mode 100644 index 000000000000..2b67dd523cc1 --- /dev/null +++ b/drivers/net/cxgb3/version.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/* $Date: 2006/10/31 18:57:51 $ $RCSfile: version.h,v $ $Revision: 1.3 $ */ +#ifndef __CHELSIO_VERSION_H +#define __CHELSIO_VERSION_H +#define DRV_DESC "Chelsio T3 Network Driver" +#define DRV_NAME "cxgb3" +/* Driver version */ +#define DRV_VERSION "1.0" +#endif /* __CHELSIO_VERSION_H */ diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c new file mode 100644 index 000000000000..eee4285b31be --- /dev/null +++ b/drivers/net/cxgb3/vsc8211.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" + +/* VSC8211 PHY specific registers. */ +enum { + VSC8211_INTR_ENABLE = 25, + VSC8211_INTR_STATUS = 26, + VSC8211_AUX_CTRL_STAT = 28, +}; + +enum { + VSC_INTR_RX_ERR = 1 << 0, + VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ + VSC_INTR_CABLE = 1 << 2, /* cable impairment */ + VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ + VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ + VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ + VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ + VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ + VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ + VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ + VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ + VSC_INTR_LINK_CHG = 1 << 13, /* link change */ + VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ +}; + +#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ + VSC_INTR_NEG_DONE) +#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ + VSC_INTR_ENABLE) + +/* PHY specific auxiliary control & status register fields */ +#define S_ACSR_ACTIPHY_TMR 0 +#define M_ACSR_ACTIPHY_TMR 0x3 +#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR) + +#define S_ACSR_SPEED 3 +#define M_ACSR_SPEED 0x3 +#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED) + +#define S_ACSR_DUPLEX 5 +#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX) + +#define S_ACSR_ACTIPHY 6 +#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY) + +/* + * Reset the PHY. This PHY completes reset immediately so we never wait. + */ +static int vsc8211_reset(struct cphy *cphy, int wait) +{ + return t3_phy_reset(cphy, 0, 0); +} + +static int vsc8211_intr_enable(struct cphy *cphy) +{ + return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK); +} + +static int vsc8211_intr_disable(struct cphy *cphy) +{ + return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0); +} + +static int vsc8211_intr_clear(struct cphy *cphy) +{ + u32 val; + + /* Clear PHY interrupts by reading the register. */ + return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val); +} + +static int vsc8211_autoneg_enable(struct cphy *cphy) +{ + return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, + BMCR_ANENABLE | BMCR_ANRESTART); +} + +static int vsc8211_autoneg_restart(struct cphy *cphy) +{ + return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, + BMCR_ANRESTART); +} + +static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok, + int *speed, int *duplex, int *fc) +{ + unsigned int bmcr, status, lpa, adv; + int err, sp = -1, dplx = -1, pause = 0; + + err = mdio_read(cphy, 0, MII_BMCR, &bmcr); + if (!err) + err = mdio_read(cphy, 0, MII_BMSR, &status); + if (err) + return err; + + if (link_ok) { + /* + * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it + * once more to get the current link state. + */ + if (!(status & BMSR_LSTATUS)) + err = mdio_read(cphy, 0, MII_BMSR, &status); + if (err) + return err; + *link_ok = (status & BMSR_LSTATUS) != 0; + } + if (!(bmcr & BMCR_ANENABLE)) { + dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; + if (bmcr & BMCR_SPEED1000) + sp = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + sp = SPEED_100; + else + sp = SPEED_10; + } else if (status & BMSR_ANEGCOMPLETE) { + err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status); + if (err) + return err; + + dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; + sp = G_ACSR_SPEED(status); + if (sp == 0) + sp = SPEED_10; + else if (sp == 1) + sp = SPEED_100; + else + sp = SPEED_1000; + + if (fc && dplx == DUPLEX_FULL) { + err = mdio_read(cphy, 0, MII_LPA, &lpa); + if (!err) + err = mdio_read(cphy, 0, MII_ADVERTISE, &adv); + if (err) + return err; + + if (lpa & adv & ADVERTISE_PAUSE_CAP) + pause = PAUSE_RX | PAUSE_TX; + else if ((lpa & ADVERTISE_PAUSE_CAP) && + (lpa & ADVERTISE_PAUSE_ASYM) && + (adv & ADVERTISE_PAUSE_ASYM)) + pause = PAUSE_TX; + else if ((lpa & ADVERTISE_PAUSE_ASYM) && + (adv & ADVERTISE_PAUSE_CAP)) + pause = PAUSE_RX; + } + } + if (speed) + *speed = sp; + if (duplex) + *duplex = dplx; + if (fc) + *fc = pause; + return 0; +} + +static int vsc8211_power_down(struct cphy *cphy, int enable) +{ + return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN, + enable ? BMCR_PDOWN : 0); +} + +static int vsc8211_intr_handler(struct cphy *cphy) +{ + unsigned int cause; + int err, cphy_cause = 0; + + err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause); + if (err) + return err; + + cause &= INTR_MASK; + if (cause & CFG_CHG_INTR_MASK) + cphy_cause |= cphy_cause_link_change; + if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO)) + cphy_cause |= cphy_cause_fifo_error; + return cphy_cause; +} + +static struct cphy_ops vsc8211_ops = { + .reset = vsc8211_reset, + .intr_enable = vsc8211_intr_enable, + .intr_disable = vsc8211_intr_disable, + .intr_clear = vsc8211_intr_clear, + .intr_handler = vsc8211_intr_handler, + .autoneg_enable = vsc8211_autoneg_enable, + .autoneg_restart = vsc8211_autoneg_restart, + .advertise = t3_phy_advertise, + .set_speed_duplex = t3_set_phy_speed_duplex, + .get_link_status = vsc8211_get_link_status, + .power_down = vsc8211_power_down, +}; + +void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter, + int phy_addr, const struct mdio_ops *mdio_ops) +{ + cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops); +} diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c new file mode 100644 index 000000000000..907a272ae32d --- /dev/null +++ b/drivers/net/cxgb3/xgmac.c @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "common.h" +#include "regs.h" + +/* + * # of exact address filters. The first one is used for the station address, + * the rest are available for multicast addresses. + */ +#define EXACT_ADDR_FILTERS 8 + +static inline int macidx(const struct cmac *mac) +{ + return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR); +} + +static void xaui_serdes_reset(struct cmac *mac) +{ + static const unsigned int clear[] = { + F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1, + F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3 + }; + + int i; + struct adapter *adap = mac->adapter; + u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset; + + t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] | + F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 | + F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 | + F_RESETPLL23 | F_RESETPLL01); + t3_read_reg(adap, ctrl); + udelay(15); + + for (i = 0; i < ARRAY_SIZE(clear); i++) { + t3_set_reg_field(adap, ctrl, clear[i], 0); + udelay(15); + } +} + +void t3b_pcs_reset(struct cmac *mac) +{ + t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, + F_PCS_RESET_, 0); + udelay(20); + t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0, + F_PCS_RESET_); +} + +int t3_mac_reset(struct cmac *mac) +{ + static const struct addr_val_pair mac_reset_avp[] = { + {A_XGM_TX_CTRL, 0}, + {A_XGM_RX_CTRL, 0}, + {A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES | + F_RMFCS | F_ENJUMBO | F_ENHASHMCAST}, + {A_XGM_RX_HASH_LOW, 0}, + {A_XGM_RX_HASH_HIGH, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_1, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_2, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_3, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_4, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_5, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_6, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_7, 0}, + {A_XGM_RX_EXACT_MATCH_LOW_8, 0}, + {A_XGM_STAT_CTRL, F_CLRSTATS} + }; + u32 val; + struct adapter *adap = mac->adapter; + unsigned int oft = mac->offset; + + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); + t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + + t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft); + t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft, + F_RXSTRFRWRD | F_DISERRFRAMES, + uses_xaui(adap) ? 0 : F_RXSTRFRWRD); + + if (uses_xaui(adap)) { + if (adap->params.rev == 0) { + t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, + F_RXENABLE | F_TXENABLE); + if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft, + F_CMULOCK, 1, 5, 2)) { + CH_ERR(adap, + "MAC %d XAUI SERDES CMU lock failed\n", + macidx(mac)); + return -1; + } + t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, + F_SERDESRESET_); + } else + xaui_serdes_reset(mac); + } + + if (adap->params.rev > 0) + t3_write_reg(adap, A_XGM_PAUSE_TIMER + oft, 0xf000); + + val = F_MAC_RESET_; + if (is_10G(adap)) + val |= F_PCS_RESET_; + else if (uses_xaui(adap)) + val |= F_PCS_RESET_ | F_XG2G_RESET_; + else + val |= F_RGMII_RESET_ | F_XG2G_RESET_; + t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); + t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ + if ((val & F_PCS_RESET_) && adap->params.rev) { + msleep(1); + t3b_pcs_reset(mac); + } + + memset(&mac->stats, 0, sizeof(mac->stats)); + return 0; +} + +/* + * Set the exact match register 'idx' to recognize the given Ethernet address. + */ +static void set_addr_filter(struct cmac *mac, int idx, const u8 * addr) +{ + u32 addr_lo, addr_hi; + unsigned int oft = mac->offset + idx * 8; + + addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; + addr_hi = (addr[5] << 8) | addr[4]; + + t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo); + t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi); +} + +/* Set one of the station's unicast MAC addresses. */ +int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]) +{ + if (idx >= mac->nucast) + return -EINVAL; + set_addr_filter(mac, idx, addr); + return 0; +} + +/* + * Specify the number of exact address filters that should be reserved for + * unicast addresses. Caller should reload the unicast and multicast addresses + * after calling this. + */ +int t3_mac_set_num_ucast(struct cmac *mac, int n) +{ + if (n > EXACT_ADDR_FILTERS) + return -EINVAL; + mac->nucast = n; + return 0; +} + +/* Calculate the RX hash filter index of an Ethernet address */ +static int hash_hw_addr(const u8 * addr) +{ + int hash = 0, octet, bit, i = 0, c; + + for (octet = 0; octet < 6; ++octet) + for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) { + hash ^= (c & 1) << i; + if (++i == 6) + i = 0; + } + return hash; +} + +int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm) +{ + u32 val, hash_lo, hash_hi; + struct adapter *adap = mac->adapter; + unsigned int oft = mac->offset; + + val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES; + if (rm->dev->flags & IFF_PROMISC) + val |= F_COPYALLFRAMES; + t3_write_reg(adap, A_XGM_RX_CFG + oft, val); + + if (rm->dev->flags & IFF_ALLMULTI) + hash_lo = hash_hi = 0xffffffff; + else { + u8 *addr; + int exact_addr_idx = mac->nucast; + + hash_lo = hash_hi = 0; + while ((addr = t3_get_next_mcaddr(rm))) + if (exact_addr_idx < EXACT_ADDR_FILTERS) + set_addr_filter(mac, exact_addr_idx++, addr); + else { + int hash = hash_hw_addr(addr); + + if (hash < 32) + hash_lo |= (1 << hash); + else + hash_hi |= (1 << (hash - 32)); + } + } + + t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo); + t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi); + return 0; +} + +int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) +{ + int hwm, lwm; + unsigned int thres, v; + struct adapter *adap = mac->adapter; + + /* + * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max + * packet size register includes header, but not FCS. + */ + mtu += 14; + if (mtu > MAX_FRAME_SIZE - 4) + return -EINVAL; + t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu); + + /* + * Adjust the PAUSE frame watermarks. We always set the LWM, and the + * HWM only if flow-control is enabled. + */ + hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, MAC_RXFIFO_SIZE / 2U); + hwm = min(hwm, 3 * MAC_RXFIFO_SIZE / 4 + 1024); + lwm = hwm - 1024; + v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset); + v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM); + v |= V_RXFIFOPAUSELWM(lwm / 8); + if (G_RXFIFOPAUSEHWM(v)) + v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) | + V_RXFIFOPAUSEHWM(hwm / 8); + t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v); + + /* Adjust the TX FIFO threshold based on the MTU */ + thres = (adap->params.vpd.cclk * 1000) / 15625; + thres = (thres * mtu) / 1000; + if (is_10G(adap)) + thres /= 10; + thres = mtu > thres ? (mtu - thres + 7) / 8 : 0; + thres = max(thres, 8U); /* need at least 8 */ + t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset, + V_TXFIFOTHRESH(M_TXFIFOTHRESH), V_TXFIFOTHRESH(thres)); + return 0; +} + +int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) +{ + u32 val; + struct adapter *adap = mac->adapter; + unsigned int oft = mac->offset; + + if (duplex >= 0 && duplex != DUPLEX_FULL) + return -EINVAL; + if (speed >= 0) { + if (speed == SPEED_10) + val = V_PORTSPEED(0); + else if (speed == SPEED_100) + val = V_PORTSPEED(1); + else if (speed == SPEED_1000) + val = V_PORTSPEED(2); + else if (speed == SPEED_10000) + val = V_PORTSPEED(3); + else + return -EINVAL; + + t3_set_reg_field(adap, A_XGM_PORT_CFG + oft, + V_PORTSPEED(M_PORTSPEED), val); + } + + val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft); + val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); + if (fc & PAUSE_TX) + val |= V_RXFIFOPAUSEHWM(G_RXFIFOPAUSELWM(val) + 128); /* +1KB */ + t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); + + t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, + (fc & PAUSE_RX) ? F_TXPAUSEEN : 0); + return 0; +} + +int t3_mac_enable(struct cmac *mac, int which) +{ + int idx = macidx(mac); + struct adapter *adap = mac->adapter; + unsigned int oft = mac->offset; + + if (which & MAC_DIRECTION_TX) { + t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN); + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); + t3_write_reg(adap, A_TP_PIO_DATA, 0xbf000001); + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); + t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx); + } + if (which & MAC_DIRECTION_RX) + t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN); + return 0; +} + +int t3_mac_disable(struct cmac *mac, int which) +{ + int idx = macidx(mac); + struct adapter *adap = mac->adapter; + + if (which & MAC_DIRECTION_TX) { + t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0); + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); + t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f); + t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE); + t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 0); + } + if (which & MAC_DIRECTION_RX) + t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0); + return 0; +} + +/* + * This function is called periodically to accumulate the current values of the + * RMON counters into the port statistics. Since the packet counters are only + * 32 bits they can overflow in ~286 secs at 10G, so the function should be + * called more frequently than that. The byte counters are 45-bit wide, they + * would overflow in ~7.8 hours. + */ +const struct mac_stats *t3_mac_update_stats(struct cmac *mac) +{ +#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset) +#define RMON_UPDATE(mac, name, reg) \ + (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg) +#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \ + (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \ + ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32) + + u32 v, lo; + + RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH); + RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH); + RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES); + RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES); + RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES); + RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES); + RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES); + RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES); + RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES); + + RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES); + mac->stats.rx_too_long += RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT); + + RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES); + RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES); + RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES); + RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES); + RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES); + RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES); + RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES); + + RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH); + RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH); + RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST); + RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST); + RMON_UPDATE(mac, tx_pause, TX_PAUSE); + /* This counts error frames in general (bad FCS, underrun, etc). */ + RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES); + + RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES); + RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES); + RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES); + RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES); + RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES); + RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES); + RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES); + + /* The next stat isn't clear-on-read. */ + t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50); + v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA); + lo = (u32) mac->stats.rx_cong_drops; + mac->stats.rx_cong_drops += (u64) (v - lo); + + return &mac->stats; +} diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 4ae0fed7122e..9f7e1db8ce62 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -5,7 +5,7 @@ * * adopted from sunlance.c by Richard van den Berg * - * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki + * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki * * additional sources: * - PMAD-AA TURBOchannel Ethernet Module Functional Specification, @@ -44,6 +44,8 @@ * v0.010: Fixes for the PMAD mapping of the LANCE buffer and for the * PMAX requirement to only use halfword accesses to the * buffer. macro + * + * v0.011: Converted the PMAD to the driver model. macro */ #include @@ -58,6 +60,7 @@ #include #include #include +#include #include #include @@ -69,15 +72,16 @@ #include #include #include -#include static char version[] __devinitdata = -"declance.c: v0.010 by Linux MIPS DECstation task force\n"; +"declance.c: v0.011 by Linux MIPS DECstation task force\n"; MODULE_AUTHOR("Linux MIPS DECstation task force"); MODULE_DESCRIPTION("DEC LANCE (DECstation onboard, PMAD-xx) driver"); MODULE_LICENSE("GPL"); +#define __unused __attribute__ ((unused)) + /* * card types */ @@ -246,7 +250,6 @@ struct lance_init_block { struct lance_private { struct net_device *next; int type; - int slot; int dma_irq; volatile struct lance_regs *ll; @@ -288,6 +291,7 @@ struct lance_regs { int dec_lance_debug = 2; +static struct tc_driver dec_lance_tc_driver; static struct net_device *root_lance_dev; static inline void writereg(volatile unsigned short *regptr, short value) @@ -1023,7 +1027,7 @@ static void lance_set_multicast_retry(unsigned long _opaque) lance_set_multicast(dev); } -static int __init dec_lance_init(const int type, const int slot) +static int __init dec_lance_probe(struct device *bdev, const int type) { static unsigned version_printed; static const char fmt[] = "declance%d"; @@ -1031,6 +1035,7 @@ static int __init dec_lance_init(const int type, const int slot) struct net_device *dev; struct lance_private *lp; volatile struct lance_regs *ll; + resource_size_t start = 0, len = 0; int i, ret; unsigned long esar_base; unsigned char *esar; @@ -1038,14 +1043,18 @@ static int __init dec_lance_init(const int type, const int slot) if (dec_lance_debug && version_printed++ == 0) printk(version); - i = 0; - dev = root_lance_dev; - while (dev) { - i++; - lp = (struct lance_private *)dev->priv; - dev = lp->next; + if (bdev) + snprintf(name, sizeof(name), "%s", bdev->bus_id); + else { + i = 0; + dev = root_lance_dev; + while (dev) { + i++; + lp = (struct lance_private *)dev->priv; + dev = lp->next; + } + snprintf(name, sizeof(name), fmt, i); } - snprintf(name, sizeof(name), fmt, i); dev = alloc_etherdev(sizeof(struct lance_private)); if (!dev) { @@ -1063,7 +1072,6 @@ static int __init dec_lance_init(const int type, const int slot) spin_lock_init(&lp->lock); lp->type = type; - lp->slot = slot; switch (type) { case ASIC_LANCE: dev->base_addr = CKSEG1ADDR(dec_kn_slot_base + IOASIC_LANCE); @@ -1110,12 +1118,22 @@ static int __init dec_lance_init(const int type, const int slot) break; #ifdef CONFIG_TC case PMAD_LANCE: - claim_tc_card(slot); + dev_set_drvdata(bdev, dev); - dev->mem_start = CKSEG1ADDR(get_tc_base_addr(slot)); + start = to_tc_dev(bdev)->resource.start; + len = to_tc_dev(bdev)->resource.end - start + 1; + if (!request_mem_region(start, len, bdev->bus_id)) { + printk(KERN_ERR + "%s: Unable to reserve MMIO resource\n", + bdev->bus_id); + ret = -EBUSY; + goto err_out_dev; + } + + dev->mem_start = CKSEG1ADDR(start); dev->mem_end = dev->mem_start + 0x100000; dev->base_addr = dev->mem_start + 0x100000; - dev->irq = get_tc_irq_nr(slot); + dev->irq = to_tc_dev(bdev)->interrupt; esar_base = dev->mem_start + 0x1c0002; lp->dma_irq = -1; @@ -1174,7 +1192,7 @@ static int __init dec_lance_init(const int type, const int slot) printk(KERN_ERR "%s: declance_init called with unknown type\n", name); ret = -ENODEV; - goto err_out_free_dev; + goto err_out_dev; } ll = (struct lance_regs *) dev->base_addr; @@ -1188,7 +1206,7 @@ static int __init dec_lance_init(const int type, const int slot) "%s: Ethernet station address prom not found!\n", name); ret = -ENODEV; - goto err_out_free_dev; + goto err_out_resource; } /* Check the prom contents */ for (i = 0; i < 8; i++) { @@ -1198,7 +1216,7 @@ static int __init dec_lance_init(const int type, const int slot) printk(KERN_ERR "%s: Something is wrong with the " "ethernet station address prom!\n", name); ret = -ENODEV; - goto err_out_free_dev; + goto err_out_resource; } } @@ -1255,48 +1273,51 @@ static int __init dec_lance_init(const int type, const int slot) if (ret) { printk(KERN_ERR "%s: Unable to register netdev, aborting.\n", name); - goto err_out_free_dev; + goto err_out_resource; } - lp->next = root_lance_dev; - root_lance_dev = dev; + if (!bdev) { + lp->next = root_lance_dev; + root_lance_dev = dev; + } printk("%s: registered as %s.\n", name, dev->name); return 0; -err_out_free_dev: +err_out_resource: + if (bdev) + release_mem_region(start, len); + +err_out_dev: free_netdev(dev); err_out: return ret; } +static void __exit dec_lance_remove(struct device *bdev) +{ + struct net_device *dev = dev_get_drvdata(bdev); + resource_size_t start, len; + + unregister_netdev(dev); + start = to_tc_dev(bdev)->resource.start; + len = to_tc_dev(bdev)->resource.end - start + 1; + release_mem_region(start, len); + free_netdev(dev); +} /* Find all the lance cards on the system and initialize them */ -static int __init dec_lance_probe(void) +static int __init dec_lance_platform_probe(void) { int count = 0; - /* Scan slots for PMAD-AA cards first. */ -#ifdef CONFIG_TC - if (TURBOCHANNEL) { - int slot; - - while ((slot = search_tc_card("PMAD-AA")) >= 0) { - if (dec_lance_init(PMAD_LANCE, slot) < 0) - break; - count++; - } - } -#endif - - /* Then handle onboard devices. */ if (dec_interrupt[DEC_IRQ_LANCE] >= 0) { if (dec_interrupt[DEC_IRQ_LANCE_MERR] >= 0) { - if (dec_lance_init(ASIC_LANCE, -1) >= 0) + if (dec_lance_probe(NULL, ASIC_LANCE) >= 0) count++; } else if (!TURBOCHANNEL) { - if (dec_lance_init(PMAX_LANCE, -1) >= 0) + if (dec_lance_probe(NULL, PMAX_LANCE) >= 0) count++; } } @@ -1304,21 +1325,70 @@ static int __init dec_lance_probe(void) return (count > 0) ? 0 : -ENODEV; } -static void __exit dec_lance_cleanup(void) +static void __exit dec_lance_platform_remove(void) { while (root_lance_dev) { struct net_device *dev = root_lance_dev; struct lance_private *lp = netdev_priv(dev); unregister_netdev(dev); -#ifdef CONFIG_TC - if (lp->slot >= 0) - release_tc_card(lp->slot); -#endif root_lance_dev = lp->next; free_netdev(dev); } } -module_init(dec_lance_probe); -module_exit(dec_lance_cleanup); +#ifdef CONFIG_TC +static int __init dec_lance_tc_probe(struct device *dev); +static int __exit dec_lance_tc_remove(struct device *dev); + +static const struct tc_device_id dec_lance_tc_table[] = { + { "DEC ", "PMAD-AA " }, + { } +}; +MODULE_DEVICE_TABLE(tc, dec_lance_tc_table); + +static struct tc_driver dec_lance_tc_driver = { + .id_table = dec_lance_tc_table, + .driver = { + .name = "declance", + .bus = &tc_bus_type, + .probe = dec_lance_tc_probe, + .remove = __exit_p(dec_lance_tc_remove), + }, +}; + +static int __init dec_lance_tc_probe(struct device *dev) +{ + int status = dec_lance_probe(dev, PMAD_LANCE); + if (!status) + get_device(dev); + return status; +} + +static int __exit dec_lance_tc_remove(struct device *dev) +{ + put_device(dev); + dec_lance_remove(dev); + return 0; +} +#endif + +static int __init dec_lance_init(void) +{ + int status; + + status = tc_register_driver(&dec_lance_tc_driver); + if (!status) + dec_lance_platform_probe(); + return status; +} + +static void __exit dec_lance_exit(void) +{ + dec_lance_platform_remove(); + tc_unregister_driver(&dec_lance_tc_driver); +} + + +module_init(dec_lance_init); +module_exit(dec_lance_exit); diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index f091042b146e..689f158a469e 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -59,17 +59,13 @@ #include #include #include -#ifdef NETIF_F_TSO6 #include -#endif #include #include #include #include #include -#ifdef NETIF_F_TSO #include -#endif #include #include #include @@ -257,7 +253,6 @@ struct e1000_adapter { spinlock_t tx_queue_lock; #endif atomic_t irq_sem; - unsigned int detect_link; unsigned int total_tx_bytes; unsigned int total_tx_packets; unsigned int total_rx_bytes; @@ -348,9 +343,7 @@ struct e1000_adapter { boolean_t have_msi; #endif /* to not mess up cache alignment, always add to the bottom */ -#ifdef NETIF_F_TSO boolean_t tso_force; -#endif boolean_t smart_power_down; /* phy smart power down */ boolean_t quad_port_a; unsigned long flags; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index fb96c87f9e56..44ebc72962dc 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -338,7 +338,6 @@ e1000_set_tx_csum(struct net_device *netdev, uint32_t data) return 0; } -#ifdef NETIF_F_TSO static int e1000_set_tso(struct net_device *netdev, uint32_t data) { @@ -352,18 +351,15 @@ e1000_set_tso(struct net_device *netdev, uint32_t data) else netdev->features &= ~NETIF_F_TSO; -#ifdef NETIF_F_TSO6 if (data) netdev->features |= NETIF_F_TSO6; else netdev->features &= ~NETIF_F_TSO6; -#endif DPRINTK(PROBE, INFO, "TSO is %s\n", data ? "Enabled" : "Disabled"); adapter->tso_force = TRUE; return 0; } -#endif /* NETIF_F_TSO */ static uint32_t e1000_get_msglevel(struct net_device *netdev) @@ -1971,10 +1967,8 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_tx_csum = e1000_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, -#ifdef NETIF_F_TSO .get_tso = ethtool_op_get_tso, .set_tso = e1000_set_tso, -#endif .self_test_count = e1000_diag_test_count, .self_test = e1000_diag_test, .get_strings = e1000_get_strings, diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index c6259c7127f6..619c89218b4b 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -36,7 +36,7 @@ static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "7.3.15-k2"DRIVERNAPI +#define DRV_VERSION "7.3.20-k2"DRIVERNAPI char e1000_driver_version[] = DRV_VERSION; static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation."; @@ -990,16 +990,12 @@ e1000_probe(struct pci_dev *pdev, netdev->features &= ~NETIF_F_HW_VLAN_FILTER; } -#ifdef NETIF_F_TSO if ((adapter->hw.mac_type >= e1000_82544) && (adapter->hw.mac_type != e1000_82547)) netdev->features |= NETIF_F_TSO; -#ifdef NETIF_F_TSO6 if (adapter->hw.mac_type > e1000_82547_rev_2) netdev->features |= NETIF_F_TSO6; -#endif -#endif if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; @@ -2583,15 +2579,22 @@ e1000_watchdog(unsigned long data) if (link) { if (!netif_carrier_ok(netdev)) { + uint32_t ctrl; boolean_t txb2b = 1; e1000_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, &adapter->link_duplex); - DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s\n", - adapter->link_speed, - adapter->link_duplex == FULL_DUPLEX ? - "Full Duplex" : "Half Duplex"); + ctrl = E1000_READ_REG(&adapter->hw, CTRL); + DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s, " + "Flow Control: %s\n", + adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? + "Full Duplex" : "Half Duplex", + ((ctrl & E1000_CTRL_TFCE) && (ctrl & + E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl & + E1000_CTRL_RFCE) ? "RX" : ((ctrl & + E1000_CTRL_TFCE) ? "TX" : "None" ))); /* tweak tx_queue_len according to speed/duplex * and adjust the timeout factor */ @@ -2619,7 +2622,6 @@ e1000_watchdog(unsigned long data) E1000_WRITE_REG(&adapter->hw, TARC0, tarc0); } -#ifdef NETIF_F_TSO /* disable TSO for pcie and 10/100 speeds, to avoid * some hardware issues */ if (!adapter->tso_force && @@ -2630,22 +2632,17 @@ e1000_watchdog(unsigned long data) DPRINTK(PROBE,INFO, "10/100 speed: disabling TSO\n"); netdev->features &= ~NETIF_F_TSO; -#ifdef NETIF_F_TSO6 netdev->features &= ~NETIF_F_TSO6; -#endif break; case SPEED_1000: netdev->features |= NETIF_F_TSO; -#ifdef NETIF_F_TSO6 netdev->features |= NETIF_F_TSO6; -#endif break; default: /* oops */ break; } } -#endif /* enable transmits in the hardware, need to do this * after setting TARC0 */ @@ -2875,7 +2872,6 @@ static int e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, struct sk_buff *skb) { -#ifdef NETIF_F_TSO struct e1000_context_desc *context_desc; struct e1000_buffer *buffer_info; unsigned int i; @@ -2904,7 +2900,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, 0); cmd_length = E1000_TXD_CMD_IP; ipcse = skb->h.raw - skb->data - 1; -#ifdef NETIF_F_TSO6 } else if (skb->protocol == htons(ETH_P_IPV6)) { skb->nh.ipv6h->payload_len = 0; skb->h.th->check = @@ -2914,7 +2909,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, IPPROTO_TCP, 0); ipcse = 0; -#endif } ipcss = skb->nh.raw - skb->data; ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data; @@ -2947,8 +2941,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, return TRUE; } -#endif - return FALSE; } @@ -2968,8 +2960,9 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, buffer_info = &tx_ring->buffer_info[i]; context_desc = E1000_CONTEXT_DESC(*tx_ring, i); + context_desc->lower_setup.ip_config = 0; context_desc->upper_setup.tcp_fields.tucss = css; - context_desc->upper_setup.tcp_fields.tucso = css + skb->csum_offset; + context_desc->upper_setup.tcp_fields.tucso = css + skb->csum; context_desc->upper_setup.tcp_fields.tucse = 0; context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); @@ -3005,7 +2998,6 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, while (len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, max_per_txd); -#ifdef NETIF_F_TSO /* Workaround for Controller erratum -- * descriptor for non-tso packet in a linear SKB that follows a * tso gets written back prematurely before the data is fully @@ -3020,7 +3012,6 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, * in TSO mode. Append 4-byte sentinel desc */ if (unlikely(mss && !nr_frags && size == len && size > 8)) size -= 4; -#endif /* work-around for errata 10 and it applies * to all controllers in PCI-X mode * The fix is to make sure that the first descriptor of a @@ -3062,12 +3053,10 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, while (len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, max_per_txd); -#ifdef NETIF_F_TSO /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ if (unlikely(mss && f == (nr_frags-1) && size == len && size > 8)) size -= 4; -#endif /* Workaround for potential 82544 hang in PCI-X. * Avoid terminating buffers within evenly-aligned * dwords. */ @@ -3292,7 +3281,6 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (adapter->hw.mac_type >= e1000_82571) max_per_txd = 8192; -#ifdef NETIF_F_TSO mss = skb_shinfo(skb)->gso_size; /* The controller does a simple calculation to * make sure there is enough room in the FIFO before @@ -3346,16 +3334,10 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL)) count++; count++; -#else - if (skb->ip_summed == CHECKSUM_PARTIAL) - count++; -#endif -#ifdef NETIF_F_TSO /* Controller Erratum workaround */ if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb)) count++; -#endif count += TXD_USE_COUNT(len, max_txd_pwr); @@ -3602,7 +3584,7 @@ e1000_update_stats(struct e1000_adapter *adapter) */ if (adapter->link_speed == 0) return; - if (pdev->error_state && pdev->error_state != pci_channel_io_normal) + if (pci_channel_offline(pdev)) return; spin_lock_irqsave(&adapter->stats_lock, flags); @@ -3765,8 +3747,8 @@ e1000_update_stats(struct e1000_adapter *adapter) * @data: pointer to a network interface device structure **/ -static -irqreturn_t e1000_intr_msi(int irq, void *data) +static irqreturn_t +e1000_intr_msi(int irq, void *data) { struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev); @@ -3774,49 +3756,27 @@ irqreturn_t e1000_intr_msi(int irq, void *data) #ifndef CONFIG_E1000_NAPI int i; #endif + uint32_t icr = E1000_READ_REG(hw, ICR); - /* this code avoids the read of ICR but has to get 1000 interrupts - * at every link change event before it will notice the change */ - if (++adapter->detect_link >= 1000) { - uint32_t icr = E1000_READ_REG(hw, ICR); #ifdef CONFIG_E1000_NAPI - /* read ICR disables interrupts using IAM, so keep up with our - * enable/disable accounting */ - atomic_inc(&adapter->irq_sem); + /* read ICR disables interrupts using IAM, so keep up with our + * enable/disable accounting */ + atomic_inc(&adapter->irq_sem); #endif - adapter->detect_link = 0; - if ((icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) && - (icr & E1000_ICR_INT_ASSERTED)) { - hw->get_link_status = 1; - /* 80003ES2LAN workaround-- - * For packet buffer work-around on link down event; - * disable receives here in the ISR and - * reset adapter in watchdog - */ - if (netif_carrier_ok(netdev) && - (adapter->hw.mac_type == e1000_80003es2lan)) { - /* disable receives */ - uint32_t rctl = E1000_READ_REG(hw, RCTL); - E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN); - } - /* guard against interrupt when we're going down */ - if (!test_bit(__E1000_DOWN, &adapter->flags)) - mod_timer(&adapter->watchdog_timer, - jiffies + 1); + if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + hw->get_link_status = 1; + /* 80003ES2LAN workaround-- For packet buffer work-around on + * link down event; disable receives here in the ISR and reset + * adapter in watchdog */ + if (netif_carrier_ok(netdev) && + (adapter->hw.mac_type == e1000_80003es2lan)) { + /* disable receives */ + uint32_t rctl = E1000_READ_REG(hw, RCTL); + E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN); } - } else { - E1000_WRITE_REG(hw, ICR, (0xffffffff & ~(E1000_ICR_RXSEQ | - E1000_ICR_LSC))); - /* bummer we have to flush here, but things break otherwise as - * some event appears to be lost or delayed and throughput - * drops. In almost all tests this flush is un-necessary */ - E1000_WRITE_FLUSH(hw); -#ifdef CONFIG_E1000_NAPI - /* Interrupt Auto-Mask (IAM)...upon writing ICR, interrupts are - * masked. No need for the IMC write, but it does mean we - * should account for it ASAP. */ - atomic_inc(&adapter->irq_sem); -#endif + /* guard against interrupt when we're going down */ + if (!test_bit(__E1000_DOWN, &adapter->flags)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); } #ifdef CONFIG_E1000_NAPI @@ -3836,7 +3796,7 @@ irqreturn_t e1000_intr_msi(int irq, void *data) for (i = 0; i < E1000_MAX_INTR; i++) if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) & - !e1000_clean_tx_irq(adapter, adapter->tx_ring))) + e1000_clean_tx_irq(adapter, adapter->tx_ring))) break; if (likely(adapter->itr_setting & 3)) @@ -3939,7 +3899,7 @@ e1000_intr(int irq, void *data) for (i = 0; i < E1000_MAX_INTR; i++) if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) & - !e1000_clean_tx_irq(adapter, adapter->tx_ring))) + e1000_clean_tx_irq(adapter, adapter->tx_ring))) break; if (likely(adapter->itr_setting & 3)) @@ -3989,7 +3949,7 @@ e1000_clean(struct net_device *poll_dev, int *budget) poll_dev->quota -= work_done; /* If no Tx and not enough Rx work done, exit the polling mode */ - if ((!tx_cleaned && (work_done == 0)) || + if ((tx_cleaned && (work_done < work_to_do)) || !netif_running(poll_dev)) { quit_polling: if (likely(adapter->itr_setting & 3)) @@ -4019,7 +3979,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, #ifdef CONFIG_E1000_NAPI unsigned int count = 0; #endif - boolean_t cleaned = FALSE; + boolean_t cleaned = TRUE; unsigned int total_tx_bytes=0, total_tx_packets=0; i = tx_ring->next_to_clean; @@ -4034,10 +3994,13 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, if (cleaned) { struct sk_buff *skb = buffer_info->skb; - unsigned int segs = skb_shinfo(skb)->gso_segs; + unsigned int segs, bytecount; + segs = skb_shinfo(skb)->gso_segs ?: 1; + /* multiply data chunks by size of headers */ + bytecount = ((segs - 1) * skb_headlen(skb)) + + skb->len; total_tx_packets += segs; - total_tx_packets++; - total_tx_bytes += skb->len; + total_tx_bytes += bytecount; } e1000_unmap_and_free_tx_resource(adapter, buffer_info); tx_desc->upper.data = 0; @@ -4050,7 +4013,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, #ifdef CONFIG_E1000_NAPI #define E1000_TX_WEIGHT 64 /* weight of a sort for tx, to avoid endless transmit cleanup */ - if (count++ == E1000_TX_WEIGHT) break; + if (count++ == E1000_TX_WEIGHT) { + cleaned = FALSE; + break; + } #endif } diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h index 18afc0c25dac..10af742d8a20 100644 --- a/drivers/net/e1000/e1000_osdep.h +++ b/drivers/net/e1000/e1000_osdep.h @@ -48,8 +48,6 @@ typedef enum { TRUE = 1 } boolean_t; -#define MSGOUT(S, A, B) printk(KERN_DEBUG S "\n", A, B) - #ifdef DBG #define DEBUGOUT(S) printk(KERN_DEBUG S "\n") #define DEBUGOUT1(S, A...) printk(KERN_DEBUG S "\n", A) @@ -58,7 +56,7 @@ typedef enum { #define DEBUGOUT1(S, A...) #endif -#define DEBUGFUNC(F) DEBUGOUT(F) +#define DEBUGFUNC(F) DEBUGOUT(F "\n") #define DEBUGOUT2 DEBUGOUT1 #define DEBUGOUT3 DEBUGOUT2 #define DEBUGOUT7 DEBUGOUT3 diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index cf2a279307e1..f8862e203ac9 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -760,22 +760,13 @@ e1000_check_copper_options(struct e1000_adapter *adapter) case SPEED_1000: DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without " "Duplex\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at 1000 Mbps " - "Full Duplex only\n"); - adapter->hw.autoneg = adapter->fc_autoneg = 1; - adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; - break; + goto full_duplex_only; case SPEED_1000 + HALF_DUPLEX: DPRINTK(PROBE, INFO, "Half Duplex is not supported at 1000 Mbps\n"); - DPRINTK(PROBE, INFO, - "Using Autonegotiation at 1000 Mbps " - "Full Duplex only\n"); - adapter->hw.autoneg = adapter->fc_autoneg = 1; - adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL; - break; + /* fall through */ case SPEED_1000 + FULL_DUPLEX: +full_duplex_only: DPRINTK(PROBE, INFO, "Using Autonegotiation at 1000 Mbps Full Duplex only\n"); adapter->hw.autoneg = adapter->fc_autoneg = 1; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 93f2b7a22160..a363148d0198 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -111,6 +111,7 @@ * 0.57: 14 May 2006: Mac address set in probe/remove and order corrections. * 0.58: 30 Oct 2006: Added support for sideband management unit. * 0.59: 30 Oct 2006: Added support for recoverable error. + * 0.60: 20 Jan 2007: Code optimizations for rings, rx & tx data paths, and stats. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -127,7 +128,7 @@ #else #define DRIVERNAPI #endif -#define FORCEDETH_VERSION "0.59" +#define FORCEDETH_VERSION "0.60" #define DRV_NAME "forcedeth" #include @@ -173,9 +174,10 @@ #define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */ #define DEV_HAS_POWER_CNTRL 0x0100 /* device supports power savings */ #define DEV_HAS_PAUSEFRAME_TX 0x0200 /* device supports tx pause frames */ -#define DEV_HAS_STATISTICS 0x0400 /* device supports hw statistics */ -#define DEV_HAS_TEST_EXTENDED 0x0800 /* device supports extended diagnostic test */ -#define DEV_HAS_MGMT_UNIT 0x1000 /* device supports management unit */ +#define DEV_HAS_STATISTICS_V1 0x0400 /* device supports hw statistics version 1 */ +#define DEV_HAS_STATISTICS_V2 0x0800 /* device supports hw statistics version 2 */ +#define DEV_HAS_TEST_EXTENDED 0x1000 /* device supports extended diagnostic test */ +#define DEV_HAS_MGMT_UNIT 0x2000 /* device supports management unit */ enum { NvRegIrqStatus = 0x000, @@ -210,7 +212,7 @@ enum { * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms */ NvRegPollingInterval = 0x00c, -#define NVREG_POLL_DEFAULT_THROUGHPUT 970 +#define NVREG_POLL_DEFAULT_THROUGHPUT 970 /* backup tx cleanup if loop max reached */ #define NVREG_POLL_DEFAULT_CPU 13 NvRegMSIMap0 = 0x020, NvRegMSIMap1 = 0x024, @@ -304,8 +306,8 @@ enum { #define NVREG_TXRXCTL_RESET 0x0010 #define NVREG_TXRXCTL_RXCHECK 0x0400 #define NVREG_TXRXCTL_DESC_1 0 -#define NVREG_TXRXCTL_DESC_2 0x02100 -#define NVREG_TXRXCTL_DESC_3 0x02200 +#define NVREG_TXRXCTL_DESC_2 0x002100 +#define NVREG_TXRXCTL_DESC_3 0xc02200 #define NVREG_TXRXCTL_VLANSTRIP 0x00040 #define NVREG_TXRXCTL_VLANINS 0x00080 NvRegTxRingPhysAddrHigh = 0x148, @@ -487,7 +489,8 @@ union ring_type { /* Miscelaneous hardware related defines: */ #define NV_PCI_REGSZ_VER1 0x270 -#define NV_PCI_REGSZ_VER2 0x604 +#define NV_PCI_REGSZ_VER2 0x2d4 +#define NV_PCI_REGSZ_VER3 0x604 /* various timeout delays: all in usec */ #define NV_TXRX_RESET_DELAY 4 @@ -518,12 +521,6 @@ union ring_type { #define TX_RING_MIN 64 #define RING_MAX_DESC_VER_1 1024 #define RING_MAX_DESC_VER_2_3 16384 -/* - * Difference between the get and put pointers for the tx ring. - * This is used to throttle the amount of data outstanding in the - * tx ring. - */ -#define TX_LIMIT_DIFFERENCE 1 /* rx/tx mac addr + type + vlan + align + slack*/ #define NV_RX_HEADERS (64) @@ -611,9 +608,6 @@ static const struct nv_ethtool_str nv_estats_str[] = { { "tx_carrier_errors" }, { "tx_excess_deferral" }, { "tx_retry_error" }, - { "tx_deferral" }, - { "tx_packets" }, - { "tx_pause" }, { "rx_frame_error" }, { "rx_extra_byte" }, { "rx_late_collision" }, @@ -626,11 +620,17 @@ static const struct nv_ethtool_str nv_estats_str[] = { { "rx_unicast" }, { "rx_multicast" }, { "rx_broadcast" }, - { "rx_bytes" }, - { "rx_pause" }, - { "rx_drop_frame" }, { "rx_packets" }, - { "rx_errors_total" } + { "rx_errors_total" }, + { "tx_errors_total" }, + + /* version 2 stats */ + { "tx_deferral" }, + { "tx_packets" }, + { "rx_bytes" }, + { "tx_pause" }, + { "rx_pause" }, + { "rx_drop_frame" } }; struct nv_ethtool_stats { @@ -643,9 +643,6 @@ struct nv_ethtool_stats { u64 tx_carrier_errors; u64 tx_excess_deferral; u64 tx_retry_error; - u64 tx_deferral; - u64 tx_packets; - u64 tx_pause; u64 rx_frame_error; u64 rx_extra_byte; u64 rx_late_collision; @@ -658,13 +655,22 @@ struct nv_ethtool_stats { u64 rx_unicast; u64 rx_multicast; u64 rx_broadcast; - u64 rx_bytes; - u64 rx_pause; - u64 rx_drop_frame; u64 rx_packets; u64 rx_errors_total; + u64 tx_errors_total; + + /* version 2 stats */ + u64 tx_deferral; + u64 tx_packets; + u64 rx_bytes; + u64 tx_pause; + u64 rx_pause; + u64 rx_drop_frame; }; +#define NV_DEV_STATISTICS_V2_COUNT (sizeof(struct nv_ethtool_stats)/sizeof(u64)) +#define NV_DEV_STATISTICS_V1_COUNT (NV_DEV_STATISTICS_V2_COUNT - 6) + /* diagnostics */ #define NV_TEST_COUNT_BASE 3 #define NV_TEST_COUNT_EXTENDED 4 @@ -691,6 +697,12 @@ static const struct register_test nv_registers_test[] = { { 0,0 } }; +struct nv_skb_map { + struct sk_buff *skb; + dma_addr_t dma; + unsigned int dma_len; +}; + /* * SMP locking: * All hardware access under dev->priv->lock, except the performance @@ -741,10 +753,12 @@ struct fe_priv { /* rx specific fields. * Locking: Within irq hander or disable_irq+spin_lock(&np->lock); */ + union ring_type get_rx, put_rx, first_rx, last_rx; + struct nv_skb_map *get_rx_ctx, *put_rx_ctx; + struct nv_skb_map *first_rx_ctx, *last_rx_ctx; + struct nv_skb_map *rx_skb; + union ring_type rx_ring; - unsigned int cur_rx, refill_rx; - struct sk_buff **rx_skbuff; - dma_addr_t *rx_dma; unsigned int rx_buf_sz; unsigned int pkt_limit; struct timer_list oom_kick; @@ -761,15 +775,15 @@ struct fe_priv { /* * tx specific fields. */ + union ring_type get_tx, put_tx, first_tx, last_tx; + struct nv_skb_map *get_tx_ctx, *put_tx_ctx; + struct nv_skb_map *first_tx_ctx, *last_tx_ctx; + struct nv_skb_map *tx_skb; + union ring_type tx_ring; - unsigned int next_tx, nic_tx; - struct sk_buff **tx_skbuff; - dma_addr_t *tx_dma; - unsigned int *tx_dma_len; u32 tx_flags; int tx_ring_size; - int tx_limit_start; - int tx_limit_stop; + int tx_stop; /* vlan fields */ struct vlan_group *vlangrp; @@ -921,16 +935,10 @@ static void free_rings(struct net_device *dev) pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size), np->rx_ring.ex, np->ring_addr); } - if (np->rx_skbuff) - kfree(np->rx_skbuff); - if (np->rx_dma) - kfree(np->rx_dma); - if (np->tx_skbuff) - kfree(np->tx_skbuff); - if (np->tx_dma) - kfree(np->tx_dma); - if (np->tx_dma_len) - kfree(np->tx_dma_len); + if (np->rx_skb) + kfree(np->rx_skb); + if (np->tx_skb) + kfree(np->tx_skb); } static int using_multi_irqs(struct net_device *dev) @@ -1279,6 +1287,61 @@ static void nv_mac_reset(struct net_device *dev) pci_push(base); } +static void nv_get_hw_stats(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + + np->estats.tx_bytes += readl(base + NvRegTxCnt); + np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt); + np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt); + np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt); + np->estats.tx_late_collision += readl(base + NvRegTxLateCol); + np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow); + np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier); + np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef); + np->estats.tx_retry_error += readl(base + NvRegTxRetryErr); + np->estats.rx_frame_error += readl(base + NvRegRxFrameErr); + np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte); + np->estats.rx_late_collision += readl(base + NvRegRxLateCol); + np->estats.rx_runt += readl(base + NvRegRxRunt); + np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong); + np->estats.rx_over_errors += readl(base + NvRegRxOverflow); + np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr); + np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr); + np->estats.rx_length_error += readl(base + NvRegRxLenErr); + np->estats.rx_unicast += readl(base + NvRegRxUnicast); + np->estats.rx_multicast += readl(base + NvRegRxMulticast); + np->estats.rx_broadcast += readl(base + NvRegRxBroadcast); + np->estats.rx_packets = + np->estats.rx_unicast + + np->estats.rx_multicast + + np->estats.rx_broadcast; + np->estats.rx_errors_total = + np->estats.rx_crc_errors + + np->estats.rx_over_errors + + np->estats.rx_frame_error + + (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) + + np->estats.rx_late_collision + + np->estats.rx_runt + + np->estats.rx_frame_too_long; + np->estats.tx_errors_total = + np->estats.tx_late_collision + + np->estats.tx_fifo_errors + + np->estats.tx_carrier_errors + + np->estats.tx_excess_deferral + + np->estats.tx_retry_error; + + if (np->driver_data & DEV_HAS_STATISTICS_V2) { + np->estats.tx_deferral += readl(base + NvRegTxDef); + np->estats.tx_packets += readl(base + NvRegTxFrame); + np->estats.rx_bytes += readl(base + NvRegRxCnt); + np->estats.tx_pause += readl(base + NvRegTxPause); + np->estats.rx_pause += readl(base + NvRegRxPause); + np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame); + } +} + /* * nv_get_stats: dev->get_stats function * Get latest stats value from the nic. @@ -1289,10 +1352,19 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); - /* It seems that the nic always generates interrupts and doesn't - * accumulate errors internally. Thus the current values in np->stats - * are already up to date. - */ + /* If the nic supports hw counters then retrieve latest values */ + if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2)) { + nv_get_hw_stats(dev); + + /* copy to net_device stats */ + np->stats.tx_bytes = np->estats.tx_bytes; + np->stats.tx_fifo_errors = np->estats.tx_fifo_errors; + np->stats.tx_carrier_errors = np->estats.tx_carrier_errors; + np->stats.rx_crc_errors = np->estats.rx_crc_errors; + np->stats.rx_over_errors = np->estats.rx_over_errors; + np->stats.rx_errors = np->estats.rx_errors_total; + np->stats.tx_errors = np->estats.tx_errors_total; + } return &np->stats; } @@ -1304,43 +1376,63 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev) static int nv_alloc_rx(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); - unsigned int refill_rx = np->refill_rx; - int nr; + struct ring_desc* less_rx; - while (np->cur_rx != refill_rx) { - struct sk_buff *skb; - - nr = refill_rx % np->rx_ring_size; - if (np->rx_skbuff[nr] == NULL) { - - skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD); - if (!skb) - break; + less_rx = np->get_rx.orig; + if (less_rx-- == np->first_rx.orig) + less_rx = np->last_rx.orig; + while (np->put_rx.orig != less_rx) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD); + if (skb) { skb->dev = dev; - np->rx_skbuff[nr] = skb; - } else { - skb = np->rx_skbuff[nr]; - } - np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, - skb->end-skb->data, PCI_DMA_FROMDEVICE); - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->rx_ring.orig[nr].buf = cpu_to_le32(np->rx_dma[nr]); + np->put_rx_ctx->skb = skb; + np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data, + skb->end-skb->data, PCI_DMA_FROMDEVICE); + np->put_rx_ctx->dma_len = skb->end-skb->data; + np->put_rx.orig->buf = cpu_to_le32(np->put_rx_ctx->dma); wmb(); - np->rx_ring.orig[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL); + np->put_rx.orig->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL); + if (unlikely(np->put_rx.orig++ == np->last_rx.orig)) + np->put_rx.orig = np->first_rx.orig; + if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx)) + np->put_rx_ctx = np->first_rx_ctx; } else { - np->rx_ring.ex[nr].bufhigh = cpu_to_le64(np->rx_dma[nr]) >> 32; - np->rx_ring.ex[nr].buflow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF; - wmb(); - np->rx_ring.ex[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL); + return 1; + } + } + return 0; +} + +static int nv_alloc_rx_optimized(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + struct ring_desc_ex* less_rx; + + less_rx = np->get_rx.ex; + if (less_rx-- == np->first_rx.ex) + less_rx = np->last_rx.ex; + + while (np->put_rx.ex != less_rx) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD); + if (skb) { + skb->dev = dev; + np->put_rx_ctx->skb = skb; + np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data, + skb->end-skb->data, PCI_DMA_FROMDEVICE); + np->put_rx_ctx->dma_len = skb->end-skb->data; + np->put_rx.ex->bufhigh = cpu_to_le64(np->put_rx_ctx->dma) >> 32; + np->put_rx.ex->buflow = cpu_to_le64(np->put_rx_ctx->dma) & 0x0FFFFFFFF; + wmb(); + np->put_rx.ex->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL); + if (unlikely(np->put_rx.ex++ == np->last_rx.ex)) + np->put_rx.ex = np->first_rx.ex; + if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx)) + np->put_rx_ctx = np->first_rx_ctx; + } else { + return 1; } - dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n", - dev->name, refill_rx); - refill_rx++; } - np->refill_rx = refill_rx; - if (np->cur_rx - refill_rx == np->rx_ring_size) - return 1; return 0; } @@ -1358,6 +1450,7 @@ static void nv_do_rx_refill(unsigned long data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); + int retcode; if (!using_multi_irqs(dev)) { if (np->msi_flags & NV_MSI_X_ENABLED) @@ -1367,7 +1460,11 @@ static void nv_do_rx_refill(unsigned long data) } else { disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); } - if (nv_alloc_rx(dev)) { + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + retcode = nv_alloc_rx(dev); + else + retcode = nv_alloc_rx_optimized(dev); + if (retcode) { spin_lock_irq(&np->lock); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); @@ -1388,56 +1485,81 @@ static void nv_init_rx(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); int i; + np->get_rx = np->put_rx = np->first_rx = np->rx_ring; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->last_rx.orig = &np->rx_ring.orig[np->rx_ring_size-1]; + else + np->last_rx.ex = &np->rx_ring.ex[np->rx_ring_size-1]; + np->get_rx_ctx = np->put_rx_ctx = np->first_rx_ctx = np->rx_skb; + np->last_rx_ctx = &np->rx_skb[np->rx_ring_size-1]; - np->cur_rx = np->rx_ring_size; - np->refill_rx = 0; - for (i = 0; i < np->rx_ring_size; i++) - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + for (i = 0; i < np->rx_ring_size; i++) { + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->rx_ring.orig[i].flaglen = 0; - else + np->rx_ring.orig[i].buf = 0; + } else { np->rx_ring.ex[i].flaglen = 0; + np->rx_ring.ex[i].txvlan = 0; + np->rx_ring.ex[i].bufhigh = 0; + np->rx_ring.ex[i].buflow = 0; + } + np->rx_skb[i].skb = NULL; + np->rx_skb[i].dma = 0; + } } static void nv_init_tx(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); int i; + np->get_tx = np->put_tx = np->first_tx = np->tx_ring; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->last_tx.orig = &np->tx_ring.orig[np->tx_ring_size-1]; + else + np->last_tx.ex = &np->tx_ring.ex[np->tx_ring_size-1]; + np->get_tx_ctx = np->put_tx_ctx = np->first_tx_ctx = np->tx_skb; + np->last_tx_ctx = &np->tx_skb[np->tx_ring_size-1]; - np->next_tx = np->nic_tx = 0; for (i = 0; i < np->tx_ring_size; i++) { - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->tx_ring.orig[i].flaglen = 0; - else + np->tx_ring.orig[i].buf = 0; + } else { np->tx_ring.ex[i].flaglen = 0; - np->tx_skbuff[i] = NULL; - np->tx_dma[i] = 0; + np->tx_ring.ex[i].txvlan = 0; + np->tx_ring.ex[i].bufhigh = 0; + np->tx_ring.ex[i].buflow = 0; + } + np->tx_skb[i].skb = NULL; + np->tx_skb[i].dma = 0; } } static int nv_init_ring(struct net_device *dev) { + struct fe_priv *np = netdev_priv(dev); + nv_init_tx(dev); nv_init_rx(dev); - return nv_alloc_rx(dev); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + return nv_alloc_rx(dev); + else + return nv_alloc_rx_optimized(dev); } -static int nv_release_txskb(struct net_device *dev, unsigned int skbnr) +static int nv_release_txskb(struct net_device *dev, struct nv_skb_map* tx_skb) { struct fe_priv *np = netdev_priv(dev); - dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n", - dev->name, skbnr); - - if (np->tx_dma[skbnr]) { - pci_unmap_page(np->pci_dev, np->tx_dma[skbnr], - np->tx_dma_len[skbnr], + if (tx_skb->dma) { + pci_unmap_page(np->pci_dev, tx_skb->dma, + tx_skb->dma_len, PCI_DMA_TODEVICE); - np->tx_dma[skbnr] = 0; + tx_skb->dma = 0; } - - if (np->tx_skbuff[skbnr]) { - dev_kfree_skb_any(np->tx_skbuff[skbnr]); - np->tx_skbuff[skbnr] = NULL; + if (tx_skb->skb) { + dev_kfree_skb_any(tx_skb->skb); + tx_skb->skb = NULL; return 1; } else { return 0; @@ -1450,11 +1572,16 @@ static void nv_drain_tx(struct net_device *dev) unsigned int i; for (i = 0; i < np->tx_ring_size; i++) { - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->tx_ring.orig[i].flaglen = 0; - else + np->tx_ring.orig[i].buf = 0; + } else { np->tx_ring.ex[i].flaglen = 0; - if (nv_release_txskb(dev, i)) + np->tx_ring.ex[i].txvlan = 0; + np->tx_ring.ex[i].bufhigh = 0; + np->tx_ring.ex[i].buflow = 0; + } + if (nv_release_txskb(dev, &np->tx_skb[i])) np->stats.tx_dropped++; } } @@ -1463,18 +1590,24 @@ static void nv_drain_rx(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); int i; + for (i = 0; i < np->rx_ring_size; i++) { - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->rx_ring.orig[i].flaglen = 0; - else + np->rx_ring.orig[i].buf = 0; + } else { np->rx_ring.ex[i].flaglen = 0; + np->rx_ring.ex[i].txvlan = 0; + np->rx_ring.ex[i].bufhigh = 0; + np->rx_ring.ex[i].buflow = 0; + } wmb(); - if (np->rx_skbuff[i]) { - pci_unmap_single(np->pci_dev, np->rx_dma[i], - np->rx_skbuff[i]->end-np->rx_skbuff[i]->data, + if (np->rx_skb[i].skb) { + pci_unmap_single(np->pci_dev, np->rx_skb[i].dma, + np->rx_skb[i].skb->end-np->rx_skb[i].skb->data, PCI_DMA_FROMDEVICE); - dev_kfree_skb(np->rx_skbuff[i]); - np->rx_skbuff[i] = NULL; + dev_kfree_skb(np->rx_skb[i].skb); + np->rx_skb[i].skb = NULL; } } } @@ -1485,6 +1618,11 @@ static void drain_ring(struct net_device *dev) nv_drain_rx(dev); } +static inline u32 nv_get_empty_tx_slots(struct fe_priv *np) +{ + return (u32)(np->tx_ring_size - ((np->tx_ring_size + (np->put_tx_ctx - np->get_tx_ctx)) % np->tx_ring_size)); +} + /* * nv_start_xmit: dev->hard_start_xmit function * Called with netif_tx_lock held. @@ -1495,14 +1633,16 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 tx_flags = 0; u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET); unsigned int fragments = skb_shinfo(skb)->nr_frags; - unsigned int nr = (np->next_tx - 1) % np->tx_ring_size; - unsigned int start_nr = np->next_tx % np->tx_ring_size; unsigned int i; u32 offset = 0; u32 bcnt; u32 size = skb->len-skb->data_len; u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); - u32 tx_flags_vlan = 0; + u32 empty_slots; + struct ring_desc* put_tx; + struct ring_desc* start_tx; + struct ring_desc* prev_tx; + struct nv_skb_map* prev_tx_ctx; /* add fragments to entries count */ for (i = 0; i < fragments; i++) { @@ -1510,34 +1650,35 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); } - spin_lock_irq(&np->lock); - - if ((np->next_tx - np->nic_tx + entries - 1) > np->tx_limit_stop) { - spin_unlock_irq(&np->lock); + empty_slots = nv_get_empty_tx_slots(np); + if (unlikely(empty_slots <= entries)) { + spin_lock_irq(&np->lock); netif_stop_queue(dev); + np->tx_stop = 1; + spin_unlock_irq(&np->lock); return NETDEV_TX_BUSY; } + start_tx = put_tx = np->put_tx.orig; + /* setup the header buffer */ do { + prev_tx = put_tx; + prev_tx_ctx = np->put_tx_ctx; bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; - nr = (nr + 1) % np->tx_ring_size; - - np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt, + np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt, PCI_DMA_TODEVICE); - np->tx_dma_len[nr] = bcnt; + np->put_tx_ctx->dma_len = bcnt; + put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma); + put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]); - np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags); - } else { - np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32; - np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; - np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags); - } tx_flags = np->tx_flags; offset += bcnt; size -= bcnt; + if (unlikely(put_tx++ == np->last_tx.orig)) + put_tx = np->first_tx.orig; + if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) + np->put_tx_ctx = np->first_tx_ctx; } while (size); /* setup the fragments */ @@ -1547,58 +1688,46 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) offset = 0; do { + prev_tx = put_tx; + prev_tx_ctx = np->put_tx_ctx; bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; - nr = (nr + 1) % np->tx_ring_size; + np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, + PCI_DMA_TODEVICE); + np->put_tx_ctx->dma_len = bcnt; + put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma); + put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); - np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, - PCI_DMA_TODEVICE); - np->tx_dma_len[nr] = bcnt; - - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]); - np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags); - } else { - np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32; - np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; - np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags); - } offset += bcnt; size -= bcnt; + if (unlikely(put_tx++ == np->last_tx.orig)) + put_tx = np->first_tx.orig; + if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) + np->put_tx_ctx = np->first_tx_ctx; } while (size); } /* set last fragment flag */ - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[nr].flaglen |= cpu_to_le32(tx_flags_extra); - } else { - np->tx_ring.ex[nr].flaglen |= cpu_to_le32(tx_flags_extra); - } + prev_tx->flaglen |= cpu_to_le32(tx_flags_extra); - np->tx_skbuff[nr] = skb; + /* save skb in this slot's context area */ + prev_tx_ctx->skb = skb; -#ifdef NETIF_F_TSO if (skb_is_gso(skb)) tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT); else -#endif - tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ? + tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ? NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0; - /* vlan tag */ - if (np->vlangrp && vlan_tx_tag_present(skb)) { - tx_flags_vlan = NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb); - } + spin_lock_irq(&np->lock); /* set tx flags */ - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - np->tx_ring.orig[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); - } else { - np->tx_ring.ex[start_nr].txvlan = cpu_to_le32(tx_flags_vlan); - np->tx_ring.ex[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); - } + start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); + np->put_tx.orig = put_tx; - dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n", - dev->name, np->next_tx, entries, tx_flags_extra); + spin_unlock_irq(&np->lock); + + dprintk(KERN_DEBUG "%s: nv_start_xmit: entries %d queued for transmission. tx_flags_extra: %x\n", + dev->name, entries, tx_flags_extra); { int j; for (j=0; j<64; j++) { @@ -1609,12 +1738,136 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) dprintk("\n"); } - np->next_tx += entries; + dev->trans_start = jiffies; + writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); + return NETDEV_TX_OK; +} + +static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + u32 tx_flags = 0; + u32 tx_flags_extra; + unsigned int fragments = skb_shinfo(skb)->nr_frags; + unsigned int i; + u32 offset = 0; + u32 bcnt; + u32 size = skb->len-skb->data_len; + u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + u32 empty_slots; + struct ring_desc_ex* put_tx; + struct ring_desc_ex* start_tx; + struct ring_desc_ex* prev_tx; + struct nv_skb_map* prev_tx_ctx; + + /* add fragments to entries count */ + for (i = 0; i < fragments; i++) { + entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) + + ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + } + + empty_slots = nv_get_empty_tx_slots(np); + if (unlikely(empty_slots <= entries)) { + spin_lock_irq(&np->lock); + netif_stop_queue(dev); + np->tx_stop = 1; + spin_unlock_irq(&np->lock); + return NETDEV_TX_BUSY; + } + + start_tx = put_tx = np->put_tx.ex; + + /* setup the header buffer */ + do { + prev_tx = put_tx; + prev_tx_ctx = np->put_tx_ctx; + bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt, + PCI_DMA_TODEVICE); + np->put_tx_ctx->dma_len = bcnt; + put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32; + put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF; + put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); + + tx_flags = NV_TX2_VALID; + offset += bcnt; + size -= bcnt; + if (unlikely(put_tx++ == np->last_tx.ex)) + put_tx = np->first_tx.ex; + if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) + np->put_tx_ctx = np->first_tx_ctx; + } while (size); + + /* setup the fragments */ + for (i = 0; i < fragments; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + u32 size = frag->size; + offset = 0; + + do { + prev_tx = put_tx; + prev_tx_ctx = np->put_tx_ctx; + bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, + PCI_DMA_TODEVICE); + np->put_tx_ctx->dma_len = bcnt; + put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32; + put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF; + put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); + + offset += bcnt; + size -= bcnt; + if (unlikely(put_tx++ == np->last_tx.ex)) + put_tx = np->first_tx.ex; + if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) + np->put_tx_ctx = np->first_tx_ctx; + } while (size); + } + + /* set last fragment flag */ + prev_tx->flaglen |= cpu_to_le32(NV_TX2_LASTPACKET); + + /* save skb in this slot's context area */ + prev_tx_ctx->skb = skb; + + if (skb_is_gso(skb)) + tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT); + else + tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ? + NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0; + + /* vlan tag */ + if (likely(!np->vlangrp)) { + start_tx->txvlan = 0; + } else { + if (vlan_tx_tag_present(skb)) + start_tx->txvlan = cpu_to_le32(NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb)); + else + start_tx->txvlan = 0; + } + + spin_lock_irq(&np->lock); + + /* set tx flags */ + start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra); + np->put_tx.ex = put_tx; + + spin_unlock_irq(&np->lock); + + dprintk(KERN_DEBUG "%s: nv_start_xmit_optimized: entries %d queued for transmission. tx_flags_extra: %x\n", + dev->name, entries, tx_flags_extra); + { + int j; + for (j=0; j<64; j++) { + if ((j%16) == 0) + dprintk("\n%03x:", j); + dprintk(" %02x", ((unsigned char*)skb->data)[j]); + } + dprintk("\n"); + } dev->trans_start = jiffies; - spin_unlock_irq(&np->lock); writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); - pci_push(get_hwbase(dev)); return NETDEV_TX_OK; } @@ -1627,26 +1880,22 @@ static void nv_tx_done(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u32 flags; - unsigned int i; - struct sk_buff *skb; + struct ring_desc* orig_get_tx = np->get_tx.orig; - while (np->nic_tx != np->next_tx) { - i = np->nic_tx % np->tx_ring_size; + while ((np->get_tx.orig != np->put_tx.orig) && + !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID)) { - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - flags = le32_to_cpu(np->tx_ring.orig[i].flaglen); - else - flags = le32_to_cpu(np->tx_ring.ex[i].flaglen); + dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n", + dev->name, flags); + + pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma, + np->get_tx_ctx->dma_len, + PCI_DMA_TODEVICE); + np->get_tx_ctx->dma = 0; - dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, flags 0x%x.\n", - dev->name, np->nic_tx, flags); - if (flags & NV_TX_VALID) - break; if (np->desc_ver == DESC_VER_1) { if (flags & NV_TX_LASTPACKET) { - skb = np->tx_skbuff[i]; - if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| - NV_TX_UNDERFLOW|NV_TX_ERROR)) { + if (flags & NV_TX_ERROR) { if (flags & NV_TX_UNDERFLOW) np->stats.tx_fifo_errors++; if (flags & NV_TX_CARRIERLOST) @@ -1654,14 +1903,14 @@ static void nv_tx_done(struct net_device *dev) np->stats.tx_errors++; } else { np->stats.tx_packets++; - np->stats.tx_bytes += skb->len; + np->stats.tx_bytes += np->get_tx_ctx->skb->len; } + dev_kfree_skb_any(np->get_tx_ctx->skb); + np->get_tx_ctx->skb = NULL; } } else { if (flags & NV_TX2_LASTPACKET) { - skb = np->tx_skbuff[i]; - if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| - NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { + if (flags & NV_TX2_ERROR) { if (flags & NV_TX2_UNDERFLOW) np->stats.tx_fifo_errors++; if (flags & NV_TX2_CARRIERLOST) @@ -1669,15 +1918,56 @@ static void nv_tx_done(struct net_device *dev) np->stats.tx_errors++; } else { np->stats.tx_packets++; - np->stats.tx_bytes += skb->len; + np->stats.tx_bytes += np->get_tx_ctx->skb->len; } + dev_kfree_skb_any(np->get_tx_ctx->skb); + np->get_tx_ctx->skb = NULL; } } - nv_release_txskb(dev, i); - np->nic_tx++; + if (unlikely(np->get_tx.orig++ == np->last_tx.orig)) + np->get_tx.orig = np->first_tx.orig; + if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx)) + np->get_tx_ctx = np->first_tx_ctx; } - if (np->next_tx - np->nic_tx < np->tx_limit_start) + if (unlikely((np->tx_stop == 1) && (np->get_tx.orig != orig_get_tx))) { + np->tx_stop = 0; netif_wake_queue(dev); + } +} + +static void nv_tx_done_optimized(struct net_device *dev, int limit) +{ + struct fe_priv *np = netdev_priv(dev); + u32 flags; + struct ring_desc_ex* orig_get_tx = np->get_tx.ex; + + while ((np->get_tx.ex != np->put_tx.ex) && + !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) && + (limit-- > 0)) { + + dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n", + dev->name, flags); + + pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma, + np->get_tx_ctx->dma_len, + PCI_DMA_TODEVICE); + np->get_tx_ctx->dma = 0; + + if (flags & NV_TX2_LASTPACKET) { + if (!(flags & NV_TX2_ERROR)) + np->stats.tx_packets++; + dev_kfree_skb_any(np->get_tx_ctx->skb); + np->get_tx_ctx->skb = NULL; + } + if (unlikely(np->get_tx.ex++ == np->last_tx.ex)) + np->get_tx.ex = np->first_tx.ex; + if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx)) + np->get_tx_ctx = np->first_tx_ctx; + } + if (unlikely((np->tx_stop == 1) && (np->get_tx.ex != orig_get_tx))) { + np->tx_stop = 0; + netif_wake_queue(dev); + } } /* @@ -1700,9 +1990,8 @@ static void nv_tx_timeout(struct net_device *dev) { int i; - printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n", - dev->name, (unsigned long)np->ring_addr, - np->next_tx, np->nic_tx); + printk(KERN_INFO "%s: Ring at %lx\n", + dev->name, (unsigned long)np->ring_addr); printk(KERN_INFO "%s: Dumping tx registers\n", dev->name); for (i=0;i<=np->register_size;i+= 32) { printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n", @@ -1750,13 +2039,16 @@ static void nv_tx_timeout(struct net_device *dev) nv_stop_tx(dev); /* 2) check that the packets were not sent already: */ - nv_tx_done(dev); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + nv_tx_done(dev); + else + nv_tx_done_optimized(dev, np->tx_ring_size); /* 3) if there are dead entries: clear everything */ - if (np->next_tx != np->nic_tx) { + if (np->get_tx_ctx != np->put_tx_ctx) { printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name); nv_drain_tx(dev); - np->next_tx = np->nic_tx = 0; + nv_init_tx(dev); setup_hw_rings(dev, NV_SETUP_TX_RING); netif_wake_queue(dev); } @@ -1823,40 +2115,27 @@ static int nv_rx_process(struct net_device *dev, int limit) { struct fe_priv *np = netdev_priv(dev); u32 flags; - u32 vlanflags = 0; - int count; + u32 rx_processed_cnt = 0; + struct sk_buff *skb; + int len; - for (count = 0; count < limit; ++count) { - struct sk_buff *skb; - int len; - int i; - if (np->cur_rx - np->refill_rx >= np->rx_ring_size) - break; /* we scanned the whole ring - do not continue */ + while((np->get_rx.orig != np->put_rx.orig) && + !((flags = le32_to_cpu(np->get_rx.orig->flaglen)) & NV_RX_AVAIL) && + (rx_processed_cnt++ < limit)) { - i = np->cur_rx % np->rx_ring_size; - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { - flags = le32_to_cpu(np->rx_ring.orig[i].flaglen); - len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver); - } else { - flags = le32_to_cpu(np->rx_ring.ex[i].flaglen); - len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver); - vlanflags = le32_to_cpu(np->rx_ring.ex[i].buflow); - } - - dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, flags 0x%x.\n", - dev->name, np->cur_rx, flags); - - if (flags & NV_RX_AVAIL) - break; /* still owned by hardware, */ + dprintk(KERN_DEBUG "%s: nv_rx_process: flags 0x%x.\n", + dev->name, flags); /* * the packet is for us - immediately tear down the pci mapping. * TODO: check if a prefetch of the first cacheline improves * the performance. */ - pci_unmap_single(np->pci_dev, np->rx_dma[i], - np->rx_skbuff[i]->end-np->rx_skbuff[i]->data, + pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma, + np->get_rx_ctx->dma_len, PCI_DMA_FROMDEVICE); + skb = np->get_rx_ctx->skb; + np->get_rx_ctx->skb = NULL; { int j; @@ -1864,123 +2143,228 @@ static int nv_rx_process(struct net_device *dev, int limit) for (j=0; j<64; j++) { if ((j%16) == 0) dprintk("\n%03x:", j); - dprintk(" %02x", ((unsigned char*)np->rx_skbuff[i]->data)[j]); + dprintk(" %02x", ((unsigned char*)skb->data)[j]); } dprintk("\n"); } /* look at what we actually got: */ if (np->desc_ver == DESC_VER_1) { - if (!(flags & NV_RX_DESCRIPTORVALID)) - goto next_pkt; - - if (flags & NV_RX_ERROR) { - if (flags & NV_RX_MISSEDFRAME) { - np->stats.rx_missed_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) { - np->stats.rx_errors++; - goto next_pkt; - } - if (flags & NV_RX_CRCERR) { - np->stats.rx_crc_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (flags & NV_RX_OVERFLOW) { - np->stats.rx_over_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (flags & NV_RX_ERROR4) { - len = nv_getlen(dev, np->rx_skbuff[i]->data, len); - if (len < 0) { + if (likely(flags & NV_RX_DESCRIPTORVALID)) { + len = flags & LEN_MASK_V1; + if (unlikely(flags & NV_RX_ERROR)) { + if (flags & NV_RX_ERROR4) { + len = nv_getlen(dev, skb->data, len); + if (len < 0) { + np->stats.rx_errors++; + dev_kfree_skb(skb); + goto next_pkt; + } + } + /* framing errors are soft errors */ + else if (flags & NV_RX_FRAMINGERR) { + if (flags & NV_RX_SUBSTRACT1) { + len--; + } + } + /* the rest are hard errors */ + else { + if (flags & NV_RX_MISSEDFRAME) + np->stats.rx_missed_errors++; + if (flags & NV_RX_CRCERR) + np->stats.rx_crc_errors++; + if (flags & NV_RX_OVERFLOW) + np->stats.rx_over_errors++; np->stats.rx_errors++; + dev_kfree_skb(skb); goto next_pkt; } } - /* framing errors are soft errors. */ - if (flags & NV_RX_FRAMINGERR) { - if (flags & NV_RX_SUBSTRACT1) { - len--; - } - } + } else { + dev_kfree_skb(skb); + goto next_pkt; } } else { - if (!(flags & NV_RX2_DESCRIPTORVALID)) - goto next_pkt; - - if (flags & NV_RX2_ERROR) { - if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) { - np->stats.rx_errors++; - goto next_pkt; - } - if (flags & NV_RX2_CRCERR) { - np->stats.rx_crc_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (flags & NV_RX2_OVERFLOW) { - np->stats.rx_over_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (flags & NV_RX2_ERROR4) { - len = nv_getlen(dev, np->rx_skbuff[i]->data, len); - if (len < 0) { + if (likely(flags & NV_RX2_DESCRIPTORVALID)) { + len = flags & LEN_MASK_V2; + if (unlikely(flags & NV_RX2_ERROR)) { + if (flags & NV_RX2_ERROR4) { + len = nv_getlen(dev, skb->data, len); + if (len < 0) { + np->stats.rx_errors++; + dev_kfree_skb(skb); + goto next_pkt; + } + } + /* framing errors are soft errors */ + else if (flags & NV_RX2_FRAMINGERR) { + if (flags & NV_RX2_SUBSTRACT1) { + len--; + } + } + /* the rest are hard errors */ + else { + if (flags & NV_RX2_CRCERR) + np->stats.rx_crc_errors++; + if (flags & NV_RX2_OVERFLOW) + np->stats.rx_over_errors++; np->stats.rx_errors++; + dev_kfree_skb(skb); goto next_pkt; } } - /* framing errors are soft errors */ - if (flags & NV_RX2_FRAMINGERR) { - if (flags & NV_RX2_SUBSTRACT1) { - len--; + if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 || + (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) { + skb->ip_summed = CHECKSUM_UNNECESSARY; } } - } - if (np->rx_csum) { - flags &= NV_RX2_CHECKSUMMASK; - if (flags == NV_RX2_CHECKSUMOK1 || - flags == NV_RX2_CHECKSUMOK2 || - flags == NV_RX2_CHECKSUMOK3) { - dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name); - np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY; - } else { - dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name); - } + } else { + dev_kfree_skb(skb); + goto next_pkt; } } /* got a valid packet - forward it to the network core */ - skb = np->rx_skbuff[i]; - np->rx_skbuff[i] = NULL; - skb_put(skb, len); skb->protocol = eth_type_trans(skb, dev); - dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n", - dev->name, np->cur_rx, len, skb->protocol); + dprintk(KERN_DEBUG "%s: nv_rx_process: %d bytes, proto %d accepted.\n", + dev->name, len, skb->protocol); #ifdef CONFIG_FORCEDETH_NAPI - if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) - vlan_hwaccel_receive_skb(skb, np->vlangrp, - vlanflags & NV_RX3_VLAN_TAG_MASK); - else - netif_receive_skb(skb); + netif_receive_skb(skb); #else - if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) - vlan_hwaccel_rx(skb, np->vlangrp, - vlanflags & NV_RX3_VLAN_TAG_MASK); - else - netif_rx(skb); + netif_rx(skb); #endif dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += len; next_pkt: - np->cur_rx++; + if (unlikely(np->get_rx.orig++ == np->last_rx.orig)) + np->get_rx.orig = np->first_rx.orig; + if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx)) + np->get_rx_ctx = np->first_rx_ctx; } - return count; + return rx_processed_cnt; +} + +static int nv_rx_process_optimized(struct net_device *dev, int limit) +{ + struct fe_priv *np = netdev_priv(dev); + u32 flags; + u32 vlanflags = 0; + u32 rx_processed_cnt = 0; + struct sk_buff *skb; + int len; + + while((np->get_rx.ex != np->put_rx.ex) && + !((flags = le32_to_cpu(np->get_rx.ex->flaglen)) & NV_RX2_AVAIL) && + (rx_processed_cnt++ < limit)) { + + dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: flags 0x%x.\n", + dev->name, flags); + + /* + * the packet is for us - immediately tear down the pci mapping. + * TODO: check if a prefetch of the first cacheline improves + * the performance. + */ + pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma, + np->get_rx_ctx->dma_len, + PCI_DMA_FROMDEVICE); + skb = np->get_rx_ctx->skb; + np->get_rx_ctx->skb = NULL; + + { + int j; + dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags); + for (j=0; j<64; j++) { + if ((j%16) == 0) + dprintk("\n%03x:", j); + dprintk(" %02x", ((unsigned char*)skb->data)[j]); + } + dprintk("\n"); + } + /* look at what we actually got: */ + if (likely(flags & NV_RX2_DESCRIPTORVALID)) { + len = flags & LEN_MASK_V2; + if (unlikely(flags & NV_RX2_ERROR)) { + if (flags & NV_RX2_ERROR4) { + len = nv_getlen(dev, skb->data, len); + if (len < 0) { + dev_kfree_skb(skb); + goto next_pkt; + } + } + /* framing errors are soft errors */ + else if (flags & NV_RX2_FRAMINGERR) { + if (flags & NV_RX2_SUBSTRACT1) { + len--; + } + } + /* the rest are hard errors */ + else { + dev_kfree_skb(skb); + goto next_pkt; + } + } + + if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 || + (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + } + + /* got a valid packet - forward it to the network core */ + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, dev); + prefetch(skb->data); + + dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: %d bytes, proto %d accepted.\n", + dev->name, len, skb->protocol); + + if (likely(!np->vlangrp)) { +#ifdef CONFIG_FORCEDETH_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif + } else { + vlanflags = le32_to_cpu(np->get_rx.ex->buflow); + if (vlanflags & NV_RX3_VLAN_TAG_PRESENT) { +#ifdef CONFIG_FORCEDETH_NAPI + vlan_hwaccel_receive_skb(skb, np->vlangrp, + vlanflags & NV_RX3_VLAN_TAG_MASK); +#else + vlan_hwaccel_rx(skb, np->vlangrp, + vlanflags & NV_RX3_VLAN_TAG_MASK); +#endif + } else { +#ifdef CONFIG_FORCEDETH_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif + } + } + + dev->last_rx = jiffies; + np->stats.rx_packets++; + np->stats.rx_bytes += len; + } else { + dev_kfree_skb(skb); + } +next_pkt: + if (unlikely(np->get_rx.ex++ == np->last_rx.ex)) + np->get_rx.ex = np->first_rx.ex; + if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx)) + np->get_rx_ctx = np->first_rx_ctx; + } + + return rx_processed_cnt; } static void set_bufsize(struct net_device *dev) @@ -2456,7 +2840,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data) events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); } - pci_push(base); dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) break; @@ -2465,22 +2848,46 @@ static irqreturn_t nv_nic_irq(int foo, void *data) nv_tx_done(dev); spin_unlock(&np->lock); - if (events & NVREG_IRQ_LINK) { +#ifdef CONFIG_FORCEDETH_NAPI + if (events & NVREG_IRQ_RX_ALL) { + netif_rx_schedule(dev); + + /* Disable furthur receive irq's */ + spin_lock(&np->lock); + np->irqmask &= ~NVREG_IRQ_RX_ALL; + + if (np->msi_flags & NV_MSI_X_ENABLED) + writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); + else + writel(np->irqmask, base + NvRegIrqMask); + spin_unlock(&np->lock); + } +#else + if (nv_rx_process(dev, dev->weight)) { + if (unlikely(nv_alloc_rx(dev))) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } + } +#endif + if (unlikely(events & NVREG_IRQ_LINK)) { spin_lock(&np->lock); nv_link_irq(dev); spin_unlock(&np->lock); } - if (np->need_linktimer && time_after(jiffies, np->link_timeout)) { + if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) { spin_lock(&np->lock); nv_linkchange(dev); spin_unlock(&np->lock); np->link_timeout = jiffies + LINK_TIMEOUT; } - if (events & (NVREG_IRQ_TX_ERR)) { + if (unlikely(events & (NVREG_IRQ_TX_ERR))) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", dev->name, events); } - if (events & (NVREG_IRQ_UNKNOWN)) { + if (unlikely(events & (NVREG_IRQ_UNKNOWN))) { printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", dev->name, events); } @@ -2501,30 +2908,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) spin_unlock(&np->lock); break; } -#ifdef CONFIG_FORCEDETH_NAPI - if (events & NVREG_IRQ_RX_ALL) { - netif_rx_schedule(dev); - - /* Disable furthur receive irq's */ - spin_lock(&np->lock); - np->irqmask &= ~NVREG_IRQ_RX_ALL; - - if (np->msi_flags & NV_MSI_X_ENABLED) - writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); - else - writel(np->irqmask, base + NvRegIrqMask); - spin_unlock(&np->lock); - } -#else - nv_rx_process(dev, dev->weight); - if (nv_alloc_rx(dev)) { - spin_lock(&np->lock); - if (!np->in_shutdown) - mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock(&np->lock); - } -#endif - if (i > max_interrupt_work) { + if (unlikely(i > max_interrupt_work)) { spin_lock(&np->lock); /* disable interrupts on the nic */ if (!(np->msi_flags & NV_MSI_X_ENABLED)) @@ -2548,6 +2932,124 @@ static irqreturn_t nv_nic_irq(int foo, void *data) return IRQ_RETVAL(i); } +#define TX_WORK_PER_LOOP 64 +#define RX_WORK_PER_LOOP 64 +/** + * All _optimized functions are used to help increase performance + * (reduce CPU and increase throughput). They use descripter version 3, + * compiler directives, and reduce memory accesses. + */ +static irqreturn_t nv_nic_irq_optimized(int foo, void *data) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + u32 events; + int i; + + dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name); + + for (i=0; ; i++) { + if (!(np->msi_flags & NV_MSI_X_ENABLED)) { + events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + } else { + events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; + writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); + } + dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); + if (!(events & np->irqmask)) + break; + + spin_lock(&np->lock); + nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); + spin_unlock(&np->lock); + +#ifdef CONFIG_FORCEDETH_NAPI + if (events & NVREG_IRQ_RX_ALL) { + netif_rx_schedule(dev); + + /* Disable furthur receive irq's */ + spin_lock(&np->lock); + np->irqmask &= ~NVREG_IRQ_RX_ALL; + + if (np->msi_flags & NV_MSI_X_ENABLED) + writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); + else + writel(np->irqmask, base + NvRegIrqMask); + spin_unlock(&np->lock); + } +#else + if (nv_rx_process_optimized(dev, dev->weight)) { + if (unlikely(nv_alloc_rx_optimized(dev))) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } + } +#endif + if (unlikely(events & NVREG_IRQ_LINK)) { + spin_lock(&np->lock); + nv_link_irq(dev); + spin_unlock(&np->lock); + } + if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) { + spin_lock(&np->lock); + nv_linkchange(dev); + spin_unlock(&np->lock); + np->link_timeout = jiffies + LINK_TIMEOUT; + } + if (unlikely(events & (NVREG_IRQ_TX_ERR))) { + dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", + dev->name, events); + } + if (unlikely(events & (NVREG_IRQ_UNKNOWN))) { + printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", + dev->name, events); + } + if (unlikely(events & NVREG_IRQ_RECOVER_ERROR)) { + spin_lock(&np->lock); + /* disable interrupts on the nic */ + if (!(np->msi_flags & NV_MSI_X_ENABLED)) + writel(0, base + NvRegIrqMask); + else + writel(np->irqmask, base + NvRegIrqMask); + pci_push(base); + + if (!np->in_shutdown) { + np->nic_poll_irq = np->irqmask; + np->recover_error = 1; + mod_timer(&np->nic_poll, jiffies + POLL_WAIT); + } + spin_unlock(&np->lock); + break; + } + + if (unlikely(i > max_interrupt_work)) { + spin_lock(&np->lock); + /* disable interrupts on the nic */ + if (!(np->msi_flags & NV_MSI_X_ENABLED)) + writel(0, base + NvRegIrqMask); + else + writel(np->irqmask, base + NvRegIrqMask); + pci_push(base); + + if (!np->in_shutdown) { + np->nic_poll_irq = np->irqmask; + mod_timer(&np->nic_poll, jiffies + POLL_WAIT); + } + printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i); + spin_unlock(&np->lock); + break; + } + + } + dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name); + + return IRQ_RETVAL(i); +} + static irqreturn_t nv_nic_irq_tx(int foo, void *data) { struct net_device *dev = (struct net_device *) data; @@ -2562,20 +3064,19 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data) for (i=0; ; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL; writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus); - pci_push(base); dprintk(KERN_DEBUG "%s: tx irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) break; spin_lock_irqsave(&np->lock, flags); - nv_tx_done(dev); + nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); spin_unlock_irqrestore(&np->lock, flags); - if (events & (NVREG_IRQ_TX_ERR)) { + if (unlikely(events & (NVREG_IRQ_TX_ERR))) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", dev->name, events); } - if (i > max_interrupt_work) { + if (unlikely(i > max_interrupt_work)) { spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask); @@ -2604,7 +3105,10 @@ static int nv_napi_poll(struct net_device *dev, int *budget) u8 __iomem *base = get_hwbase(dev); unsigned long flags; - pkts = nv_rx_process(dev, limit); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + pkts = nv_rx_process(dev, limit); + else + pkts = nv_rx_process_optimized(dev, limit); if (nv_alloc_rx(dev)) { spin_lock_irqsave(&np->lock, flags); @@ -2670,20 +3174,20 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) for (i=0; ; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL; writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); - pci_push(base); dprintk(KERN_DEBUG "%s: rx irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) break; - nv_rx_process(dev, dev->weight); - if (nv_alloc_rx(dev)) { - spin_lock_irqsave(&np->lock, flags); - if (!np->in_shutdown) - mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock_irqrestore(&np->lock, flags); + if (nv_rx_process_optimized(dev, dev->weight)) { + if (unlikely(nv_alloc_rx_optimized(dev))) { + spin_lock_irqsave(&np->lock, flags); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock_irqrestore(&np->lock, flags); + } } - if (i > max_interrupt_work) { + if (unlikely(i > max_interrupt_work)) { spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); @@ -2718,11 +3222,15 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data) for (i=0; ; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_OTHER; writel(NVREG_IRQ_OTHER, base + NvRegMSIXIrqStatus); - pci_push(base); dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) break; + /* check tx in case we reached max loop limit in tx isr */ + spin_lock_irqsave(&np->lock, flags); + nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); + spin_unlock_irqrestore(&np->lock, flags); + if (events & NVREG_IRQ_LINK) { spin_lock_irqsave(&np->lock, flags); nv_link_irq(dev); @@ -2752,7 +3260,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data) printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", dev->name, events); } - if (i > max_interrupt_work) { + if (unlikely(i > max_interrupt_work)) { spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_OTHER, base + NvRegIrqMask); @@ -2835,6 +3343,16 @@ static int nv_request_irq(struct net_device *dev, int intr_test) u8 __iomem *base = get_hwbase(dev); int ret = 1; int i; + irqreturn_t (*handler)(int foo, void *data); + + if (intr_test) { + handler = nv_nic_irq_test; + } else { + if (np->desc_ver == DESC_VER_3) + handler = nv_nic_irq_optimized; + else + handler = nv_nic_irq; + } if (np->msi_flags & NV_MSI_X_CAPABLE) { for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) { @@ -2872,10 +3390,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test) set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER); } else { /* Request irq for all interrupts */ - if ((!intr_test && - request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) || - (intr_test && - request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) { + if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, handler, IRQF_SHARED, dev->name, dev) != 0) { printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret); pci_disable_msix(np->pci_dev); np->msi_flags &= ~NV_MSI_X_ENABLED; @@ -2891,8 +3406,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test) if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) { if ((ret = pci_enable_msi(np->pci_dev)) == 0) { np->msi_flags |= NV_MSI_ENABLED; - if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) || - (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) { + if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) { printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret); pci_disable_msi(np->pci_dev); np->msi_flags &= ~NV_MSI_ENABLED; @@ -2907,8 +3421,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test) } } if (ret != 0) { - if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) || - (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) + if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) goto out_err; } @@ -3051,47 +3564,8 @@ static void nv_do_stats_poll(unsigned long data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); - u8 __iomem *base = get_hwbase(dev); - np->estats.tx_bytes += readl(base + NvRegTxCnt); - np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt); - np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt); - np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt); - np->estats.tx_late_collision += readl(base + NvRegTxLateCol); - np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow); - np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier); - np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef); - np->estats.tx_retry_error += readl(base + NvRegTxRetryErr); - np->estats.tx_deferral += readl(base + NvRegTxDef); - np->estats.tx_packets += readl(base + NvRegTxFrame); - np->estats.tx_pause += readl(base + NvRegTxPause); - np->estats.rx_frame_error += readl(base + NvRegRxFrameErr); - np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte); - np->estats.rx_late_collision += readl(base + NvRegRxLateCol); - np->estats.rx_runt += readl(base + NvRegRxRunt); - np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong); - np->estats.rx_over_errors += readl(base + NvRegRxOverflow); - np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr); - np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr); - np->estats.rx_length_error += readl(base + NvRegRxLenErr); - np->estats.rx_unicast += readl(base + NvRegRxUnicast); - np->estats.rx_multicast += readl(base + NvRegRxMulticast); - np->estats.rx_broadcast += readl(base + NvRegRxBroadcast); - np->estats.rx_bytes += readl(base + NvRegRxCnt); - np->estats.rx_pause += readl(base + NvRegRxPause); - np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame); - np->estats.rx_packets = - np->estats.rx_unicast + - np->estats.rx_multicast + - np->estats.rx_broadcast; - np->estats.rx_errors_total = - np->estats.rx_crc_errors + - np->estats.rx_over_errors + - np->estats.rx_frame_error + - (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) + - np->estats.rx_late_collision + - np->estats.rx_runt + - np->estats.rx_frame_too_long; + nv_get_hw_stats(dev); if (!np->in_shutdown) mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL); @@ -3465,7 +3939,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - u8 *rxtx_ring, *rx_skbuff, *tx_skbuff, *rx_dma, *tx_dma, *tx_dma_len; + u8 *rxtx_ring, *rx_skbuff, *tx_skbuff; dma_addr_t ring_addr; if (ring->rx_pending < RX_RING_MIN || @@ -3491,12 +3965,9 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri sizeof(struct ring_desc_ex) * (ring->rx_pending + ring->tx_pending), &ring_addr); } - rx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->rx_pending, GFP_KERNEL); - rx_dma = kmalloc(sizeof(dma_addr_t) * ring->rx_pending, GFP_KERNEL); - tx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->tx_pending, GFP_KERNEL); - tx_dma = kmalloc(sizeof(dma_addr_t) * ring->tx_pending, GFP_KERNEL); - tx_dma_len = kmalloc(sizeof(unsigned int) * ring->tx_pending, GFP_KERNEL); - if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) { + rx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->rx_pending, GFP_KERNEL); + tx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->tx_pending, GFP_KERNEL); + if (!rxtx_ring || !rx_skbuff || !tx_skbuff) { /* fall back to old rings */ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { if (rxtx_ring) @@ -3509,14 +3980,8 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri } if (rx_skbuff) kfree(rx_skbuff); - if (rx_dma) - kfree(rx_dma); if (tx_skbuff) kfree(tx_skbuff); - if (tx_dma) - kfree(tx_dma); - if (tx_dma_len) - kfree(tx_dma_len); goto exit; } @@ -3538,8 +4003,6 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri /* set new values */ np->rx_ring_size = ring->rx_pending; np->tx_ring_size = ring->tx_pending; - np->tx_limit_stop = ring->tx_pending - TX_LIMIT_DIFFERENCE; - np->tx_limit_start = ring->tx_pending - TX_LIMIT_DIFFERENCE - 1; if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->rx_ring.orig = (struct ring_desc*)rxtx_ring; np->tx_ring.orig = &np->rx_ring.orig[np->rx_ring_size]; @@ -3547,18 +4010,12 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri np->rx_ring.ex = (struct ring_desc_ex*)rxtx_ring; np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size]; } - np->rx_skbuff = (struct sk_buff**)rx_skbuff; - np->rx_dma = (dma_addr_t*)rx_dma; - np->tx_skbuff = (struct sk_buff**)tx_skbuff; - np->tx_dma = (dma_addr_t*)tx_dma; - np->tx_dma_len = (unsigned int*)tx_dma_len; + np->rx_skb = (struct nv_skb_map*)rx_skbuff; + np->tx_skb = (struct nv_skb_map*)tx_skbuff; np->ring_addr = ring_addr; - memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size); - memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size); - memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size); - memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size); - memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size); + memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size); + memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size); if (netif_running(dev)) { /* reinit driver view of the queues */ @@ -3727,8 +4184,10 @@ static int nv_get_stats_count(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); - if (np->driver_data & DEV_HAS_STATISTICS) - return sizeof(struct nv_ethtool_stats)/sizeof(u64); + if (np->driver_data & DEV_HAS_STATISTICS_V1) + return NV_DEV_STATISTICS_V1_COUNT; + else if (np->driver_data & DEV_HAS_STATISTICS_V2) + return NV_DEV_STATISTICS_V2_COUNT; else return 0; } @@ -3955,7 +4414,7 @@ static int nv_loopback_test(struct net_device *dev) dprintk(KERN_DEBUG "%s: loopback len mismatch %d vs %d\n", dev->name, len, pkt_len); } else { - rx_skb = np->rx_skbuff[0]; + rx_skb = np->rx_skb[0].skb; for (i = 0; i < pkt_len; i++) { if (rx_skb->data[i] != (u8)(i & 0xff)) { ret = 0; @@ -4315,7 +4774,7 @@ static int nv_open(struct net_device *dev) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); /* start statistics timer */ - if (np->driver_data & DEV_HAS_STATISTICS) + if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2)) mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL); spin_unlock_irq(&np->lock); @@ -4412,7 +4871,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (err < 0) goto out_disable; - if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS)) + if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V2)) + np->register_size = NV_PCI_REGSZ_VER3; + else if (id->driver_data & DEV_HAS_STATISTICS_V1) np->register_size = NV_PCI_REGSZ_VER2; else np->register_size = NV_PCI_REGSZ_VER1; @@ -4475,10 +4936,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->rx_csum = 1; np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; -#ifdef NETIF_F_TSO dev->features |= NETIF_F_TSO; -#endif - } + } np->vlanctl_bits = 0; if (id->driver_data & DEV_HAS_VLAN) { @@ -4512,8 +4971,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i np->rx_ring_size = RX_RING_DEFAULT; np->tx_ring_size = TX_RING_DEFAULT; - np->tx_limit_stop = np->tx_ring_size - TX_LIMIT_DIFFERENCE; - np->tx_limit_start = np->tx_ring_size - TX_LIMIT_DIFFERENCE - 1; if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->rx_ring.orig = pci_alloc_consistent(pci_dev, @@ -4530,22 +4987,19 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i goto out_unmap; np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size]; } - np->rx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->rx_ring_size, GFP_KERNEL); - np->rx_dma = kmalloc(sizeof(dma_addr_t) * np->rx_ring_size, GFP_KERNEL); - np->tx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->tx_ring_size, GFP_KERNEL); - np->tx_dma = kmalloc(sizeof(dma_addr_t) * np->tx_ring_size, GFP_KERNEL); - np->tx_dma_len = kmalloc(sizeof(unsigned int) * np->tx_ring_size, GFP_KERNEL); - if (!np->rx_skbuff || !np->rx_dma || !np->tx_skbuff || !np->tx_dma || !np->tx_dma_len) + np->rx_skb = kmalloc(sizeof(struct nv_skb_map) * np->rx_ring_size, GFP_KERNEL); + np->tx_skb = kmalloc(sizeof(struct nv_skb_map) * np->tx_ring_size, GFP_KERNEL); + if (!np->rx_skb || !np->tx_skb) goto out_freering; - memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size); - memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size); - memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size); - memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size); - memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size); + memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size); + memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size); dev->open = nv_open; dev->stop = nv_close; - dev->hard_start_xmit = nv_start_xmit; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + dev->hard_start_xmit = nv_start_xmit; + else + dev->hard_start_xmit = nv_start_xmit_optimized; dev->get_stats = nv_get_stats; dev->change_mtu = nv_change_mtu; dev->set_mac_address = nv_set_mac_address; @@ -4553,7 +5007,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = nv_poll_controller; #endif - dev->weight = 64; + dev->weight = RX_WORK_PER_LOOP; #ifdef CONFIG_FORCEDETH_NAPI dev->poll = nv_napi_poll; #endif @@ -4868,83 +5322,83 @@ static struct pci_device_id pci_tbl[] = { }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, }, { /* CK804 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, }, { /* MCP04 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1, }, { /* MCP51 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, }, { /* MCP51 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, {0,}, }; diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 844c136e9920..7dc5185aa2c0 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -3034,7 +3034,7 @@ static int __init hp100_module_init(void) goto out2; #endif #ifdef CONFIG_PCI - err = pci_module_init(&hp100_pci_driver); + err = pci_register_driver(&hp100_pci_driver); if (err && err != -ENODEV) goto out3; #endif 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/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index f4aba4355b19..cf30a1059ce0 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -61,9 +61,7 @@ #include #include #include -#ifdef NETIF_F_TSO #include -#endif #include #include diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 82c044d6e08a..d6628bd9590a 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -82,10 +82,8 @@ static struct ixgb_stats ixgb_gstrings_stats[] = { {"tx_restart_queue", IXGB_STAT(restart_queue) }, {"rx_long_length_errors", IXGB_STAT(stats.roc)}, {"rx_short_length_errors", IXGB_STAT(stats.ruc)}, -#ifdef NETIF_F_TSO {"tx_tcp_seg_good", IXGB_STAT(stats.tsctc)}, {"tx_tcp_seg_failed", IXGB_STAT(stats.tsctfc)}, -#endif {"rx_flow_control_xon", IXGB_STAT(stats.xonrxc)}, {"rx_flow_control_xoff", IXGB_STAT(stats.xoffrxc)}, {"tx_flow_control_xon", IXGB_STAT(stats.xontxc)}, @@ -240,7 +238,6 @@ ixgb_set_tx_csum(struct net_device *netdev, uint32_t data) return 0; } -#ifdef NETIF_F_TSO static int ixgb_set_tso(struct net_device *netdev, uint32_t data) { @@ -250,7 +247,6 @@ ixgb_set_tso(struct net_device *netdev, uint32_t data) netdev->features &= ~NETIF_F_TSO; return 0; } -#endif /* NETIF_F_TSO */ static uint32_t ixgb_get_msglevel(struct net_device *netdev) @@ -722,10 +718,8 @@ static const struct ethtool_ops ixgb_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_msglevel = ixgb_get_msglevel, .set_msglevel = ixgb_set_msglevel, -#ifdef NETIF_F_TSO .get_tso = ethtool_op_get_tso, .set_tso = ixgb_set_tso, -#endif .get_strings = ixgb_get_strings, .phys_id = ixgb_phys_id, .get_stats_count = ixgb_get_stats_count, diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index a083a9189230..0c3682889344 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -456,9 +456,7 @@ ixgb_probe(struct pci_dev *pdev, NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; -#ifdef NETIF_F_TSO netdev->features |= NETIF_F_TSO; -#endif #ifdef NETIF_F_LLTX netdev->features |= NETIF_F_LLTX; #endif @@ -1176,7 +1174,6 @@ ixgb_watchdog(unsigned long data) static int ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb) { -#ifdef NETIF_F_TSO struct ixgb_context_desc *context_desc; unsigned int i; uint8_t ipcss, ipcso, tucss, tucso, hdr_len; @@ -1233,7 +1230,6 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb) return 1; } -#endif return 0; } @@ -1609,7 +1605,7 @@ ixgb_update_stats(struct ixgb_adapter *adapter) struct pci_dev *pdev = adapter->pdev; /* Prevent stats update while adapter is being reset */ - if (pdev->error_state && pdev->error_state != pci_channel_io_normal) + if (pci_channel_offline(pdev)) return; if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) || diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 25b559b5d5ed..e67361e2bf5d 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", @@ -1046,6 +1046,14 @@ static int __devinit macb_probe(struct platform_device *pdev) spin_lock_init(&bp->lock); +#if defined(CONFIG_ARCH_AT91) + bp->pclk = clk_get(&pdev->dev, "macb_clk"); + if (IS_ERR(bp->pclk)) { + dev_err(&pdev->dev, "failed to get macb_clk\n"); + goto err_out_free_dev; + } + clk_enable(bp->pclk); +#else bp->pclk = clk_get(&pdev->dev, "pclk"); if (IS_ERR(bp->pclk)) { dev_err(&pdev->dev, "failed to get pclk\n"); @@ -1059,6 +1067,7 @@ static int __devinit macb_probe(struct platform_device *pdev) clk_enable(bp->pclk); clk_enable(bp->hclk); +#endif bp->regs = ioremap(regs->start, regs->end - regs->start + 1); if (!bp->regs) { @@ -1119,9 +1128,17 @@ static int __devinit macb_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; if (pdata && pdata->is_rmii) +#if defined(CONFIG_ARCH_AT91) + macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) ); +#else macb_writel(bp, USRIO, 0); +#endif else +#if defined(CONFIG_ARCH_AT91) + macb_writel(bp, USRIO, MACB_BIT(CLKEN)); +#else macb_writel(bp, USRIO, MACB_BIT(MII)); +#endif bp->tx_pending = DEF_TX_RING_PENDING; @@ -1148,9 +1165,11 @@ err_out_free_irq: err_out_iounmap: iounmap(bp->regs); err_out_disable_clocks: +#ifndef CONFIG_ARCH_AT91 clk_disable(bp->hclk); - clk_disable(bp->pclk); clk_put(bp->hclk); +#endif + clk_disable(bp->pclk); err_out_put_pclk: clk_put(bp->pclk); err_out_free_dev: @@ -1173,9 +1192,11 @@ static int __devexit macb_remove(struct platform_device *pdev) unregister_netdev(dev); free_irq(dev->irq, dev); iounmap(bp->regs); +#ifndef CONFIG_ARCH_AT91 clk_disable(bp->hclk); - clk_disable(bp->pclk); clk_put(bp->hclk); +#endif + clk_disable(bp->pclk); clk_put(bp->pclk); free_netdev(dev); platform_set_drvdata(pdev, NULL); diff --git a/drivers/net/macb.h b/drivers/net/macb.h index 27bf0ae0f0bb..b3bb2182edd1 100644 --- a/drivers/net/macb.h +++ b/drivers/net/macb.h @@ -200,7 +200,7 @@ #define MACB_SOF_OFFSET 30 #define MACB_SOF_SIZE 2 -/* Bitfields in USRIO */ +/* Bitfields in USRIO (AVR32) */ #define MACB_MII_OFFSET 0 #define MACB_MII_SIZE 1 #define MACB_EAM_OFFSET 1 @@ -210,6 +210,12 @@ #define MACB_TX_PAUSE_ZERO_OFFSET 3 #define MACB_TX_PAUSE_ZERO_SIZE 1 +/* Bitfields in USRIO (AT91) */ +#define MACB_RMII_OFFSET 0 +#define MACB_RMII_SIZE 1 +#define MACB_CLKEN_OFFSET 1 +#define MACB_CLKEN_SIZE 1 + /* Bitfields in WOL */ #define MACB_IP_OFFSET 0 #define MACB_IP_SIZE 16 diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 2907cfb12ada..9ec24f0d5d68 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -74,7 +75,6 @@ struct mace_data { #define PRIV_BYTES (sizeof(struct mace_data) \ + (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd)) -static int bitrev(int); static int mace_open(struct net_device *dev); static int mace_close(struct net_device *dev); static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); @@ -96,18 +96,6 @@ static void __mace_set_address(struct net_device *dev, void *addr); */ static unsigned char *dummy_buf; -/* Bit-reverse one byte of an ethernet hardware address. */ -static inline int -bitrev(int b) -{ - int d = 0, i; - - for (i = 0; i < 8; ++i, b >>= 1) - d = (d << 1) | (b & 1); - return d; -} - - static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_id *match) { struct device_node *mace = macio_get_of_node(mdev); @@ -173,7 +161,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i rev = addr[0] == 0 && addr[1] == 0xA0; for (j = 0; j < 6; ++j) { - dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j]; + dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j]; } mp->chipid = (in_8(&mp->mace->chipid_hi) << 8) | in_8(&mp->mace->chipid_lo); diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 464e4a6f3d5f..5d541e873041 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -81,19 +82,6 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id); static irqreturn_t mace_dma_intr(int irq, void *dev_id); static void mace_tx_timeout(struct net_device *dev); -/* Bit-reverse one byte of an ethernet hardware address. */ - -static int bitrev(int b) -{ - int d = 0, i; - - for (i = 0; i < 8; ++i, b >>= 1) { - d = (d << 1) | (b & 1); - } - - return d; -} - /* * Load a receive DMA channel with a base address and ring length */ @@ -219,12 +207,12 @@ struct net_device *mace_probe(int unit) addr = (void *)MACE_PROM; for (j = 0; j < 6; ++j) { - u8 v=bitrev(addr[j<<4]); + u8 v = bitrev8(addr[j<<4]); checksum ^= v; dev->dev_addr[j] = v; } for (; j < 8; ++j) { - checksum ^= bitrev(addr[j<<4]); + checksum ^= bitrev8(addr[j<<4]); } if (checksum != 0xFF) { diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index 393d995f1919..24f6050fbf33 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -121,16 +121,12 @@ enum macsonic_type { * For reversing the PROM address */ -static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14, - 1, 9, 5, 13, 3, 11, 7, 15}; - static inline void bit_reverse_addr(unsigned char addr[6]) { int i; for(i = 0; i < 6; i++) - addr[i] = ((nibbletab[addr[i] & 0xf] << 4) | - nibbletab[(addr[i] >> 4) &0xf]); + addr[i] = bitrev8(addr[i]); } int __init macsonic_init(struct net_device* dev) diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 61cbd4a60446..030924fb1ab3 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1412,10 +1412,8 @@ static const struct ethtool_ops myri10ge_ethtool_ops = { .set_tx_csum = ethtool_op_set_tx_hw_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, -#ifdef NETIF_F_TSO .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, -#endif .get_strings = myri10ge_get_strings, .get_stats_count = myri10ge_get_stats_count, .get_ethtool_stats = myri10ge_get_ethtool_stats, @@ -1975,13 +1973,11 @@ again: mss = 0; max_segments = MXGEFW_MAX_SEND_DESC; -#ifdef NETIF_F_TSO if (skb->len > (dev->mtu + ETH_HLEN)) { mss = skb_shinfo(skb)->gso_size; if (mss != 0) max_segments = MYRI10GE_MAX_SEND_DESC_TSO; } -#endif /*NETIF_F_TSO */ if ((unlikely(avail < max_segments))) { /* we are out of transmit resources */ @@ -2013,7 +2009,6 @@ again: cum_len = 0; -#ifdef NETIF_F_TSO if (mss) { /* TSO */ /* this removes any CKSUM flag from before */ flags = (MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST); @@ -2029,7 +2024,6 @@ again: * the checksum by parsing the header. */ pseudo_hdr_offset = mss; } else -#endif /*NETIF_F_TSO */ /* Mark small packets, and pad out tiny packets */ if (skb->len <= MXGEFW_SEND_SMALL_SIZE) { flags |= MXGEFW_FLAGS_SMALL; @@ -2097,7 +2091,6 @@ again: seglen = len; flags_next = flags & ~MXGEFW_FLAGS_FIRST; cum_len_next = cum_len + seglen; -#ifdef NETIF_F_TSO if (mss) { /* TSO */ (req - rdma_count)->rdma_count = rdma_count + 1; @@ -2124,7 +2117,6 @@ again: (small * MXGEFW_FLAGS_SMALL); } } -#endif /* NETIF_F_TSO */ req->addr_high = high_swapped; req->addr_low = htonl(low); req->pseudo_hdr_offset = htons(pseudo_hdr_offset); @@ -2161,14 +2153,12 @@ again: } (req - rdma_count)->rdma_count = rdma_count; -#ifdef NETIF_F_TSO if (mss) do { req--; req->flags |= MXGEFW_FLAGS_TSO_LAST; } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | MXGEFW_FLAGS_FIRST))); -#endif idx = ((count - 1) + tx->req) & tx->mask; tx->info[idx].last = 1; if (tx->wc_fifo == NULL) diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index e8598b809228..3f3896e98879 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -63,11 +63,14 @@ #include "netxen_nic_hw.h" -#define NETXEN_NIC_BUILD_NO "2" #define _NETXEN_NIC_LINUX_MAJOR 3 #define _NETXEN_NIC_LINUX_MINOR 3 #define _NETXEN_NIC_LINUX_SUBVERSION 3 -#define NETXEN_NIC_LINUX_VERSIONID "3.3.3" "-" NETXEN_NIC_BUILD_NO +#define NETXEN_NIC_LINUX_VERSIONID "3.3.3" + +#define NUM_FLASH_SECTORS (64) +#define FLASH_SECTOR_SIZE (64 * 1024) +#define FLASH_TOTAL_SIZE (NUM_FLASH_SECTORS * FLASH_SECTOR_SIZE) #define RCV_DESC_RINGSIZE \ (sizeof(struct rcv_desc) * adapter->max_rx_desc_count) @@ -85,6 +88,7 @@ #define NETXEN_RCV_PRODUCER_OFFSET 0 #define NETXEN_RCV_PEG_DB_ID 2 #define NETXEN_HOST_DUMMY_DMA_SIZE 1024 +#define FLASH_SUCCESS 0 #define ADDR_IN_WINDOW1(off) \ ((off > NETXEN_CRB_PCIX_HOST2) && (off < NETXEN_CRB_MAX)) ? 1 : 0 @@ -1028,6 +1032,15 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val); void netxen_load_firmware(struct netxen_adapter *adapter); int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose); int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp); +int netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, + u8 *bytes, size_t size); +int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, + u8 *bytes, size_t size); +int netxen_flash_unlock(struct netxen_adapter *adapter); +int netxen_backup_crbinit(struct netxen_adapter *adapter); +int netxen_flash_erase_secondary(struct netxen_adapter *adapter); +int netxen_flash_erase_primary(struct netxen_adapter *adapter); + int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data); int netxen_rom_se(struct netxen_adapter *adapter, int addr); int netxen_do_rom_se(struct netxen_adapter *adapter, int addr); diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index c381d77a7336..cc0efe213e01 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -32,6 +32,7 @@ */ #include +#include #include #include #include @@ -94,17 +95,7 @@ static const char netxen_nic_gstrings_test[][ETH_GSTRING_LEN] = { static int netxen_nic_get_eeprom_len(struct net_device *dev) { - struct netxen_port *port = netdev_priv(dev); - struct netxen_adapter *adapter = port->adapter; - int n; - - if ((netxen_rom_fast_read(adapter, 0, &n) == 0) - && (n & NETXEN_ROM_ROUNDUP)) { - n &= ~NETXEN_ROM_ROUNDUP; - if (n < NETXEN_MAX_EEPROM_LEN) - return n; - } - return 0; + return FLASH_TOTAL_SIZE; } static void @@ -440,18 +431,92 @@ netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, struct netxen_port *port = netdev_priv(dev); struct netxen_adapter *adapter = port->adapter; int offset; + int ret; if (eeprom->len == 0) return -EINVAL; eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16); - for (offset = 0; offset < eeprom->len; offset++) - if (netxen_rom_fast_read - (adapter, (8 * offset) + 8, (int *)eeprom->data) == -1) - return -EIO; + offset = eeprom->offset; + + ret = netxen_rom_fast_read_words(adapter, offset, bytes, + eeprom->len); + if (ret < 0) + return ret; + return 0; } +static int +netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, + u8 * bytes) +{ + struct netxen_port *port = netdev_priv(dev); + struct netxen_adapter *adapter = port->adapter; + int offset = eeprom->offset; + static int flash_start; + static int ready_to_flash; + int ret; + + if (flash_start == 0) { + ret = netxen_flash_unlock(adapter); + if (ret < 0) { + printk(KERN_ERR "%s: Flash unlock failed.\n", + netxen_nic_driver_name); + return ret; + } + printk(KERN_INFO "%s: flash unlocked. \n", + netxen_nic_driver_name); + ret = netxen_flash_erase_secondary(adapter); + if (ret != FLASH_SUCCESS) { + printk(KERN_ERR "%s: Flash erase failed.\n", + netxen_nic_driver_name); + return ret; + } + printk(KERN_INFO "%s: secondary flash erased successfully.\n", + netxen_nic_driver_name); + flash_start = 1; + return 0; + } + + if (offset == BOOTLD_START) { + ret = netxen_flash_erase_primary(adapter); + if (ret != FLASH_SUCCESS) { + printk(KERN_ERR "%s: Flash erase failed.\n", + netxen_nic_driver_name); + return ret; + } + + ret = netxen_rom_se(adapter, USER_START); + if (ret != FLASH_SUCCESS) + return ret; + ret = netxen_rom_se(adapter, FIXED_START); + if (ret != FLASH_SUCCESS) + return ret; + + printk(KERN_INFO "%s: primary flash erased successfully\n", + netxen_nic_driver_name); + + ret = netxen_backup_crbinit(adapter); + if (ret != FLASH_SUCCESS) { + printk(KERN_ERR "%s: CRBinit backup failed.\n", + netxen_nic_driver_name); + return ret; + } + printk(KERN_INFO "%s: CRBinit backup done.\n", + netxen_nic_driver_name); + ready_to_flash = 1; + } + + if (!ready_to_flash) { + printk(KERN_ERR "%s: Invalid write sequence, returning...\n", + netxen_nic_driver_name); + return -EINVAL; + } + + return netxen_rom_fast_write_words(adapter, offset, bytes, eeprom->len); +} + static void netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) { @@ -721,6 +786,7 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .get_link = netxen_nic_get_link, .get_eeprom_len = netxen_nic_get_eeprom_len, .get_eeprom = netxen_nic_get_eeprom, + .set_eeprom = netxen_nic_set_eeprom, .get_ringparam = netxen_nic_get_ringparam, .get_pauseparam = netxen_nic_get_pauseparam, .set_pauseparam = netxen_nic_set_pauseparam, diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 973af96337a9..f7bb8c90537c 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -110,6 +110,7 @@ static void crb_addr_transform_setup(void) crb_addr_transform(CAM); crb_addr_transform(C2C1); crb_addr_transform(C2C0); + crb_addr_transform(SMB); } int netxen_init_firmware(struct netxen_adapter *adapter) @@ -276,6 +277,7 @@ unsigned long netxen_decode_crb_addr(unsigned long addr) static long rom_max_timeout = 10000; static long rom_lock_timeout = 1000000; +static long rom_write_timeout = 700; static inline int rom_lock(struct netxen_adapter *adapter) { @@ -404,7 +406,7 @@ do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) { netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr); netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3); - udelay(100); /* prevent bursting on CRB */ + udelay(70); /* prevent bursting on CRB */ netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb); if (netxen_wait_rom_done(adapter)) { @@ -413,13 +415,46 @@ do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) } /* reset abyte_cnt and dummy_byte_cnt */ netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0); - udelay(100); /* prevent bursting on CRB */ + udelay(70); /* prevent bursting on CRB */ netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); *valp = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_ROM_RDATA); return 0; } +static inline int +do_rom_fast_read_words(struct netxen_adapter *adapter, int addr, + u8 *bytes, size_t size) +{ + int addridx; + int ret = 0; + + for (addridx = addr; addridx < (addr + size); addridx += 4) { + ret = do_rom_fast_read(adapter, addridx, (int *)bytes); + if (ret != 0) + break; + bytes += 4; + } + + return ret; +} + +int +netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, + u8 *bytes, size_t size) +{ + int ret; + + ret = rom_lock(adapter); + if (ret < 0) + return ret; + + ret = do_rom_fast_read_words(adapter, addr, bytes, size); + + netxen_rom_unlock(adapter); + return ret; +} + int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) { int ret; @@ -443,6 +478,152 @@ int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data) netxen_rom_unlock(adapter); return ret; } + +static inline int do_rom_fast_write_words(struct netxen_adapter *adapter, + int addr, u8 *bytes, size_t size) +{ + int addridx = addr; + int ret = 0; + + while (addridx < (addr + size)) { + int last_attempt = 0; + int timeout = 0; + int data; + + data = *(u32*)bytes; + + ret = do_rom_fast_write(adapter, addridx, data); + if (ret < 0) + return ret; + + while(1) { + int data1; + + do_rom_fast_read(adapter, addridx, &data1); + if (data1 == data) + break; + + if (timeout++ >= rom_write_timeout) { + if (last_attempt++ < 4) { + ret = do_rom_fast_write(adapter, + addridx, data); + if (ret < 0) + return ret; + } + else { + printk(KERN_INFO "Data write did not " + "succeed at address 0x%x\n", addridx); + break; + } + } + } + + bytes += 4; + addridx += 4; + } + + return ret; +} + +int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, + u8 *bytes, size_t size) +{ + int ret = 0; + + ret = rom_lock(adapter); + if (ret < 0) + return ret; + + ret = do_rom_fast_write_words(adapter, addr, bytes, size); + netxen_rom_unlock(adapter); + + return ret; +} + +int netxen_rom_wrsr(struct netxen_adapter *adapter, int data) +{ + int ret; + + ret = netxen_rom_wren(adapter); + if (ret < 0) + return ret; + + netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_ROM_WDATA, data); + netxen_crb_writelit_adapter(adapter, + NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0x1); + + ret = netxen_wait_rom_done(adapter); + if (ret < 0) + return ret; + + return netxen_rom_wip_poll(adapter); +} + +int netxen_rom_rdsr(struct netxen_adapter *adapter) +{ + int ret; + + ret = rom_lock(adapter); + if (ret < 0) + return ret; + + ret = netxen_do_rom_rdsr(adapter); + netxen_rom_unlock(adapter); + return ret; +} + +int netxen_backup_crbinit(struct netxen_adapter *adapter) +{ + int ret = FLASH_SUCCESS; + int val; + char *buffer = kmalloc(FLASH_SECTOR_SIZE, GFP_KERNEL); + + if (!buffer) + return -ENOMEM; + /* unlock sector 63 */ + val = netxen_rom_rdsr(adapter); + val = val & 0xe3; + ret = netxen_rom_wrsr(adapter, val); + if (ret != FLASH_SUCCESS) + goto out_kfree; + + ret = netxen_rom_wip_poll(adapter); + if (ret != FLASH_SUCCESS) + goto out_kfree; + + /* copy sector 0 to sector 63 */ + ret = netxen_rom_fast_read_words(adapter, CRBINIT_START, + buffer, FLASH_SECTOR_SIZE); + if (ret != FLASH_SUCCESS) + goto out_kfree; + + ret = netxen_rom_fast_write_words(adapter, FIXED_START, + buffer, FLASH_SECTOR_SIZE); + if (ret != FLASH_SUCCESS) + goto out_kfree; + + /* lock sector 63 */ + val = netxen_rom_rdsr(adapter); + if (!(val & 0x8)) { + val |= (0x1 << 2); + /* lock sector 63 */ + if (netxen_rom_wrsr(adapter, val) == 0) { + ret = netxen_rom_wip_poll(adapter); + if (ret != FLASH_SUCCESS) + goto out_kfree; + + /* lock SR writes */ + ret = netxen_rom_wip_poll(adapter); + if (ret != FLASH_SUCCESS) + goto out_kfree; + } + } + +out_kfree: + kfree(buffer); + return ret; +} + int netxen_do_rom_se(struct netxen_adapter *adapter, int addr) { netxen_rom_wren(adapter); @@ -457,6 +638,27 @@ int netxen_do_rom_se(struct netxen_adapter *adapter, int addr) return netxen_rom_wip_poll(adapter); } +void check_erased_flash(struct netxen_adapter *adapter, int addr) +{ + int i; + int val; + int count = 0, erased_errors = 0; + int range; + + range = (addr == USER_START) ? FIXED_START : addr + FLASH_SECTOR_SIZE; + + for (i = addr; i < range; i += 4) { + netxen_rom_fast_read(adapter, i, &val); + if (val != 0xffffffff) + erased_errors++; + count++; + } + + if (erased_errors) + printk(KERN_INFO "0x%x out of 0x%x words fail to be erased " + "for sector address: %x\n", erased_errors, count, addr); +} + int netxen_rom_se(struct netxen_adapter *adapter, int addr) { int ret = 0; @@ -465,6 +667,68 @@ int netxen_rom_se(struct netxen_adapter *adapter, int addr) } ret = netxen_do_rom_se(adapter, addr); netxen_rom_unlock(adapter); + msleep(30); + check_erased_flash(adapter, addr); + + return ret; +} + +int +netxen_flash_erase_sections(struct netxen_adapter *adapter, int start, int end) +{ + int ret = FLASH_SUCCESS; + int i; + + for (i = start; i < end; i++) { + ret = netxen_rom_se(adapter, i * FLASH_SECTOR_SIZE); + if (ret) + break; + ret = netxen_rom_wip_poll(adapter); + if (ret < 0) + return ret; + } + + return ret; +} + +int +netxen_flash_erase_secondary(struct netxen_adapter *adapter) +{ + int ret = FLASH_SUCCESS; + int start, end; + + start = SECONDARY_START / FLASH_SECTOR_SIZE; + end = USER_START / FLASH_SECTOR_SIZE; + ret = netxen_flash_erase_sections(adapter, start, end); + + return ret; +} + +int +netxen_flash_erase_primary(struct netxen_adapter *adapter) +{ + int ret = FLASH_SUCCESS; + int start, end; + + start = PRIMARY_START / FLASH_SECTOR_SIZE; + end = SECONDARY_START / FLASH_SECTOR_SIZE; + ret = netxen_flash_erase_sections(adapter, start, end); + + return ret; +} + +int netxen_flash_unlock(struct netxen_adapter *adapter) +{ + int ret = 0; + + ret = netxen_rom_wrsr(adapter, 0); + if (ret < 0) + return ret; + + ret = netxen_rom_wren(adapter); + if (ret < 0) + return ret; + return ret; } @@ -543,9 +807,13 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) } for (i = 0; i < n; i++) { - off = - netxen_decode_crb_addr((unsigned long)buf[i].addr) + - NETXEN_PCI_CRBSPACE; + off = netxen_decode_crb_addr((unsigned long)buf[i].addr); + if (off == NETXEN_ADDR_ERROR) { + printk(KERN_ERR"CRB init value out of range %lx\n", + buf[i].addr); + continue; + } + off += NETXEN_PCI_CRBSPACE; /* skipping cold reboot MAGIC */ if (off == NETXEN_CAM_RAM(0x1fc)) continue; @@ -662,6 +930,7 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val) int loops = 0; if (!pegtune_val) { + val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) { udelay(100); schedule(); diff --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c deleted file mode 100644 index 702e3e95612a..000000000000 --- a/drivers/net/oaknet.c +++ /dev/null @@ -1,666 +0,0 @@ -/* - * - * Copyright (c) 1999-2000 Grant Erickson - * - * Module name: oaknet.c - * - * Description: - * Driver for the National Semiconductor DP83902AV Ethernet controller - * on-board the IBM PowerPC "Oak" evaluation board. Adapted from the - * various other 8390 drivers written by Donald Becker and Paul Gortmaker. - * - * Additional inspiration from the "tcd8390.c" driver from TiVo, Inc. - * and "enetLib.c" from IBM. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "8390.h" - - -/* Preprocessor Defines */ - -#if !defined(TRUE) || TRUE != 1 -#define TRUE 1 -#endif - -#if !defined(FALSE) || FALSE != 0 -#define FALSE 0 -#endif - -#define OAKNET_START_PG 0x20 /* First page of TX buffer */ -#define OAKNET_STOP_PG 0x40 /* Last pagge +1 of RX ring */ - -#define OAKNET_WAIT (2 * HZ / 100) /* 20 ms */ - -/* Experimenting with some fixes for a broken driver... */ - -#define OAKNET_DISINT -#define OAKNET_HEADCHECK -#define OAKNET_RWFIX - - -/* Global Variables */ - -static const char *name = "National DP83902AV"; - -static struct net_device *oaknet_devs; - - -/* Function Prototypes */ - -static int oaknet_open(struct net_device *dev); -static int oaknet_close(struct net_device *dev); - -static void oaknet_reset_8390(struct net_device *dev); -static void oaknet_get_8390_hdr(struct net_device *dev, - struct e8390_pkt_hdr *hdr, int ring_page); -static void oaknet_block_input(struct net_device *dev, int count, - struct sk_buff *skb, int ring_offset); -static void oaknet_block_output(struct net_device *dev, int count, - const unsigned char *buf, int start_page); - -static void oaknet_dma_error(struct net_device *dev, const char *name); - - -/* - * int oaknet_init() - * - * Description: - * This routine performs all the necessary platform-specific initiali- - * zation and set-up for the IBM "Oak" evaluation board's National - * Semiconductor DP83902AV "ST-NIC" Ethernet controller. - * - * Input(s): - * N/A - * - * Output(s): - * N/A - * - * Returns: - * 0 if OK, otherwise system error number on error. - * - */ -static int __init oaknet_init(void) -{ - register int i; - int reg0, regd; - int ret = -ENOMEM; - struct net_device *dev; -#if 0 - unsigned long ioaddr = OAKNET_IO_BASE; -#else - unsigned long ioaddr = ioremap(OAKNET_IO_BASE, OAKNET_IO_SIZE); -#endif - bd_t *bip = (bd_t *)__res; - - if (!ioaddr) - return -ENOMEM; - - dev = alloc_ei_netdev(); - if (!dev) - goto out_unmap; - - ret = -EBUSY; - if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name)) - goto out_dev; - - /* Quick register check to see if the device is really there. */ - - ret = -ENODEV; - if ((reg0 = ei_ibp(ioaddr)) == 0xFF) - goto out_region; - - /* - * That worked. Now a more thorough check, using the multicast - * address registers, that the device is definitely out there - * and semi-functional. - */ - - ei_obp(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD); - regd = ei_ibp(ioaddr + 0x0D); - ei_obp(0xFF, ioaddr + 0x0D); - ei_obp(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD); - ei_ibp(ioaddr + EN0_COUNTER0); - - /* It's no good. Fix things back up and leave. */ - - ret = -ENODEV; - if (ei_ibp(ioaddr + EN0_COUNTER0) != 0) { - ei_obp(reg0, ioaddr); - ei_obp(regd, ioaddr + 0x0D); - goto out_region; - } - - SET_MODULE_OWNER(dev); - - /* - * This controller is on an embedded board, so the base address - * and interrupt assignments are pre-assigned and unchageable. - */ - - dev->base_addr = ioaddr; - dev->irq = OAKNET_INT; - - /* - * Disable all chip interrupts for now and ACK all pending - * interrupts. - */ - - ei_obp(0x0, ioaddr + EN0_IMR); - ei_obp(0xFF, ioaddr + EN0_ISR); - - /* Attempt to get the interrupt line */ - - ret = -EAGAIN; - if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) { - printk("%s: unable to request interrupt %d.\n", - name, dev->irq); - goto out_region; - } - - /* Tell the world about what and where we've found. */ - - printk("%s: %s at", dev->name, name); - for (i = 0; i < ETHER_ADDR_LEN; ++i) { - dev->dev_addr[i] = bip->bi_enetaddr[i]; - printk("%c%.2x", (i ? ':' : ' '), dev->dev_addr[i]); - } - printk(", found at %#lx, using IRQ %d.\n", dev->base_addr, dev->irq); - - /* Set up some required driver fields and then we're done. */ - - ei_status.name = name; - ei_status.word16 = FALSE; - ei_status.tx_start_page = OAKNET_START_PG; - ei_status.rx_start_page = OAKNET_START_PG + TX_PAGES; - ei_status.stop_page = OAKNET_STOP_PG; - - ei_status.reset_8390 = &oaknet_reset_8390; - ei_status.block_input = &oaknet_block_input; - ei_status.block_output = &oaknet_block_output; - ei_status.get_8390_hdr = &oaknet_get_8390_hdr; - - dev->open = oaknet_open; - dev->stop = oaknet_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif - - NS8390_init(dev, FALSE); - ret = register_netdev(dev); - if (ret) - goto out_irq; - - oaknet_devs = dev; - return 0; - -out_irq; - free_irq(dev->irq, dev); -out_region: - release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE); -out_dev: - free_netdev(dev); -out_unmap: - iounmap(ioaddr); - return ret; -} - -/* - * static int oaknet_open() - * - * Description: - * This routine is a modest wrapper around ei_open, the 8390-generic, - * driver open routine. This just increments the module usage count - * and passes along the status from ei_open. - * - * Input(s): - * *dev - Pointer to the device structure for this driver. - * - * Output(s): - * *dev - Pointer to the device structure for this driver, potentially - * modified by ei_open. - * - * Returns: - * 0 if OK, otherwise < 0 on error. - * - */ -static int -oaknet_open(struct net_device *dev) -{ - int status = ei_open(dev); - return (status); -} - -/* - * static int oaknet_close() - * - * Description: - * This routine is a modest wrapper around ei_close, the 8390-generic, - * driver close routine. This just decrements the module usage count - * and passes along the status from ei_close. - * - * Input(s): - * *dev - Pointer to the device structure for this driver. - * - * Output(s): - * *dev - Pointer to the device structure for this driver, potentially - * modified by ei_close. - * - * Returns: - * 0 if OK, otherwise < 0 on error. - * - */ -static int -oaknet_close(struct net_device *dev) -{ - int status = ei_close(dev); - return (status); -} - -/* - * static void oaknet_reset_8390() - * - * Description: - * This routine resets the DP83902 chip. - * - * Input(s): - * *dev - Pointer to the device structure for this driver. - * - * Output(s): - * N/A - * - * Returns: - * N/A - * - */ -static void -oaknet_reset_8390(struct net_device *dev) -{ - int base = E8390_BASE; - - /* - * We have no provision of reseting the controller as is done - * in other drivers, such as "ne.c". However, the following - * seems to work well enough in the TiVo driver. - */ - - printk("Resetting %s...\n", dev->name); - ei_obp(E8390_STOP | E8390_NODMA | E8390_PAGE0, base + E8390_CMD); - ei_status.txing = 0; - ei_status.dmaing = 0; -} - -/* - * static void oaknet_get_8390_hdr() - * - * Description: - * This routine grabs the 8390-specific header. It's similar to the - * block input routine, but we don't need to be concerned with ring wrap - * as the header will be at the start of a page, so we optimize accordingly. - * - * Input(s): - * *dev - Pointer to the device structure for this driver. - * *hdr - Pointer to storage for the 8390-specific packet header. - * ring_page - ? - * - * Output(s): - * *hdr - Pointer to the 8390-specific packet header for the just- - * received frame. - * - * Returns: - * N/A - * - */ -static void -oaknet_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, - int ring_page) -{ - int base = dev->base_addr; - - /* - * This should NOT happen. If it does, it is the LAST thing you'll - * see. - */ - - if (ei_status.dmaing) { - oaknet_dma_error(dev, "oaknet_get_8390_hdr"); - return; - } - - ei_status.dmaing |= 0x01; - outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD); - outb_p(sizeof(struct e8390_pkt_hdr), base + EN0_RCNTLO); - outb_p(0, base + EN0_RCNTHI); - outb_p(0, base + EN0_RSARLO); /* On page boundary */ - outb_p(ring_page, base + EN0_RSARHI); - outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD); - - if (ei_status.word16) - insw(base + OAKNET_DATA, hdr, - sizeof(struct e8390_pkt_hdr) >> 1); - else - insb(base + OAKNET_DATA, hdr, - sizeof(struct e8390_pkt_hdr)); - - /* Byte-swap the packet byte count */ - - hdr->count = le16_to_cpu(hdr->count); - - outb_p(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */ - ei_status.dmaing &= ~0x01; -} - -/* - * XXX - Document me. - */ -static void -oaknet_block_input(struct net_device *dev, int count, struct sk_buff *skb, - int ring_offset) -{ - int base = OAKNET_BASE; - char *buf = skb->data; - - /* - * This should NOT happen. If it does, it is the LAST thing you'll - * see. - */ - - if (ei_status.dmaing) { - oaknet_dma_error(dev, "oaknet_block_input"); - return; - } - -#ifdef OAKNET_DISINT - save_flags(flags); - cli(); -#endif - - ei_status.dmaing |= 0x01; - ei_obp(E8390_NODMA + E8390_PAGE0 + E8390_START, base + E8390_CMD); - ei_obp(count & 0xff, base + EN0_RCNTLO); - ei_obp(count >> 8, base + EN0_RCNTHI); - ei_obp(ring_offset & 0xff, base + EN0_RSARLO); - ei_obp(ring_offset >> 8, base + EN0_RSARHI); - ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD); - if (ei_status.word16) { - ei_isw(base + E8390_DATA, buf, count >> 1); - if (count & 0x01) { - buf[count - 1] = ei_ib(base + E8390_DATA); -#ifdef OAKNET_HEADCHECK - bytes++; -#endif - } - } else { - ei_isb(base + E8390_DATA, buf, count); - } -#ifdef OAKNET_HEADCHECK - /* - * This was for the ALPHA version only, but enough people have - * been encountering problems so it is still here. If you see - * this message you either 1) have a slightly incompatible clone - * or 2) have noise/speed problems with your bus. - */ - - /* DMA termination address check... */ - { - int addr, tries = 20; - do { - /* DON'T check for 'ei_ibp(EN0_ISR) & ENISR_RDC' here - -- it's broken for Rx on some cards! */ - int high = ei_ibp(base + EN0_RSARHI); - int low = ei_ibp(base + EN0_RSARLO); - addr = (high << 8) + low; - if (((ring_offset + bytes) & 0xff) == low) - break; - } while (--tries > 0); - if (tries <= 0) - printk("%s: RX transfer address mismatch," - "%#4.4x (expected) vs. %#4.4x (actual).\n", - dev->name, ring_offset + bytes, addr); - } -#endif - ei_obp(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */ - ei_status.dmaing &= ~0x01; - -#ifdef OAKNET_DISINT - restore_flags(flags); -#endif -} - -/* - * static void oaknet_block_output() - * - * Description: - * This routine... - * - * Input(s): - * *dev - Pointer to the device structure for this driver. - * count - Number of bytes to be transferred. - * *buf - - * start_page - - * - * Output(s): - * N/A - * - * Returns: - * N/A - * - */ -static void -oaknet_block_output(struct net_device *dev, int count, - const unsigned char *buf, int start_page) -{ - int base = E8390_BASE; -#if 0 - int bug; -#endif - unsigned long start; -#ifdef OAKNET_DISINT - unsigned long flags; -#endif -#ifdef OAKNET_HEADCHECK - int retries = 0; -#endif - - /* Round the count up for word writes. */ - - if (ei_status.word16 && (count & 0x1)) - count++; - - /* - * This should NOT happen. If it does, it is the LAST thing you'll - * see. - */ - - if (ei_status.dmaing) { - oaknet_dma_error(dev, "oaknet_block_output"); - return; - } - -#ifdef OAKNET_DISINT - save_flags(flags); - cli(); -#endif - - ei_status.dmaing |= 0x01; - - /* Make sure we are in page 0. */ - - ei_obp(E8390_PAGE0 + E8390_START + E8390_NODMA, base + E8390_CMD); - -#ifdef OAKNET_HEADCHECK -retry: -#endif - -#if 0 - /* - * The 83902 documentation states that the processor needs to - * do a "dummy read" before doing the remote write to work - * around a chip bug they don't feel like fixing. - */ - - bug = 0; - while (1) { - unsigned int rdhi; - unsigned int rdlo; - - /* Now the normal output. */ - ei_obp(ENISR_RDC, base + EN0_ISR); - ei_obp(count & 0xff, base + EN0_RCNTLO); - ei_obp(count >> 8, base + EN0_RCNTHI); - ei_obp(0x00, base + EN0_RSARLO); - ei_obp(start_page, base + EN0_RSARHI); - - if (bug++) - break; - - /* Perform the dummy read */ - rdhi = ei_ibp(base + EN0_CRDAHI); - rdlo = ei_ibp(base + EN0_CRDALO); - ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD); - - while (1) { - unsigned int nrdhi; - unsigned int nrdlo; - nrdhi = ei_ibp(base + EN0_CRDAHI); - nrdlo = ei_ibp(base + EN0_CRDALO); - if ((rdhi != nrdhi) || (rdlo != nrdlo)) - break; - } - } -#else -#ifdef OAKNET_RWFIX - /* - * Handle the read-before-write bug the same way as the - * Crynwr packet driver -- the Nat'l Semi. method doesn't work. - * Actually this doesn't always work either, but if you have - * problems with your 83902 this is better than nothing! - */ - - ei_obp(0x42, base + EN0_RCNTLO); - ei_obp(0x00, base + EN0_RCNTHI); - ei_obp(0x42, base + EN0_RSARLO); - ei_obp(0x00, base + EN0_RSARHI); - ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD); - /* Make certain that the dummy read has occurred. */ - udelay(6); -#endif - - ei_obp(ENISR_RDC, base + EN0_ISR); - - /* Now the normal output. */ - ei_obp(count & 0xff, base + EN0_RCNTLO); - ei_obp(count >> 8, base + EN0_RCNTHI); - ei_obp(0x00, base + EN0_RSARLO); - ei_obp(start_page, base + EN0_RSARHI); -#endif /* 0/1 */ - - ei_obp(E8390_RWRITE + E8390_START, base + E8390_CMD); - if (ei_status.word16) { - ei_osw(E8390_BASE + E8390_DATA, buf, count >> 1); - } else { - ei_osb(E8390_BASE + E8390_DATA, buf, count); - } - -#ifdef OAKNET_DISINT - restore_flags(flags); -#endif - - start = jiffies; - -#ifdef OAKNET_HEADCHECK - /* - * This was for the ALPHA version only, but enough people have - * been encountering problems so it is still here. - */ - - { - /* DMA termination address check... */ - int addr, tries = 20; - do { - int high = ei_ibp(base + EN0_RSARHI); - int low = ei_ibp(base + EN0_RSARLO); - addr = (high << 8) + low; - if ((start_page << 8) + count == addr) - break; - } while (--tries > 0); - - if (tries <= 0) { - printk("%s: Tx packet transfer address mismatch," - "%#4.4x (expected) vs. %#4.4x (actual).\n", - dev->name, (start_page << 8) + count, addr); - if (retries++ == 0) - goto retry; - } - } -#endif - - while ((ei_ibp(base + EN0_ISR) & ENISR_RDC) == 0) { - if (time_after(jiffies, start + OAKNET_WAIT)) { - printk("%s: timeout waiting for Tx RDC.\n", dev->name); - oaknet_reset_8390(dev); - NS8390_init(dev, TRUE); - break; - } - } - - ei_obp(ENISR_RDC, base + EN0_ISR); /* Ack intr. */ - ei_status.dmaing &= ~0x01; -} - -/* - * static void oaknet_dma_error() - * - * Description: - * This routine prints out a last-ditch informative message to the console - * indicating that a DMA error occurred. If you see this, it's the last - * thing you'll see. - * - * Input(s): - * *dev - Pointer to the device structure for this driver. - * *name - Informative text (e.g. function name) indicating where the - * DMA error occurred. - * - * Output(s): - * N/A - * - * Returns: - * N/A - * - */ -static void -oaknet_dma_error(struct net_device *dev, const char *name) -{ - printk(KERN_EMERG "%s: DMAing conflict in %s." - "[DMAstat:%d][irqlock:%d][intr:%ld]\n", - dev->name, name, ei_status.dmaing, ei_status.irqlock, - dev->interrupt); -} - -/* - * Oak Ethernet module unload interface. - */ -static void __exit oaknet_cleanup_module (void) -{ - /* Convert to loop once driver supports multiple devices. */ - unregister_netdev(oaknet_dev); - free_irq(oaknet_devs->irq, oaknet_devs); - release_region(oaknet_devs->base_addr, OAKNET_IO_SIZE); - iounmap(ioaddr); - free_netdev(oaknet_devs); -} - -module_init(oaknet_init); -module_exit(oaknet_cleanup_module); -MODULE_LICENSE("GPL"); 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/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c old mode 100644 new mode 100755 index 8844c20eac2d..2429b274f0b0 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ MODULE_PARM_DESC(msi, "Turn on Message Signaled Interrupts."); static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)}, + {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3032_DEVICE_ID)}, /* required last entry */ {0,} }; @@ -1475,6 +1477,10 @@ static int ql_mii_setup(struct ql3_adapter *qdev) 2) << 7)) return -1; + if (qdev->device_id == QL3032_DEVICE_ID) + ql_write_page0_reg(qdev, + &port_regs->macMIIMgmtControlReg, 0x0f00000); + /* Divide 125MHz clock by 28 to meet PHY timing requirements */ reg = MAC_MII_CONTROL_CLK_SEL_DIV28; @@ -1706,18 +1712,42 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, struct ob_mac_iocb_rsp *mac_rsp) { struct ql_tx_buf_cb *tx_cb; + int i; tx_cb = &qdev->tx_buf[mac_rsp->transaction_id]; pci_unmap_single(qdev->pdev, - pci_unmap_addr(tx_cb, mapaddr), - pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE); - dev_kfree_skb_irq(tx_cb->skb); + pci_unmap_addr(&tx_cb->map[0], mapaddr), + pci_unmap_len(&tx_cb->map[0], maplen), + PCI_DMA_TODEVICE); + tx_cb->seg_count--; + if (tx_cb->seg_count) { + for (i = 1; i < tx_cb->seg_count; i++) { + pci_unmap_page(qdev->pdev, + pci_unmap_addr(&tx_cb->map[i], + mapaddr), + pci_unmap_len(&tx_cb->map[i], maplen), + PCI_DMA_TODEVICE); + } + } qdev->stats.tx_packets++; qdev->stats.tx_bytes += tx_cb->skb->len; + dev_kfree_skb_irq(tx_cb->skb); tx_cb->skb = NULL; atomic_inc(&qdev->tx_count); } +/* + * The difference between 3022 and 3032 for inbound completions: + * 3022 uses two buffers per completion. The first buffer contains + * (some) header info, the second the remainder of the headers plus + * the data. For this chip we reserve some space at the top of the + * receive buffer so that the header info in buffer one can be + * prepended to the buffer two. Buffer two is the sent up while + * buffer one is returned to the hardware to be reused. + * 3032 receives all of it's data and headers in one buffer for a + * simpler process. 3032 also supports checksum verification as + * can be seen in ql_process_macip_rx_intr(). + */ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev, struct ib_mac_iocb_rsp *ib_mac_rsp_ptr) { @@ -1740,14 +1770,17 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev, qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset; qdev->small_buf_release_cnt++; - /* start of first buffer */ - lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); - lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index]; - qdev->lrg_buf_release_cnt++; - if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) - qdev->lrg_buf_index = 0; - curr_ial_ptr++; /* 64-bit pointers require two incs. */ - curr_ial_ptr++; + if (qdev->device_id == QL3022_DEVICE_ID) { + /* start of first buffer (3022 only) */ + lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); + lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index]; + qdev->lrg_buf_release_cnt++; + if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) { + qdev->lrg_buf_index = 0; + } + curr_ial_ptr++; /* 64-bit pointers require two incs. */ + curr_ial_ptr++; + } /* start of second buffer */ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); @@ -1778,7 +1811,8 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev, qdev->ndev->last_rx = jiffies; lrg_buf_cb2->skb = NULL; - ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1); + if (qdev->device_id == QL3022_DEVICE_ID) + ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1); ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2); } @@ -1790,7 +1824,7 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL; struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL; u32 *curr_ial_ptr; - struct sk_buff *skb1, *skb2; + struct sk_buff *skb1 = NULL, *skb2; struct net_device *ndev = qdev->ndev; u16 length = le16_to_cpu(ib_ip_rsp_ptr->length); u16 size = 0; @@ -1806,16 +1840,20 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset; qdev->small_buf_release_cnt++; - /* start of first buffer */ - lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); - lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index]; - - qdev->lrg_buf_release_cnt++; - if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) - qdev->lrg_buf_index = 0; - skb1 = lrg_buf_cb1->skb; - curr_ial_ptr++; /* 64-bit pointers require two incs. */ - curr_ial_ptr++; + if (qdev->device_id == QL3022_DEVICE_ID) { + /* start of first buffer on 3022 */ + lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); + lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index]; + qdev->lrg_buf_release_cnt++; + if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) + qdev->lrg_buf_index = 0; + skb1 = lrg_buf_cb1->skb; + curr_ial_ptr++; /* 64-bit pointers require two incs. */ + curr_ial_ptr++; + size = ETH_HLEN; + if (*((u16 *) skb1->data) != 0xFFFF) + size += VLAN_ETH_HLEN - ETH_HLEN; + } /* start of second buffer */ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); @@ -1825,18 +1863,6 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) qdev->lrg_buf_index = 0; - qdev->stats.rx_packets++; - qdev->stats.rx_bytes += length; - - /* - * Copy the ethhdr from first buffer to second. This - * is necessary for IP completions. - */ - if (*((u16 *) skb1->data) != 0xFFFF) - size = VLAN_ETH_HLEN; - else - size = ETH_HLEN; - skb_put(skb2, length); /* Just the second buffer length here. */ pci_unmap_single(qdev->pdev, pci_unmap_addr(lrg_buf_cb2, mapaddr), @@ -1844,16 +1870,40 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, PCI_DMA_FROMDEVICE); prefetch(skb2->data); - memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size); - skb2->dev = qdev->ndev; skb2->ip_summed = CHECKSUM_NONE; + if (qdev->device_id == QL3022_DEVICE_ID) { + /* + * Copy the ethhdr from first buffer to second. This + * is necessary for 3022 IP completions. + */ + memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size); + } else { + u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum); + if (checksum & + (IB_IP_IOCB_RSP_3032_ICE | + IB_IP_IOCB_RSP_3032_CE | + IB_IP_IOCB_RSP_3032_NUC)) { + printk(KERN_ERR + "%s: Bad checksum for this %s packet, checksum = %x.\n", + __func__, + ((checksum & + IB_IP_IOCB_RSP_3032_TCP) ? "TCP" : + "UDP"),checksum); + } else if (checksum & IB_IP_IOCB_RSP_3032_TCP) { + skb2->ip_summed = CHECKSUM_UNNECESSARY; + } + } + skb2->dev = qdev->ndev; skb2->protocol = eth_type_trans(skb2, qdev->ndev); netif_receive_skb(skb2); + qdev->stats.rx_packets++; + qdev->stats.rx_bytes += length; ndev->last_rx = jiffies; lrg_buf_cb2->skb = NULL; - ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1); + if (qdev->device_id == QL3022_DEVICE_ID) + ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1); ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2); } @@ -1880,12 +1930,14 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev, break; case OPCODE_IB_MAC_IOCB: + case OPCODE_IB_3032_MAC_IOCB: ql_process_mac_rx_intr(qdev, (struct ib_mac_iocb_rsp *) net_rsp); (*rx_cleaned)++; break; case OPCODE_IB_IP_IOCB: + case OPCODE_IB_3032_IP_IOCB: ql_process_macip_rx_intr(qdev, (struct ib_ip_iocb_rsp *) net_rsp); (*rx_cleaned)++; @@ -2032,13 +2084,96 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id) return IRQ_RETVAL(handled); } +/* + * Get the total number of segments needed for the + * given number of fragments. This is necessary because + * outbound address lists (OAL) will be used when more than + * two frags are given. Each address list has 5 addr/len + * pairs. The 5th pair in each AOL is used to point to + * the next AOL if more frags are coming. + * That is why the frags:segment count ratio is not linear. + */ +static int ql_get_seg_count(unsigned short frags) +{ + switch(frags) { + case 0: return 1; /* just the skb->data seg */ + case 1: return 2; /* skb->data + 1 frag */ + case 2: return 3; /* skb->data + 2 frags */ + case 3: return 5; /* skb->data + 1 frag + 1 AOL containting 2 frags */ + case 4: return 6; + case 5: return 7; + case 6: return 8; + case 7: return 10; + case 8: return 11; + case 9: return 12; + case 10: return 13; + case 11: return 15; + case 12: return 16; + case 13: return 17; + case 14: return 18; + case 15: return 20; + case 16: return 21; + case 17: return 22; + case 18: return 23; + } + return -1; +} + +static void ql_hw_csum_setup(struct sk_buff *skb, + struct ob_mac_iocb_req *mac_iocb_ptr) +{ + struct ethhdr *eth; + struct iphdr *ip = NULL; + u8 offset = ETH_HLEN; + + eth = (struct ethhdr *)(skb->data); + + if (eth->h_proto == __constant_htons(ETH_P_IP)) { + ip = (struct iphdr *)&skb->data[ETH_HLEN]; + } else if (eth->h_proto == htons(ETH_P_8021Q) && + ((struct vlan_ethhdr *)skb->data)-> + h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP)) { + ip = (struct iphdr *)&skb->data[VLAN_ETH_HLEN]; + offset = VLAN_ETH_HLEN; + } + + if (ip) { + if (ip->protocol == IPPROTO_TCP) { + mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC; + mac_iocb_ptr->ip_hdr_off = offset; + mac_iocb_ptr->ip_hdr_len = ip->ihl; + } else if (ip->protocol == IPPROTO_UDP) { + mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC; + mac_iocb_ptr->ip_hdr_off = offset; + mac_iocb_ptr->ip_hdr_len = ip->ihl; + } + } +} + +/* + * The difference between 3022 and 3032 sends: + * 3022 only supports a simple single segment transmission. + * 3032 supports checksumming and scatter/gather lists (fragments). + * The 3032 supports sglists by using the 3 addr/len pairs (ALP) + * in the IOCB plus a chain of outbound address lists (OAL) that + * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th) + * will used to point to an OAL when more ALP entries are required. + * The IOCB is always the top of the chain followed by one or more + * OALs (when necessary). + */ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) { struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; struct ql_tx_buf_cb *tx_cb; + u32 tot_len = skb->len; + struct oal *oal; + struct oal_entry *oal_entry; + int len; struct ob_mac_iocb_req *mac_iocb_ptr; u64 map; + int seg_cnt, seg = 0; + int frag_cnt = (int)skb_shinfo(skb)->nr_frags; if (unlikely(atomic_read(&qdev->tx_count) < 2)) { if (!netif_queue_stopped(ndev)) @@ -2046,21 +2181,79 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) return NETDEV_TX_BUSY; } tx_cb = &qdev->tx_buf[qdev->req_producer_index] ; + seg_cnt = tx_cb->seg_count = ql_get_seg_count((skb_shinfo(skb)->nr_frags)); + if(seg_cnt == -1) { + printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__); + return NETDEV_TX_OK; + + } mac_iocb_ptr = tx_cb->queue_entry; memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req)); mac_iocb_ptr->opcode = qdev->mac_ob_opcode; mac_iocb_ptr->flags |= qdev->mb_bit_mask; mac_iocb_ptr->transaction_id = qdev->req_producer_index; - mac_iocb_ptr->data_len = cpu_to_le16((u16) skb->len); + mac_iocb_ptr->data_len = cpu_to_le16((u16) tot_len); tx_cb->skb = skb; - map = pci_map_single(qdev->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - mac_iocb_ptr->buf_addr0_low = cpu_to_le32(LS_64BITS(map)); - mac_iocb_ptr->buf_addr0_high = cpu_to_le32(MS_64BITS(map)); - mac_iocb_ptr->buf_0_len = cpu_to_le32(skb->len | OB_MAC_IOCB_REQ_E); - pci_unmap_addr_set(tx_cb, mapaddr, map); - pci_unmap_len_set(tx_cb, maplen, skb->len); - atomic_dec(&qdev->tx_count); + if (skb->ip_summed == CHECKSUM_PARTIAL) + ql_hw_csum_setup(skb, mac_iocb_ptr); + len = skb_headlen(skb); + map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE); + oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low; + oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); + oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); + oal_entry->len = cpu_to_le32(len); + pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map); + pci_unmap_len_set(&tx_cb->map[seg], maplen, len); + seg++; + if (!skb_shinfo(skb)->nr_frags) { + /* Terminate the last segment. */ + oal_entry->len = + cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY); + } else { + int i; + oal = tx_cb->oal; + for (i=0; ifrags[i]; + oal_entry++; + if ((seg == 2 && seg_cnt > 3) || /* Check for continuation */ + (seg == 7 && seg_cnt > 8) || /* requirements. It's strange */ + (seg == 12 && seg_cnt > 13) || /* but necessary. */ + (seg == 17 && seg_cnt > 18)) { + /* Continuation entry points to outbound address list. */ + map = pci_map_single(qdev->pdev, oal, + sizeof(struct oal), + PCI_DMA_TODEVICE); + oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); + oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); + oal_entry->len = + cpu_to_le32(sizeof(struct oal) | + OAL_CONT_ENTRY); + pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, + map); + pci_unmap_len_set(&tx_cb->map[seg], maplen, + len); + oal_entry = (struct oal_entry *)oal; + oal++; + seg++; + } + + map = + pci_map_page(qdev->pdev, frag->page, + frag->page_offset, frag->size, + PCI_DMA_TODEVICE); + oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); + oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); + oal_entry->len = cpu_to_le32(frag->size); + pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map); + pci_unmap_len_set(&tx_cb->map[seg], maplen, + frag->size); + } + /* Terminate the last segment. */ + oal_entry->len = + cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY); + } + wmb(); qdev->req_producer_index++; if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES) qdev->req_producer_index = 0; @@ -2074,8 +2267,10 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n", ndev->name, qdev->req_producer_index, skb->len); + atomic_dec(&qdev->tx_count); return NETDEV_TX_OK; } + static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev) { qdev->req_q_size = @@ -2359,7 +2554,22 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev) return 0; } -static void ql_create_send_free_list(struct ql3_adapter *qdev) +static void ql_free_send_free_list(struct ql3_adapter *qdev) +{ + struct ql_tx_buf_cb *tx_cb; + int i; + + tx_cb = &qdev->tx_buf[0]; + for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) { + if (tx_cb->oal) { + kfree(tx_cb->oal); + tx_cb->oal = NULL; + } + tx_cb++; + } +} + +static int ql_create_send_free_list(struct ql3_adapter *qdev) { struct ql_tx_buf_cb *tx_cb; int i; @@ -2368,11 +2578,16 @@ static void ql_create_send_free_list(struct ql3_adapter *qdev) /* Create free list of transmit buffers */ for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) { + tx_cb = &qdev->tx_buf[i]; tx_cb->skb = NULL; tx_cb->queue_entry = req_q_curr; req_q_curr++; + tx_cb->oal = kmalloc(512, GFP_KERNEL); + if (tx_cb->oal == NULL) + return -1; } + return 0; } static int ql_alloc_mem_resources(struct ql3_adapter *qdev) @@ -2447,12 +2662,14 @@ static int ql_alloc_mem_resources(struct ql3_adapter *qdev) /* Initialize the large buffer queue. */ ql_init_large_buffers(qdev); - ql_create_send_free_list(qdev); + if (ql_create_send_free_list(qdev)) + goto err_free_list; qdev->rsp_current = qdev->rsp_q_virt_addr; return 0; - +err_free_list: + ql_free_send_free_list(qdev); err_small_buffers: ql_free_buffer_queues(qdev); err_buffer_queues: @@ -2468,6 +2685,7 @@ err_req_rsp: static void ql_free_mem_resources(struct ql3_adapter *qdev) { + ql_free_send_free_list(qdev); ql_free_large_buffers(qdev); ql_free_small_buffers(qdev); ql_free_buffer_queues(qdev); @@ -2766,11 +2984,20 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev) } /* Enable Ethernet Function */ - value = - (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI | - PORT_CONTROL_HH); - ql_write_page0_reg(qdev, &port_regs->portControl, - ((value << 16) | value)); + if (qdev->device_id == QL3032_DEVICE_ID) { + value = + (QL3032_PORT_CONTROL_EF | QL3032_PORT_CONTROL_KIE | + QL3032_PORT_CONTROL_EIv6 | QL3032_PORT_CONTROL_EIv4); + ql_write_page0_reg(qdev, &port_regs->functionControl, + ((value << 16) | value)); + } else { + value = + (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI | + PORT_CONTROL_HH); + ql_write_page0_reg(qdev, &port_regs->portControl, + ((value << 16) | value)); + } + out: return status; @@ -2917,8 +3144,10 @@ static void ql_display_dev_info(struct net_device *ndev) struct pci_dev *pdev = qdev->pdev; printk(KERN_INFO PFX - "\n%s Adapter %d RevisionID %d found on PCI slot %d.\n", - DRV_NAME, qdev->index, qdev->chip_rev_id, qdev->pci_slot); + "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n", + DRV_NAME, qdev->index, qdev->chip_rev_id, + (qdev->device_id == QL3032_DEVICE_ID) ? "QLA3032" : "QLA3022", + qdev->pci_slot); printk(KERN_INFO PFX "%s Interface.\n", test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER"); @@ -3212,15 +3441,22 @@ static void ql_reset_work(struct work_struct *work) * Loop through the active list and return the skb. */ for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) { + int j; tx_cb = &qdev->tx_buf[i]; if (tx_cb->skb) { - printk(KERN_DEBUG PFX "%s: Freeing lost SKB.\n", qdev->ndev->name); pci_unmap_single(qdev->pdev, - pci_unmap_addr(tx_cb, mapaddr), - pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE); + pci_unmap_addr(&tx_cb->map[0], mapaddr), + pci_unmap_len(&tx_cb->map[0], maplen), + PCI_DMA_TODEVICE); + for(j=1;jseg_count;j++) { + pci_unmap_page(qdev->pdev, + pci_unmap_addr(&tx_cb->map[j],mapaddr), + pci_unmap_len(&tx_cb->map[j],maplen), + PCI_DMA_TODEVICE); + } dev_kfree_skb(tx_cb->skb); tx_cb->skb = NULL; } @@ -3379,21 +3615,24 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); - if (pci_using_dac) - ndev->features |= NETIF_F_HIGHDMA; - pci_set_drvdata(pdev, ndev); qdev = netdev_priv(ndev); qdev->index = cards_found; qdev->ndev = ndev; qdev->pdev = pdev; + qdev->device_id = pci_entry->device; qdev->port_link_state = LS_DOWN; if (msi) qdev->msi = 1; qdev->msg_enable = netif_msg_init(debug, default_msg); + if (pci_using_dac) + ndev->features |= NETIF_F_HIGHDMA; + if (qdev->device_id == QL3032_DEVICE_ID) + ndev->features |= (NETIF_F_HW_CSUM | NETIF_F_SG); + qdev->mem_map_registers = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(qdev->pdev, 1)); diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h old mode 100644 new mode 100755 index ea94de7fd071..b2d76ea68827 --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h @@ -21,7 +21,9 @@ #define OPCODE_UPDATE_NCB_IOCB 0xF0 #define OPCODE_IB_MAC_IOCB 0xF9 +#define OPCODE_IB_3032_MAC_IOCB 0x09 #define OPCODE_IB_IP_IOCB 0xFA +#define OPCODE_IB_3032_IP_IOCB 0x0A #define OPCODE_IB_TCP_IOCB 0xFB #define OPCODE_DUMP_PROTO_IOCB 0xFE #define OPCODE_BUFFER_ALERT_IOCB 0xFB @@ -37,18 +39,23 @@ struct ob_mac_iocb_req { u8 opcode; u8 flags; -#define OB_MAC_IOCB_REQ_MA 0xC0 -#define OB_MAC_IOCB_REQ_F 0x20 -#define OB_MAC_IOCB_REQ_X 0x10 +#define OB_MAC_IOCB_REQ_MA 0xe0 +#define OB_MAC_IOCB_REQ_F 0x10 +#define OB_MAC_IOCB_REQ_X 0x08 #define OB_MAC_IOCB_REQ_D 0x02 #define OB_MAC_IOCB_REQ_I 0x01 - __le16 reserved0; + u8 flags1; +#define OB_3032MAC_IOCB_REQ_IC 0x04 +#define OB_3032MAC_IOCB_REQ_TC 0x02 +#define OB_3032MAC_IOCB_REQ_UC 0x01 + u8 reserved0; __le32 transaction_id; __le16 data_len; - __le16 reserved1; + u8 ip_hdr_off; + u8 ip_hdr_len; + __le32 reserved1; __le32 reserved2; - __le32 reserved3; __le32 buf_addr0_low; __le32 buf_addr0_high; __le32 buf_0_len; @@ -58,8 +65,8 @@ struct ob_mac_iocb_req { __le32 buf_addr2_low; __le32 buf_addr2_high; __le32 buf_2_len; + __le32 reserved3; __le32 reserved4; - __le32 reserved5; }; /* * The following constants define control bits for buffer @@ -74,6 +81,7 @@ struct ob_mac_iocb_rsp { u8 opcode; u8 flags; #define OB_MAC_IOCB_RSP_P 0x08 +#define OB_MAC_IOCB_RSP_L 0x04 #define OB_MAC_IOCB_RSP_S 0x02 #define OB_MAC_IOCB_RSP_I 0x01 @@ -85,6 +93,7 @@ struct ob_mac_iocb_rsp { struct ib_mac_iocb_rsp { u8 opcode; +#define IB_MAC_IOCB_RSP_V 0x80 u8 flags; #define IB_MAC_IOCB_RSP_S 0x80 #define IB_MAC_IOCB_RSP_H1 0x40 @@ -138,6 +147,7 @@ struct ob_ip_iocb_req { struct ob_ip_iocb_rsp { u8 opcode; u8 flags; +#define OB_MAC_IOCB_RSP_H 0x10 #define OB_MAC_IOCB_RSP_E 0x08 #define OB_MAC_IOCB_RSP_L 0x04 #define OB_MAC_IOCB_RSP_S 0x02 @@ -220,6 +230,10 @@ struct ob_tcp_iocb_rsp { struct ib_ip_iocb_rsp { u8 opcode; +#define IB_IP_IOCB_RSP_3032_V 0x80 +#define IB_IP_IOCB_RSP_3032_O 0x40 +#define IB_IP_IOCB_RSP_3032_I 0x20 +#define IB_IP_IOCB_RSP_3032_R 0x10 u8 flags; #define IB_IP_IOCB_RSP_S 0x80 #define IB_IP_IOCB_RSP_H1 0x40 @@ -230,6 +244,12 @@ struct ib_ip_iocb_rsp { __le16 length; __le16 checksum; +#define IB_IP_IOCB_RSP_3032_ICE 0x01 +#define IB_IP_IOCB_RSP_3032_CE 0x02 +#define IB_IP_IOCB_RSP_3032_NUC 0x04 +#define IB_IP_IOCB_RSP_3032_UDP 0x08 +#define IB_IP_IOCB_RSP_3032_TCP 0x10 +#define IB_IP_IOCB_RSP_3032_IPE 0x20 __le16 reserved; #define IB_IP_IOCB_RSP_R 0x01 __le32 ial_low; @@ -524,6 +544,21 @@ enum { IP_ADDR_INDEX_REG_FUNC_2_SEC = 0x0005, IP_ADDR_INDEX_REG_FUNC_3_PRI = 0x0006, IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007, + IP_ADDR_INDEX_REG_6 = 0x0008, + IP_ADDR_INDEX_REG_OFFSET_MASK = 0x0030, + IP_ADDR_INDEX_REG_E = 0x0040, +}; +enum { + QL3032_PORT_CONTROL_DS = 0x0001, + QL3032_PORT_CONTROL_HH = 0x0002, + QL3032_PORT_CONTROL_EIv6 = 0x0004, + QL3032_PORT_CONTROL_EIv4 = 0x0008, + QL3032_PORT_CONTROL_ET = 0x0010, + QL3032_PORT_CONTROL_EF = 0x0020, + QL3032_PORT_CONTROL_DRM = 0x0040, + QL3032_PORT_CONTROL_RLB = 0x0080, + QL3032_PORT_CONTROL_RCB = 0x0100, + QL3032_PORT_CONTROL_KIE = 0x0200, }; enum { @@ -657,7 +692,8 @@ struct ql3xxx_port_registers { u32 internalRamWDataReg; u32 reclaimedBufferAddrRegLow; u32 reclaimedBufferAddrRegHigh; - u32 reserved[2]; + u32 tcpConfiguration; + u32 functionControl; u32 fpgaRevID; u32 localRamAddr; u32 localRamDataAutoIncr; @@ -963,6 +999,7 @@ struct eeprom_data { #define QL3XXX_VENDOR_ID 0x1077 #define QL3022_DEVICE_ID 0x3022 +#define QL3032_DEVICE_ID 0x3032 /* MTU & Frame Size stuff */ #define NORMAL_MTU_SIZE ETH_DATA_LEN @@ -1038,11 +1075,41 @@ struct ql_rcv_buf_cb { int index; }; +/* + * Original IOCB has 3 sg entries: + * first points to skb-data area + * second points to first frag + * third points to next oal. + * OAL has 5 entries: + * 1 thru 4 point to frags + * fifth points to next oal. + */ +#define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1) + +struct oal_entry { + u32 dma_lo; + u32 dma_hi; + u32 len; +#define OAL_LAST_ENTRY 0x80000000 /* Last valid buffer in list. */ +#define OAL_CONT_ENTRY 0x40000000 /* points to an OAL. (continuation) */ + u32 reserved; +}; + +struct oal { + struct oal_entry oal_entry[5]; +}; + +struct map_list { + DECLARE_PCI_UNMAP_ADDR(mapaddr); + DECLARE_PCI_UNMAP_LEN(maplen); +}; + struct ql_tx_buf_cb { struct sk_buff *skb; struct ob_mac_iocb_req *queue_entry ; - DECLARE_PCI_UNMAP_ADDR(mapaddr); - DECLARE_PCI_UNMAP_LEN(maplen); + int seg_count; + struct oal *oal; + struct map_list map[MAX_SKB_FRAGS+1]; }; /* definitions for type field */ @@ -1189,6 +1256,7 @@ struct ql3_adapter { struct delayed_work reset_work; struct delayed_work tx_timeout_work; u32 max_frame_size; + u32 device_id; }; #endif /* _QLA3XXX_H_ */ diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index a914fef44309..0e345cbc2bf9 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -15,7 +15,7 @@ #define TBD 0 -typedef struct _XENA_dev_config { +struct XENA_dev_config { /* Convention: mHAL_XXX is mask, vHAL_XXX is value */ /* General Control-Status Registers */ @@ -300,6 +300,7 @@ typedef struct _XENA_dev_config { u64 gpio_control; #define GPIO_CTRL_GPIO_0 BIT(8) u64 misc_control; +#define FAULT_BEHAVIOUR BIT(0) #define EXT_REQ_EN BIT(1) #define MISC_LINK_STABILITY_PRD(val) vBIT(val,29,3) @@ -851,9 +852,9 @@ typedef struct _XENA_dev_config { #define SPI_CONTROL_DONE BIT(6) u64 spi_data; #define SPI_DATA_WRITE(data,len) vBIT(data,0,len) -} XENA_dev_config_t; +}; -#define XENA_REG_SPACE sizeof(XENA_dev_config_t) +#define XENA_REG_SPACE sizeof(struct XENA_dev_config) #define XENA_EEPROM_SPACE (0x01 << 11) #endif /* _REGS_H */ diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 1dd66b8ea0fa..639fbc0f16f3 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -77,7 +77,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.15.2" +#define DRV_VERSION "2.0.16.1" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -86,7 +86,7 @@ static char s2io_driver_version[] = DRV_VERSION; static int rxd_size[4] = {32,48,48,64}; static int rxd_count[4] = {127,85,85,63}; -static inline int RXD_IS_UP2DT(RxD_t *rxdp) +static inline int RXD_IS_UP2DT(struct RxD_t *rxdp) { int ret; @@ -111,9 +111,9 @@ static inline int RXD_IS_UP2DT(RxD_t *rxdp) #define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status)) #define PANIC 1 #define LOW 2 -static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring) +static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring) { - mac_info_t *mac_control; + struct mac_info *mac_control; mac_control = &sp->mac_control; if (rxb_size <= rxd_count[sp->rxd_mode]) @@ -286,7 +286,7 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { static void s2io_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { - nic_t *nic = dev->priv; + struct s2io_nic *nic = dev->priv; unsigned long flags; spin_lock_irqsave(&nic->tx_lock, flags); @@ -297,7 +297,7 @@ static void s2io_vlan_rx_register(struct net_device *dev, /* Unregister the vlan */ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) { - nic_t *nic = dev->priv; + struct s2io_nic *nic = dev->priv; unsigned long flags; spin_lock_irqsave(&nic->tx_lock, flags); @@ -401,9 +401,10 @@ S2IO_PARM_INT(lro, 0); * aggregation happens until we hit max IP pkt size(64K) */ S2IO_PARM_INT(lro_max_pkts, 0xFFFF); -#ifndef CONFIG_S2IO_NAPI S2IO_PARM_INT(indicate_max_pkts, 0); -#endif + +S2IO_PARM_INT(napi, 1); +S2IO_PARM_INT(ufo, 0); static unsigned int tx_fifo_len[MAX_TX_FIFOS] = {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN}; @@ -457,14 +458,14 @@ static int init_shared_mem(struct s2io_nic *nic) u32 size; void *tmp_v_addr, *tmp_v_addr_next; dma_addr_t tmp_p_addr, tmp_p_addr_next; - RxD_block_t *pre_rxd_blk = NULL; - int i, j, blk_cnt, rx_sz, tx_sz; + struct RxD_block *pre_rxd_blk = NULL; + int i, j, blk_cnt; int lst_size, lst_per_page; struct net_device *dev = nic->dev; unsigned long tmp; - buffAdd_t *ba; + struct buffAdd *ba; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; mac_control = &nic->mac_control; @@ -482,13 +483,12 @@ static int init_shared_mem(struct s2io_nic *nic) return -EINVAL; } - lst_size = (sizeof(TxD_t) * config->max_txds); - tx_sz = lst_size * size; + lst_size = (sizeof(struct TxD) * config->max_txds); lst_per_page = PAGE_SIZE / lst_size; for (i = 0; i < config->tx_fifo_num; i++) { int fifo_len = config->tx_cfg[i].fifo_len; - int list_holder_size = fifo_len * sizeof(list_info_hold_t); + int list_holder_size = fifo_len * sizeof(struct list_info_hold); mac_control->fifos[i].list_info = kmalloc(list_holder_size, GFP_KERNEL); if (!mac_control->fifos[i].list_info) { @@ -579,10 +579,9 @@ static int init_shared_mem(struct s2io_nic *nic) mac_control->rings[i].block_count; } if (nic->rxd_mode == RXD_MODE_1) - size = (size * (sizeof(RxD1_t))); + size = (size * (sizeof(struct RxD1))); else - size = (size * (sizeof(RxD3_t))); - rx_sz = size; + size = (size * (sizeof(struct RxD3))); for (i = 0; i < config->rx_ring_num; i++) { mac_control->rings[i].rx_curr_get_info.block_index = 0; @@ -600,7 +599,7 @@ static int init_shared_mem(struct s2io_nic *nic) (rxd_count[nic->rxd_mode] + 1); /* Allocating all the Rx blocks */ for (j = 0; j < blk_cnt; j++) { - rx_block_info_t *rx_blocks; + struct rx_block_info *rx_blocks; int l; rx_blocks = &mac_control->rings[i].rx_blocks[j]; @@ -620,9 +619,11 @@ static int init_shared_mem(struct s2io_nic *nic) memset(tmp_v_addr, 0, size); rx_blocks->block_virt_addr = tmp_v_addr; rx_blocks->block_dma_addr = tmp_p_addr; - rx_blocks->rxds = kmalloc(sizeof(rxd_info_t)* + rx_blocks->rxds = kmalloc(sizeof(struct rxd_info)* rxd_count[nic->rxd_mode], GFP_KERNEL); + if (!rx_blocks->rxds) + return -ENOMEM; for (l=0; lrxd_mode];l++) { rx_blocks->rxds[l].virt_addr = rx_blocks->block_virt_addr + @@ -645,7 +646,7 @@ static int init_shared_mem(struct s2io_nic *nic) mac_control->rings[i].rx_blocks[(j + 1) % blk_cnt].block_dma_addr; - pre_rxd_blk = (RxD_block_t *) tmp_v_addr; + pre_rxd_blk = (struct RxD_block *) tmp_v_addr; pre_rxd_blk->reserved_2_pNext_RxD_block = (unsigned long) tmp_v_addr_next; pre_rxd_blk->pNext_RxD_Blk_physical = @@ -661,14 +662,14 @@ static int init_shared_mem(struct s2io_nic *nic) blk_cnt = config->rx_cfg[i].num_rxd / (rxd_count[nic->rxd_mode]+ 1); mac_control->rings[i].ba = - kmalloc((sizeof(buffAdd_t *) * blk_cnt), + kmalloc((sizeof(struct buffAdd *) * blk_cnt), GFP_KERNEL); if (!mac_control->rings[i].ba) return -ENOMEM; for (j = 0; j < blk_cnt; j++) { int k = 0; mac_control->rings[i].ba[j] = - kmalloc((sizeof(buffAdd_t) * + kmalloc((sizeof(struct buffAdd) * (rxd_count[nic->rxd_mode] + 1)), GFP_KERNEL); if (!mac_control->rings[i].ba[j]) @@ -700,7 +701,7 @@ static int init_shared_mem(struct s2io_nic *nic) } /* Allocation and initialization of Statistics block */ - size = sizeof(StatInfo_t); + size = sizeof(struct stat_block); mac_control->stats_mem = pci_alloc_consistent (nic->pdev, size, &mac_control->stats_mem_phy); @@ -715,7 +716,7 @@ static int init_shared_mem(struct s2io_nic *nic) mac_control->stats_mem_sz = size; tmp_v_addr = mac_control->stats_mem; - mac_control->stats_info = (StatInfo_t *) tmp_v_addr; + mac_control->stats_info = (struct stat_block *) tmp_v_addr; memset(tmp_v_addr, 0, size); DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name, (unsigned long long) tmp_p_addr); @@ -735,7 +736,7 @@ static void free_shared_mem(struct s2io_nic *nic) int i, j, blk_cnt, size; void *tmp_v_addr; dma_addr_t tmp_p_addr; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; int lst_size, lst_per_page; struct net_device *dev = nic->dev; @@ -746,7 +747,7 @@ static void free_shared_mem(struct s2io_nic *nic) mac_control = &nic->mac_control; config = &nic->config; - lst_size = (sizeof(TxD_t) * config->max_txds); + lst_size = (sizeof(struct TxD) * config->max_txds); lst_per_page = PAGE_SIZE / lst_size; for (i = 0; i < config->tx_fifo_num; i++) { @@ -809,7 +810,7 @@ static void free_shared_mem(struct s2io_nic *nic) if (!mac_control->rings[i].ba[j]) continue; while (k != rxd_count[nic->rxd_mode]) { - buffAdd_t *ba = + struct buffAdd *ba = &mac_control->rings[i].ba[j][k]; kfree(ba->ba_0_org); kfree(ba->ba_1_org); @@ -835,9 +836,9 @@ static void free_shared_mem(struct s2io_nic *nic) * s2io_verify_pci_mode - */ -static int s2io_verify_pci_mode(nic_t *nic) +static int s2io_verify_pci_mode(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0; int mode; @@ -868,9 +869,9 @@ static int bus_speed[8] = {33, 133, 133, 200, 266, 133, 200, 266}; /** * s2io_print_pci_mode - */ -static int s2io_print_pci_mode(nic_t *nic) +static int s2io_print_pci_mode(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0; int mode; struct config_param *config = &nic->config; @@ -938,13 +939,13 @@ static int s2io_print_pci_mode(nic_t *nic) static int init_nic(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; struct net_device *dev = nic->dev; register u64 val64 = 0; void __iomem *add; u32 time; int i, j; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; int dtx_cnt = 0; unsigned long long mem_share; @@ -1414,7 +1415,7 @@ static int init_nic(struct s2io_nic *nic) val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) | TTI_DATA2_MEM_TX_UFC_B(0x20) | - TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80); + TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80); writeq(val64, &bar0->tti_data2_mem); val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD; @@ -1610,7 +1611,8 @@ static int init_nic(struct s2io_nic *nic) * that does not start on an ADB to reduce disconnects. */ if (nic->device_type == XFRAME_II_DEVICE) { - val64 = EXT_REQ_EN | MISC_LINK_STABILITY_PRD(3); + val64 = FAULT_BEHAVIOUR | EXT_REQ_EN | + MISC_LINK_STABILITY_PRD(3); writeq(val64, &bar0->misc_control); val64 = readq(&bar0->pic_control2); val64 &= ~(BIT(13)|BIT(14)|BIT(15)); @@ -1626,7 +1628,7 @@ static int init_nic(struct s2io_nic *nic) #define LINK_UP_DOWN_INTERRUPT 1 #define MAC_RMAC_ERR_TIMER 2 -static int s2io_link_fault_indication(nic_t *nic) +static int s2io_link_fault_indication(struct s2io_nic *nic) { if (nic->intr_type != INTA) return MAC_RMAC_ERR_TIMER; @@ -1649,14 +1651,14 @@ static int s2io_link_fault_indication(nic_t *nic) static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0, temp64 = 0; /* Top level interrupt classification */ /* PIC Interrupts */ if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) { /* Enable PIC Intrs in the general intr mask register */ - val64 = TXPIC_INT_M | PIC_RX_INT_M; + val64 = TXPIC_INT_M; if (flag == ENABLE_INTRS) { temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); @@ -1694,70 +1696,6 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) } } - /* DMA Interrupts */ - /* Enabling/Disabling Tx DMA interrupts */ - if (mask & TX_DMA_INTR) { - /* Enable TxDMA Intrs in the general intr mask register */ - val64 = TXDMA_INT_M; - if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); - /* - * Keep all interrupts other than PFC interrupt - * and PCC interrupt disabled in DMA level. - */ - val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M | - TXDMA_PCC_INT_M); - writeq(val64, &bar0->txdma_int_mask); - /* - * Enable only the MISC error 1 interrupt in PFC block - */ - val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1); - writeq(val64, &bar0->pfc_err_mask); - /* - * Enable only the FB_ECC error interrupt in PCC block - */ - val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR); - writeq(val64, &bar0->pcc_err_mask); - } else if (flag == DISABLE_INTRS) { - /* - * Disable TxDMA Intrs in the general intr mask - * register - */ - writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask); - writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); - } - } - - /* Enabling/Disabling Rx DMA interrupts */ - if (mask & RX_DMA_INTR) { - /* Enable RxDMA Intrs in the general intr mask register */ - val64 = RXDMA_INT_M; - if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); - /* - * All RxDMA block interrupts are disabled for now - * TODO - */ - writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask); - } else if (flag == DISABLE_INTRS) { - /* - * Disable RxDMA Intrs in the general intr mask - * register - */ - writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); - } - } - /* MAC Interrupts */ /* Enabling/Disabling MAC interrupts */ if (mask & (TX_MAC_INTR | RX_MAC_INTR)) { @@ -1784,53 +1722,6 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) } } - /* XGXS Interrupts */ - if (mask & (TX_XGXS_INTR | RX_XGXS_INTR)) { - val64 = TXXGXS_INT_M | RXXGXS_INT_M; - if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); - /* - * All XGXS block error interrupts are disabled for now - * TODO - */ - writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask); - } else if (flag == DISABLE_INTRS) { - /* - * Disable MC Intrs in the general intr mask register - */ - writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); - } - } - - /* Memory Controller(MC) interrupts */ - if (mask & MC_INTR) { - val64 = MC_INT_M; - if (flag == ENABLE_INTRS) { - temp64 = readq(&bar0->general_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->general_int_mask); - /* - * Enable all MC Intrs. - */ - writeq(0x0, &bar0->mc_int_mask); - writeq(0x0, &bar0->mc_err_mask); - } else if (flag == DISABLE_INTRS) { - /* - * Disable MC Intrs in the general intr mask register - */ - writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask); - temp64 = readq(&bar0->general_int_mask); - val64 |= temp64; - writeq(val64, &bar0->general_int_mask); - } - } - - /* Tx traffic interrupts */ if (mask & TX_TRAFFIC_INTR) { val64 = TXTRAFFIC_INT_M; @@ -1877,41 +1768,36 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) } } -static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc) +/** + * verify_pcc_quiescent- Checks for PCC quiescent state + * Return: 1 If PCC is quiescence + * 0 If PCC is not quiescence + */ +static int verify_pcc_quiescent(struct s2io_nic *sp, int flag) { - int ret = 0; + int ret = 0, herc; + struct XENA_dev_config __iomem *bar0 = sp->bar0; + u64 val64 = readq(&bar0->adapter_status); + + herc = (sp->device_type == XFRAME_II_DEVICE); if (flag == FALSE) { - if ((!herc && (rev_id >= 4)) || herc) { - if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) && - ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT)) { + if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) { + if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE)) ret = 1; - } - }else { - if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) && - ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT)) { + } else { + if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE)) ret = 1; - } } } else { - if ((!herc && (rev_id >= 4)) || herc) { + if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) { if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) == - ADAPTER_STATUS_RMAC_PCC_IDLE) && - (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) || - ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT))) { + ADAPTER_STATUS_RMAC_PCC_IDLE)) ret = 1; - } } else { if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) == - ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) && - (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) || - ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT))) { + ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE)) ret = 1; - } } } @@ -1919,9 +1805,6 @@ static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc) } /** * verify_xena_quiescence - Checks whether the H/W is ready - * @val64 : Value read from adapter status register. - * @flag : indicates if the adapter enable bit was ever written once - * before. * Description: Returns whether the H/W is ready to go or not. Depending * on whether adapter enable bit was written or not the comparison * differs and the calling function passes the input argument flag to @@ -1930,24 +1813,63 @@ static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc) * 0 If Xena is not quiescence */ -static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag) +static int verify_xena_quiescence(struct s2io_nic *sp) { - int ret = 0, herc; - u64 tmp64 = ~((u64) val64); - int rev_id = get_xena_rev_id(sp->pdev); + int mode; + struct XENA_dev_config __iomem *bar0 = sp->bar0; + u64 val64 = readq(&bar0->adapter_status); + mode = s2io_verify_pci_mode(sp); - herc = (sp->device_type == XFRAME_II_DEVICE); - if (! - (tmp64 & - (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY | - ADAPTER_STATUS_PFC_READY | ADAPTER_STATUS_TMAC_BUF_EMPTY | - ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY | - ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK | - ADAPTER_STATUS_P_PLL_LOCK))) { - ret = check_prc_pcc_state(val64, flag, rev_id, herc); + if (!(val64 & ADAPTER_STATUS_TDMA_READY)) { + DBG_PRINT(ERR_DBG, "%s", "TDMA is not ready!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_RDMA_READY)) { + DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_PFC_READY)) { + DBG_PRINT(ERR_DBG, "%s", "PFC is not ready!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) { + DBG_PRINT(ERR_DBG, "%s", "TMAC BUF is not empty!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) { + DBG_PRINT(ERR_DBG, "%s", "PIC is not QUIESCENT!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) { + DBG_PRINT(ERR_DBG, "%s", "MC_DRAM is not ready!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) { + DBG_PRINT(ERR_DBG, "%s", "MC_QUEUES is not ready!"); + return 0; + } + if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) { + DBG_PRINT(ERR_DBG, "%s", "M_PLL is not locked!"); + return 0; } - return ret; + /* + * In PCI 33 mode, the P_PLL is not used, and therefore, + * the the P_PLL_LOCK bit in the adapter_status register will + * not be asserted. + */ + if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) && + sp->device_type == XFRAME_II_DEVICE && mode != + PCI_MODE_PCI_33) { + DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!"); + return 0; + } + if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == + ADAPTER_STATUS_RC_PRC_QUIESCENT)) { + DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!"); + return 0; + } + return 1; } /** @@ -1958,9 +1880,9 @@ static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag) * */ -static void fix_mac_address(nic_t * sp) +static void fix_mac_address(struct s2io_nic * sp) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; int i = 0; @@ -1986,11 +1908,11 @@ static void fix_mac_address(nic_t * sp) static int start_nic(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; struct net_device *dev = nic->dev; register u64 val64 = 0; u16 subid, i; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; mac_control = &nic->mac_control; @@ -2052,7 +1974,7 @@ static int start_nic(struct s2io_nic *nic) * it. */ val64 = readq(&bar0->adapter_status); - if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) { + if (!verify_xena_quiescence(nic)) { DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name); DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n", (unsigned long long) val64); @@ -2095,11 +2017,12 @@ static int start_nic(struct s2io_nic *nic) /** * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb */ -static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, int get_off) +static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \ + TxD *txdlp, int get_off) { - nic_t *nic = fifo_data->nic; + struct s2io_nic *nic = fifo_data->nic; struct sk_buff *skb; - TxD_t *txds; + struct TxD *txds; u16 j, frg_cnt; txds = txdlp; @@ -2113,7 +2036,7 @@ static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, in skb = (struct sk_buff *) ((unsigned long) txds->Host_Control); if (!skb) { - memset(txdlp, 0, (sizeof(TxD_t) * fifo_data->max_txds)); + memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds)); return NULL; } pci_unmap_single(nic->pdev, (dma_addr_t) @@ -2132,7 +2055,7 @@ static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, in frag->size, PCI_DMA_TODEVICE); } } - memset(txdlp,0, (sizeof(TxD_t) * fifo_data->max_txds)); + memset(txdlp,0, (sizeof(struct TxD) * fifo_data->max_txds)); return(skb); } @@ -2148,9 +2071,9 @@ static void free_tx_buffers(struct s2io_nic *nic) { struct net_device *dev = nic->dev; struct sk_buff *skb; - TxD_t *txdp; + struct TxD *txdp; int i, j; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; int cnt = 0; @@ -2159,7 +2082,7 @@ static void free_tx_buffers(struct s2io_nic *nic) for (i = 0; i < config->tx_fifo_num; i++) { for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) { - txdp = (TxD_t *) mac_control->fifos[i].list_info[j]. + txdp = (struct TxD *) mac_control->fifos[i].list_info[j]. list_virt_addr; skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j); if (skb) { @@ -2187,10 +2110,10 @@ static void free_tx_buffers(struct s2io_nic *nic) static void stop_nic(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0; u16 interruptible; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; mac_control = &nic->mac_control; @@ -2208,14 +2131,15 @@ static void stop_nic(struct s2io_nic *nic) writeq(val64, &bar0->adapter_control); } -static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb) +static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \ + sk_buff *skb) { struct net_device *dev = nic->dev; struct sk_buff *frag_list; void *tmp; /* Buffer-1 receives L3/L4 headers */ - ((RxD3_t*)rxdp)->Buffer1_ptr = pci_map_single + ((struct RxD3*)rxdp)->Buffer1_ptr = pci_map_single (nic->pdev, skb->data, l3l4hdr_size + 4, PCI_DMA_FROMDEVICE); @@ -2226,13 +2150,14 @@ static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb) return -ENOMEM ; } frag_list = skb_shinfo(skb)->frag_list; + skb->truesize += frag_list->truesize; frag_list->next = NULL; tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1); frag_list->data = tmp; frag_list->tail = tmp; /* Buffer-2 receives L4 data payload */ - ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev, + ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev, frag_list->data, dev->mtu, PCI_DMA_FROMDEVICE); rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4); @@ -2266,18 +2191,16 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) { struct net_device *dev = nic->dev; struct sk_buff *skb; - RxD_t *rxdp; + struct RxD_t *rxdp; int off, off1, size, block_no, block_no1; u32 alloc_tab = 0; u32 alloc_cnt; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; u64 tmp; - buffAdd_t *ba; -#ifndef CONFIG_S2IO_NAPI + struct buffAdd *ba; unsigned long flags; -#endif - RxD_t *first_rxdp = NULL; + struct RxD_t *first_rxdp = NULL; mac_control = &nic->mac_control; config = &nic->config; @@ -2320,12 +2243,15 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n", dev->name, rxdp); } -#ifndef CONFIG_S2IO_NAPI - spin_lock_irqsave(&nic->put_lock, flags); - mac_control->rings[ring_no].put_pos = - (block_no * (rxd_count[nic->rxd_mode] + 1)) + off; - spin_unlock_irqrestore(&nic->put_lock, flags); -#endif + if(!napi) { + spin_lock_irqsave(&nic->put_lock, flags); + mac_control->rings[ring_no].put_pos = + (block_no * (rxd_count[nic->rxd_mode] + 1)) + off; + spin_unlock_irqrestore(&nic->put_lock, flags); + } else { + mac_control->rings[ring_no].put_pos = + (block_no * (rxd_count[nic->rxd_mode] + 1)) + off; + } if ((rxdp->Control_1 & RXD_OWN_XENA) && ((nic->rxd_mode >= RXD_MODE_3A) && (rxdp->Control_2 & BIT(0)))) { @@ -2356,9 +2282,9 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) } if (nic->rxd_mode == RXD_MODE_1) { /* 1 buffer mode - normal operation mode */ - memset(rxdp, 0, sizeof(RxD1_t)); + memset(rxdp, 0, sizeof(struct RxD1)); skb_reserve(skb, NET_IP_ALIGN); - ((RxD1_t*)rxdp)->Buffer0_ptr = pci_map_single + ((struct RxD1*)rxdp)->Buffer0_ptr = pci_map_single (nic->pdev, skb->data, size - NET_IP_ALIGN, PCI_DMA_FROMDEVICE); rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN); @@ -2375,7 +2301,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) * payload */ - memset(rxdp, 0, sizeof(RxD3_t)); + memset(rxdp, 0, sizeof(struct RxD3)); ba = &mac_control->rings[ring_no].ba[block_no][off]; skb_reserve(skb, BUF0_LEN); tmp = (u64)(unsigned long) skb->data; @@ -2384,13 +2310,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) skb->data = (void *) (unsigned long)tmp; skb->tail = (void *) (unsigned long)tmp; - if (!(((RxD3_t*)rxdp)->Buffer0_ptr)) - ((RxD3_t*)rxdp)->Buffer0_ptr = + if (!(((struct RxD3*)rxdp)->Buffer0_ptr)) + ((struct RxD3*)rxdp)->Buffer0_ptr = pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN, PCI_DMA_FROMDEVICE); else pci_dma_sync_single_for_device(nic->pdev, - (dma_addr_t) ((RxD3_t*)rxdp)->Buffer0_ptr, + (dma_addr_t) ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN, PCI_DMA_FROMDEVICE); rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN); if (nic->rxd_mode == RXD_MODE_3B) { @@ -2400,13 +2326,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) * Buffer2 will have L3/L4 header plus * L4 payload */ - ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single + ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single (nic->pdev, skb->data, dev->mtu + 4, PCI_DMA_FROMDEVICE); /* Buffer-1 will be dummy buffer. Not used */ - if (!(((RxD3_t*)rxdp)->Buffer1_ptr)) { - ((RxD3_t*)rxdp)->Buffer1_ptr = + if (!(((struct RxD3*)rxdp)->Buffer1_ptr)) { + ((struct RxD3*)rxdp)->Buffer1_ptr = pci_map_single(nic->pdev, ba->ba_1, BUF1_LEN, PCI_DMA_FROMDEVICE); @@ -2466,9 +2392,9 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) struct net_device *dev = sp->dev; int j; struct sk_buff *skb; - RxD_t *rxdp; - mac_info_t *mac_control; - buffAdd_t *ba; + struct RxD_t *rxdp; + struct mac_info *mac_control; + struct buffAdd *ba; mac_control = &sp->mac_control; for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) { @@ -2481,41 +2407,41 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) } if (sp->rxd_mode == RXD_MODE_1) { pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD1_t*)rxdp)->Buffer0_ptr, + ((struct RxD1*)rxdp)->Buffer0_ptr, dev->mtu + HEADER_ETHERNET_II_802_3_SIZE + HEADER_802_2_SIZE + HEADER_SNAP_SIZE, PCI_DMA_FROMDEVICE); - memset(rxdp, 0, sizeof(RxD1_t)); + memset(rxdp, 0, sizeof(struct RxD1)); } else if(sp->rxd_mode == RXD_MODE_3B) { ba = &mac_control->rings[ring_no]. ba[blk][j]; pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer0_ptr, + ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN, PCI_DMA_FROMDEVICE); pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer1_ptr, + ((struct RxD3*)rxdp)->Buffer1_ptr, BUF1_LEN, PCI_DMA_FROMDEVICE); pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer2_ptr, + ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu + 4, PCI_DMA_FROMDEVICE); - memset(rxdp, 0, sizeof(RxD3_t)); + memset(rxdp, 0, sizeof(struct RxD3)); } else { pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN, + ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN, PCI_DMA_FROMDEVICE); pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer1_ptr, + ((struct RxD3*)rxdp)->Buffer1_ptr, l3l4hdr_size + 4, PCI_DMA_FROMDEVICE); pci_unmap_single(sp->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer2_ptr, dev->mtu, + ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu, PCI_DMA_FROMDEVICE); - memset(rxdp, 0, sizeof(RxD3_t)); + memset(rxdp, 0, sizeof(struct RxD3)); } dev_kfree_skb(skb); atomic_dec(&sp->rx_bufs_left[ring_no]); @@ -2535,7 +2461,7 @@ static void free_rx_buffers(struct s2io_nic *sp) { struct net_device *dev = sp->dev; int i, blk = 0, buf_cnt = 0; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; mac_control = &sp->mac_control; @@ -2568,15 +2494,13 @@ static void free_rx_buffers(struct s2io_nic *sp) * 0 on success and 1 if there are No Rx packets to be processed. */ -#if defined(CONFIG_S2IO_NAPI) static int s2io_poll(struct net_device *dev, int *budget) { - nic_t *nic = dev->priv; + struct s2io_nic *nic = dev->priv; int pkt_cnt = 0, org_pkts_to_process; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; - XENA_dev_config_t __iomem *bar0 = nic->bar0; - u64 val64 = 0xFFFFFFFFFFFFFFFFULL; + struct XENA_dev_config __iomem *bar0 = nic->bar0; int i; atomic_inc(&nic->isr_cnt); @@ -2588,8 +2512,8 @@ static int s2io_poll(struct net_device *dev, int *budget) nic->pkts_to_process = dev->quota; org_pkts_to_process = nic->pkts_to_process; - writeq(val64, &bar0->rx_traffic_int); - val64 = readl(&bar0->rx_traffic_int); + writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); + readl(&bar0->rx_traffic_int); for (i = 0; i < config->rx_ring_num; i++) { rx_intr_handler(&mac_control->rings[i]); @@ -2615,7 +2539,7 @@ static int s2io_poll(struct net_device *dev, int *budget) } /* Re enable the Rx interrupts. */ writeq(0x0, &bar0->rx_traffic_mask); - val64 = readl(&bar0->rx_traffic_mask); + readl(&bar0->rx_traffic_mask); atomic_dec(&nic->isr_cnt); return 0; @@ -2633,7 +2557,6 @@ no_rx: atomic_dec(&nic->isr_cnt); return 1; } -#endif #ifdef CONFIG_NET_POLL_CONTROLLER /** @@ -2647,10 +2570,10 @@ no_rx: */ static void s2io_netpoll(struct net_device *dev) { - nic_t *nic = dev->priv; - mac_info_t *mac_control; + struct s2io_nic *nic = dev->priv; + struct mac_info *mac_control; struct config_param *config; - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; u64 val64 = 0xFFFFFFFFFFFFFFFFULL; int i; @@ -2699,17 +2622,15 @@ static void s2io_netpoll(struct net_device *dev) * Return Value: * NONE. */ -static void rx_intr_handler(ring_info_t *ring_data) +static void rx_intr_handler(struct ring_info *ring_data) { - nic_t *nic = ring_data->nic; + struct s2io_nic *nic = ring_data->nic; struct net_device *dev = (struct net_device *) nic->dev; int get_block, put_block, put_offset; - rx_curr_get_info_t get_info, put_info; - RxD_t *rxdp; + struct rx_curr_get_info get_info, put_info; + struct RxD_t *rxdp; struct sk_buff *skb; -#ifndef CONFIG_S2IO_NAPI int pkt_cnt = 0; -#endif int i; spin_lock(&nic->rx_lock); @@ -2722,19 +2643,21 @@ static void rx_intr_handler(ring_info_t *ring_data) get_info = ring_data->rx_curr_get_info; get_block = get_info.block_index; - put_info = ring_data->rx_curr_put_info; + memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info)); put_block = put_info.block_index; rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr; -#ifndef CONFIG_S2IO_NAPI - spin_lock(&nic->put_lock); - put_offset = ring_data->put_pos; - spin_unlock(&nic->put_lock); -#else - put_offset = (put_block * (rxd_count[nic->rxd_mode] + 1)) + - put_info.offset; -#endif + if (!napi) { + spin_lock(&nic->put_lock); + put_offset = ring_data->put_pos; + spin_unlock(&nic->put_lock); + } else + put_offset = ring_data->put_pos; + while (RXD_IS_UP2DT(rxdp)) { - /* If your are next to put index then it's FIFO full condition */ + /* + * If your are next to put index then it's + * FIFO full condition + */ if ((get_block == put_block) && (get_info.offset + 1) == put_info.offset) { DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name); @@ -2750,7 +2673,7 @@ static void rx_intr_handler(ring_info_t *ring_data) } if (nic->rxd_mode == RXD_MODE_1) { pci_unmap_single(nic->pdev, (dma_addr_t) - ((RxD1_t*)rxdp)->Buffer0_ptr, + ((struct RxD1*)rxdp)->Buffer0_ptr, dev->mtu + HEADER_ETHERNET_II_802_3_SIZE + HEADER_802_2_SIZE + @@ -2758,22 +2681,22 @@ static void rx_intr_handler(ring_info_t *ring_data) PCI_DMA_FROMDEVICE); } else if (nic->rxd_mode == RXD_MODE_3B) { pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer0_ptr, + ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN, PCI_DMA_FROMDEVICE); pci_unmap_single(nic->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer2_ptr, + ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu + 4, PCI_DMA_FROMDEVICE); } else { pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN, + ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN, PCI_DMA_FROMDEVICE); pci_unmap_single(nic->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer1_ptr, + ((struct RxD3*)rxdp)->Buffer1_ptr, l3l4hdr_size + 4, PCI_DMA_FROMDEVICE); pci_unmap_single(nic->pdev, (dma_addr_t) - ((RxD3_t*)rxdp)->Buffer2_ptr, + ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu, PCI_DMA_FROMDEVICE); } prefetch(skb->data); @@ -2792,20 +2715,17 @@ static void rx_intr_handler(ring_info_t *ring_data) rxdp = ring_data->rx_blocks[get_block].block_virt_addr; } -#ifdef CONFIG_S2IO_NAPI nic->pkts_to_process -= 1; - if (!nic->pkts_to_process) + if ((napi) && (!nic->pkts_to_process)) break; -#else pkt_cnt++; if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts)) break; -#endif } if (nic->lro) { /* Clear all LRO sessions before exiting */ for (i=0; ilro0_n[i]; + struct lro *lro = &nic->lro0_n[i]; if (lro->in_use) { update_L3L4_header(nic, lro); queue_rx_frame(lro->parent); @@ -2829,17 +2749,17 @@ static void rx_intr_handler(ring_info_t *ring_data) * NONE */ -static void tx_intr_handler(fifo_info_t *fifo_data) +static void tx_intr_handler(struct fifo_info *fifo_data) { - nic_t *nic = fifo_data->nic; + struct s2io_nic *nic = fifo_data->nic; struct net_device *dev = (struct net_device *) nic->dev; - tx_curr_get_info_t get_info, put_info; + struct tx_curr_get_info get_info, put_info; struct sk_buff *skb; - TxD_t *txdlp; + struct TxD *txdlp; get_info = fifo_data->tx_curr_get_info; - put_info = fifo_data->tx_curr_put_info; - txdlp = (TxD_t *) fifo_data->list_info[get_info.offset]. + memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info)); + txdlp = (struct TxD *) fifo_data->list_info[get_info.offset]. list_virt_addr; while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) && (get_info.offset != put_info.offset) && @@ -2854,11 +2774,10 @@ static void tx_intr_handler(fifo_info_t *fifo_data) } if ((err >> 48) == 0xA) { DBG_PRINT(TX_DBG, "TxD returned due \ -to loss of link\n"); + to loss of link\n"); } else { - DBG_PRINT(ERR_DBG, "***TxD error \ -%llx\n", err); + DBG_PRINT(ERR_DBG, "***TxD error %llx\n", err); } } @@ -2877,7 +2796,7 @@ to loss of link\n"); get_info.offset++; if (get_info.offset == get_info.fifo_len + 1) get_info.offset = 0; - txdlp = (TxD_t *) fifo_data->list_info + txdlp = (struct TxD *) fifo_data->list_info [get_info.offset].list_virt_addr; fifo_data->tx_curr_get_info.offset = get_info.offset; @@ -2902,8 +2821,8 @@ to loss of link\n"); static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev) { u64 val64 = 0x0; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; //address transaction val64 = val64 | MDIO_MMD_INDX_ADDR(addr) @@ -2951,8 +2870,8 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev) { u64 val64 = 0x0; u64 rval64 = 0x0; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; /* address transaction */ val64 = val64 | MDIO_MMD_INDX_ADDR(addr) @@ -3055,8 +2974,8 @@ static void s2io_updt_xpak_counter(struct net_device *dev) u64 val64 = 0x0; u64 addr = 0x0; - nic_t *sp = dev->priv; - StatInfo_t *stat_info = sp->mac_control.stats_info; + struct s2io_nic *sp = dev->priv; + struct stat_block *stat_info = sp->mac_control.stats_info; /* Check the communication with the MDIO slave */ addr = 0x0000; @@ -3154,10 +3073,12 @@ static void s2io_updt_xpak_counter(struct net_device *dev) static void alarm_intr_handler(struct s2io_nic *nic) { struct net_device *dev = (struct net_device *) nic->dev; - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0, err_reg = 0; u64 cnt; int i; + if (atomic_read(&nic->card_state) == CARD_DOWN) + return; nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0; /* Handling the XPAK counters update */ if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) { @@ -3297,6 +3218,25 @@ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit) } return ret; } +/* + * check_pci_device_id - Checks if the device id is supported + * @id : device id + * Description: Function to check if the pci device id is supported by driver. + * Return value: Actual device id if supported else PCI_ANY_ID + */ +static u16 check_pci_device_id(u16 id) +{ + switch (id) { + case PCI_DEVICE_ID_HERC_WIN: + case PCI_DEVICE_ID_HERC_UNI: + return XFRAME_II_DEVICE; + case PCI_DEVICE_ID_S2IO_UNI: + case PCI_DEVICE_ID_S2IO_WIN: + return XFRAME_I_DEVICE; + default: + return PCI_ANY_ID; + } +} /** * s2io_reset - Resets the card. @@ -3308,42 +3248,57 @@ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit) * void. */ -static void s2io_reset(nic_t * sp) +static void s2io_reset(struct s2io_nic * sp) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; u16 subid, pci_cmd; + int i; + u16 val16; + DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n", + __FUNCTION__, sp->dev->name); /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */ pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd)); + if (sp->device_type == XFRAME_II_DEVICE) { + int ret; + ret = pci_set_power_state(sp->pdev, 3); + if (!ret) + ret = pci_set_power_state(sp->pdev, 0); + else { + DBG_PRINT(ERR_DBG,"%s PME based SW_Reset failed!\n", + __FUNCTION__); + goto old_way; + } + msleep(20); + goto new_way; + } +old_way: val64 = SW_RESET_ALL; writeq(val64, &bar0->sw_reset); - - /* - * At this stage, if the PCI write is indeed completed, the - * card is reset and so is the PCI Config space of the device. - * So a read cannot be issued at this stage on any of the - * registers to ensure the write into "sw_reset" register - * has gone through. - * Question: Is there any system call that will explicitly force - * all the write commands still pending on the bus to be pushed - * through? - * As of now I'am just giving a 250ms delay and hoping that the - * PCI write to sw_reset register is done by this time. - */ - msleep(250); +new_way: if (strstr(sp->product_name, "CX4")) { msleep(750); } - - /* Restore the PCI state saved during initialization. */ - pci_restore_state(sp->pdev); - pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - pci_cmd); - s2io_init_pci(sp); - msleep(250); + for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) { + + /* Restore the PCI state saved during initialization. */ + pci_restore_state(sp->pdev); + pci_read_config_word(sp->pdev, 0x2, &val16); + if (check_pci_device_id(val16) != (u16)PCI_ANY_ID) + break; + msleep(200); + } + + if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) { + DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__); + } + + pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd); + + s2io_init_pci(sp); /* Set swapper to enable I/O register access */ s2io_set_swapper(sp); @@ -3399,10 +3354,10 @@ static void s2io_reset(nic_t * sp) * SUCCESS on success and FAILURE on failure. */ -static int s2io_set_swapper(nic_t * sp) +static int s2io_set_swapper(struct s2io_nic * sp) { struct net_device *dev = sp->dev; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64, valt, valr; /* @@ -3527,9 +3482,9 @@ static int s2io_set_swapper(nic_t * sp) return SUCCESS; } -static int wait_for_msix_trans(nic_t *nic, int i) +static int wait_for_msix_trans(struct s2io_nic *nic, int i) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; u64 val64; int ret = 0, cnt = 0; @@ -3548,9 +3503,9 @@ static int wait_for_msix_trans(nic_t *nic, int i) return ret; } -static void restore_xmsi_data(nic_t *nic) +static void restore_xmsi_data(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; u64 val64; int i; @@ -3566,9 +3521,9 @@ static void restore_xmsi_data(nic_t *nic) } } -static void store_xmsi_data(nic_t *nic) +static void store_xmsi_data(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; u64 val64, addr, data; int i; @@ -3589,9 +3544,9 @@ static void store_xmsi_data(nic_t *nic) } } -int s2io_enable_msi(nic_t *nic) +int s2io_enable_msi(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; u16 msi_ctrl, msg_val; struct config_param *config = &nic->config; struct net_device *dev = nic->dev; @@ -3639,9 +3594,9 @@ int s2io_enable_msi(nic_t *nic) return 0; } -static int s2io_enable_msi_x(nic_t *nic) +static int s2io_enable_msi_x(struct s2io_nic *nic) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; u64 tx_mat, rx_mat; u16 msi_control; /* Temp variable */ int ret, i, j, msix_indx = 1; @@ -3749,7 +3704,7 @@ static int s2io_enable_msi_x(nic_t *nic) static int s2io_open(struct net_device *dev) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; int err = 0; /* @@ -3802,7 +3757,7 @@ hw_init_failed: static int s2io_close(struct net_device *dev) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; flush_scheduled_work(); netif_stop_queue(dev); @@ -3828,15 +3783,15 @@ static int s2io_close(struct net_device *dev) static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off; register u64 val64; - TxD_t *txdp; - TxFIFO_element_t __iomem *tx_fifo; + struct TxD *txdp; + struct TxFIFO_element __iomem *tx_fifo; unsigned long flags; u16 vlan_tag = 0; int vlan_priority = 0; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; int offload_type; @@ -3864,7 +3819,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset; get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset; - txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off]. + txdp = (struct TxD *) mac_control->fifos[queue].list_info[put_off]. list_virt_addr; queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1; @@ -3887,12 +3842,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) } offload_type = s2io_offload_type(skb); -#ifdef NETIF_F_TSO if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { txdp->Control_1 |= TXD_TCP_LSO_EN; txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb)); } -#endif if (skb->ip_summed == CHECKSUM_PARTIAL) { txdp->Control_2 |= (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN | @@ -3993,13 +3946,13 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) static void s2io_alarm_handle(unsigned long data) { - nic_t *sp = (nic_t *)data; + struct s2io_nic *sp = (struct s2io_nic *)data; alarm_intr_handler(sp); mod_timer(&sp->alarm_timer, jiffies + HZ / 2); } -static int s2io_chk_rx_buffers(nic_t *sp, int rng_n) +static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n) { int rxb_size, level; @@ -4031,9 +3984,9 @@ static int s2io_chk_rx_buffers(nic_t *sp, int rng_n) static irqreturn_t s2io_msi_handle(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; int i; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; atomic_inc(&sp->isr_cnt); @@ -4063,8 +4016,8 @@ static irqreturn_t s2io_msi_handle(int irq, void *dev_id) static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) { - ring_info_t *ring = (ring_info_t *)dev_id; - nic_t *sp = ring->nic; + struct ring_info *ring = (struct ring_info *)dev_id; + struct s2io_nic *sp = ring->nic; atomic_inc(&sp->isr_cnt); @@ -4077,17 +4030,17 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id) { - fifo_info_t *fifo = (fifo_info_t *)dev_id; - nic_t *sp = fifo->nic; + struct fifo_info *fifo = (struct fifo_info *)dev_id; + struct s2io_nic *sp = fifo->nic; atomic_inc(&sp->isr_cnt); tx_intr_handler(fifo); atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } -static void s2io_txpic_intr_handle(nic_t *sp) +static void s2io_txpic_intr_handle(struct s2io_nic *sp) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; val64 = readq(&bar0->pic_int_status); @@ -4109,39 +4062,33 @@ static void s2io_txpic_intr_handle(nic_t *sp) } else if (val64 & GPIO_INT_REG_LINK_UP) { val64 = readq(&bar0->adapter_status); - if (verify_xena_quiescence(sp, val64, - sp->device_enabled_once)) { /* Enable Adapter */ - val64 = readq(&bar0->adapter_control); - val64 |= ADAPTER_CNTL_EN; - writeq(val64, &bar0->adapter_control); - val64 |= ADAPTER_LED_ON; - writeq(val64, &bar0->adapter_control); - if (!sp->device_enabled_once) - sp->device_enabled_once = 1; + val64 = readq(&bar0->adapter_control); + val64 |= ADAPTER_CNTL_EN; + writeq(val64, &bar0->adapter_control); + val64 |= ADAPTER_LED_ON; + writeq(val64, &bar0->adapter_control); + if (!sp->device_enabled_once) + sp->device_enabled_once = 1; - s2io_link(sp, LINK_UP); - /* - * unmask link down interrupt and mask link-up - * intr - */ - val64 = readq(&bar0->gpio_int_mask); - val64 &= ~GPIO_INT_MASK_LINK_DOWN; - val64 |= GPIO_INT_MASK_LINK_UP; - writeq(val64, &bar0->gpio_int_mask); + s2io_link(sp, LINK_UP); + /* + * unmask link down interrupt and mask link-up + * intr + */ + val64 = readq(&bar0->gpio_int_mask); + val64 &= ~GPIO_INT_MASK_LINK_DOWN; + val64 |= GPIO_INT_MASK_LINK_UP; + writeq(val64, &bar0->gpio_int_mask); - } }else if (val64 & GPIO_INT_REG_LINK_DOWN) { val64 = readq(&bar0->adapter_status); - if (verify_xena_quiescence(sp, val64, - sp->device_enabled_once)) { - s2io_link(sp, LINK_DOWN); - /* Link is down so unmaks link up interrupt */ - val64 = readq(&bar0->gpio_int_mask); - val64 &= ~GPIO_INT_MASK_LINK_UP; - val64 |= GPIO_INT_MASK_LINK_DOWN; - writeq(val64, &bar0->gpio_int_mask); - } + s2io_link(sp, LINK_DOWN); + /* Link is down so unmaks link up interrupt */ + val64 = readq(&bar0->gpio_int_mask); + val64 &= ~GPIO_INT_MASK_LINK_UP; + val64 |= GPIO_INT_MASK_LINK_DOWN; + writeq(val64, &bar0->gpio_int_mask); } } val64 = readq(&bar0->gpio_int_mask); @@ -4163,11 +4110,11 @@ static void s2io_txpic_intr_handle(nic_t *sp) static irqreturn_t s2io_isr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; int i; - u64 reason = 0, val64, org_mask; - mac_info_t *mac_control; + u64 reason = 0; + struct mac_info *mac_control; struct config_param *config; atomic_inc(&sp->isr_cnt); @@ -4185,43 +4132,48 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) reason = readq(&bar0->general_int_status); if (!reason) { - /* The interrupt was not raised by Xena. */ + /* The interrupt was not raised by us. */ + atomic_dec(&sp->isr_cnt); + return IRQ_NONE; + } + else if (unlikely(reason == S2IO_MINUS_ONE) ) { + /* Disable device and get out */ atomic_dec(&sp->isr_cnt); return IRQ_NONE; } - val64 = 0xFFFFFFFFFFFFFFFFULL; - /* Store current mask before masking all interrupts */ - org_mask = readq(&bar0->general_int_mask); - writeq(val64, &bar0->general_int_mask); + if (napi) { + if (reason & GEN_INTR_RXTRAFFIC) { + if ( likely ( netif_rx_schedule_prep(dev)) ) { + __netif_rx_schedule(dev); + writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask); + } + else + writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); + } + } else { + /* + * Rx handler is called by default, without checking for the + * cause of interrupt. + * rx_traffic_int reg is an R1 register, writing all 1's + * will ensure that the actual interrupt causing bit get's + * cleared and hence a read can be avoided. + */ + if (reason & GEN_INTR_RXTRAFFIC) + writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); -#ifdef CONFIG_S2IO_NAPI - if (reason & GEN_INTR_RXTRAFFIC) { - if (netif_rx_schedule_prep(dev)) { - writeq(val64, &bar0->rx_traffic_mask); - __netif_rx_schedule(dev); + for (i = 0; i < config->rx_ring_num; i++) { + rx_intr_handler(&mac_control->rings[i]); } } -#else - /* - * Rx handler is called by default, without checking for the - * cause of interrupt. - * rx_traffic_int reg is an R1 register, writing all 1's - * will ensure that the actual interrupt causing bit get's - * cleared and hence a read can be avoided. - */ - writeq(val64, &bar0->rx_traffic_int); - for (i = 0; i < config->rx_ring_num; i++) { - rx_intr_handler(&mac_control->rings[i]); - } -#endif /* * tx_traffic_int reg is an R1 register, writing all 1's * will ensure that the actual interrupt causing bit get's * cleared and hence a read can be avoided. */ - writeq(val64, &bar0->tx_traffic_int); + if (reason & GEN_INTR_TXTRAFFIC) + writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int); for (i = 0; i < config->tx_fifo_num; i++) tx_intr_handler(&mac_control->fifos[i]); @@ -4233,11 +4185,14 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) * reallocate the buffers from the interrupt handler itself, * else schedule a tasklet to reallocate the buffers. */ -#ifndef CONFIG_S2IO_NAPI - for (i = 0; i < config->rx_ring_num; i++) - s2io_chk_rx_buffers(sp, i); -#endif - writeq(org_mask, &bar0->general_int_mask); + if (!napi) { + for (i = 0; i < config->rx_ring_num; i++) + s2io_chk_rx_buffers(sp, i); + } + + writeq(0, &bar0->general_int_mask); + readl(&bar0->general_int_status); + atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } @@ -4245,9 +4200,9 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) /** * s2io_updt_stats - */ -static void s2io_updt_stats(nic_t *sp) +static void s2io_updt_stats(struct s2io_nic *sp) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; int cnt = 0; @@ -4266,7 +4221,7 @@ static void s2io_updt_stats(nic_t *sp) break; /* Updt failed */ } while(1); } else { - memset(sp->mac_control.stats_info, 0, sizeof(StatInfo_t)); + memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block)); } } @@ -4282,8 +4237,8 @@ static void s2io_updt_stats(nic_t *sp) static struct net_device_stats *s2io_get_stats(struct net_device *dev) { - nic_t *sp = dev->priv; - mac_info_t *mac_control; + struct s2io_nic *sp = dev->priv; + struct mac_info *mac_control; struct config_param *config; @@ -4324,8 +4279,8 @@ static void s2io_set_multicast(struct net_device *dev) { int i, j, prev_cnt; struct dev_mc_list *mclist; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0, multi_mac = 0x010203040506ULL, mask = 0xfeffffffffffULL; u64 dis_addr = 0xffffffffffffULL, mac_addr = 0; @@ -4478,8 +4433,8 @@ static void s2io_set_multicast(struct net_device *dev) static int s2io_set_mac_addr(struct net_device *dev, u8 * addr) { - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; register u64 val64, mac_addr = 0; int i; @@ -4525,7 +4480,7 @@ static int s2io_set_mac_addr(struct net_device *dev, u8 * addr) static int s2io_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; if ((info->autoneg == AUTONEG_ENABLE) || (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL)) return -EINVAL; @@ -4551,7 +4506,7 @@ static int s2io_ethtool_sset(struct net_device *dev, static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); info->port = PORT_FIBRE; @@ -4584,7 +4539,7 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) static void s2io_ethtool_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; strncpy(info->driver, s2io_driver_name, sizeof(info->driver)); strncpy(info->version, s2io_driver_version, sizeof(info->version)); @@ -4616,7 +4571,7 @@ static void s2io_ethtool_gregs(struct net_device *dev, int i; u64 reg; u8 *reg_space = (u8 *) space; - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; regs->len = XENA_REG_SPACE; regs->version = sp->pdev->subsystem_device; @@ -4638,8 +4593,8 @@ static void s2io_ethtool_gregs(struct net_device *dev, */ static void s2io_phy_id(unsigned long data) { - nic_t *sp = (nic_t *) data; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = (struct s2io_nic *) data; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0; u16 subid; @@ -4676,8 +4631,8 @@ static void s2io_phy_id(unsigned long data) static int s2io_ethtool_idnic(struct net_device *dev, u32 data) { u64 val64 = 0, last_gpio_ctrl_val; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u16 subid; subid = sp->pdev->subsystem_device; @@ -4725,8 +4680,8 @@ static void s2io_ethtool_getpause_data(struct net_device *dev, struct ethtool_pauseparam *ep) { u64 val64; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; val64 = readq(&bar0->rmac_pause_cfg); if (val64 & RMAC_PAUSE_GEN_ENABLE) @@ -4752,8 +4707,8 @@ static int s2io_ethtool_setpause_data(struct net_device *dev, struct ethtool_pauseparam *ep) { u64 val64; - nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct s2io_nic *sp = dev->priv; + struct XENA_dev_config __iomem *bar0 = sp->bar0; val64 = readq(&bar0->rmac_pause_cfg); if (ep->tx_pause) @@ -4785,12 +4740,12 @@ static int s2io_ethtool_setpause_data(struct net_device *dev, */ #define S2IO_DEV_ID 5 -static int read_eeprom(nic_t * sp, int off, u64 * data) +static int read_eeprom(struct s2io_nic * sp, int off, u64 * data) { int ret = -1; u32 exit_cnt = 0; u64 val64; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; if (sp->device_type == XFRAME_I_DEVICE) { val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | @@ -4850,11 +4805,11 @@ static int read_eeprom(nic_t * sp, int off, u64 * data) * 0 on success, -1 on failure. */ -static int write_eeprom(nic_t * sp, int off, u64 data, int cnt) +static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt) { int exit_cnt = 0, ret = -1; u64 val64; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; if (sp->device_type == XFRAME_I_DEVICE) { val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) | @@ -4899,7 +4854,7 @@ static int write_eeprom(nic_t * sp, int off, u64 data, int cnt) } return ret; } -static void s2io_vpd_read(nic_t *nic) +static void s2io_vpd_read(struct s2io_nic *nic) { u8 *vpd_data; u8 data; @@ -4914,6 +4869,7 @@ static void s2io_vpd_read(nic_t *nic) strcpy(nic->product_name, "Xframe I 10GbE network adapter"); vpd_addr = 0x50; } + strcpy(nic->serial_num, "NOT AVAILABLE"); vpd_data = kmalloc(256, GFP_KERNEL); if (!vpd_data) @@ -4937,7 +4893,22 @@ static void s2io_vpd_read(nic_t *nic) pci_read_config_dword(nic->pdev, (vpd_addr + 4), (u32 *)&vpd_data[i]); } - if ((!fail) && (vpd_data[1] < VPD_PRODUCT_NAME_LEN)) { + + if(!fail) { + /* read serial number of adapter */ + for (cnt = 0; cnt < 256; cnt++) { + if ((vpd_data[cnt] == 'S') && + (vpd_data[cnt+1] == 'N') && + (vpd_data[cnt+2] < VPD_STRING_LEN)) { + memset(nic->serial_num, 0, VPD_STRING_LEN); + memcpy(nic->serial_num, &vpd_data[cnt + 3], + vpd_data[cnt+2]); + break; + } + } + } + + if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) { memset(nic->product_name, 0, vpd_data[1]); memcpy(nic->product_name, &vpd_data[3], vpd_data[1]); } @@ -4962,7 +4933,7 @@ static int s2io_ethtool_geeprom(struct net_device *dev, { u32 i, valid; u64 data; - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16); @@ -5000,7 +4971,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev, { int len = eeprom->len, cnt = 0; u64 valid = 0, data; - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) { DBG_PRINT(ERR_DBG, @@ -5044,9 +5015,9 @@ static int s2io_ethtool_seeprom(struct net_device *dev, * 0 on success. */ -static int s2io_register_test(nic_t * sp, uint64_t * data) +static int s2io_register_test(struct s2io_nic * sp, uint64_t * data) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0, exp_val; int fail = 0; @@ -5111,7 +5082,7 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) * 0 on success. */ -static int s2io_eeprom_test(nic_t * sp, uint64_t * data) +static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data) { int fail = 0; u64 ret_data, org_4F0, org_7F0; @@ -5213,7 +5184,7 @@ static int s2io_eeprom_test(nic_t * sp, uint64_t * data) * 0 on success and -1 on failure. */ -static int s2io_bist_test(nic_t * sp, uint64_t * data) +static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data) { u8 bist = 0; int cnt = 0, ret = -1; @@ -5249,9 +5220,9 @@ static int s2io_bist_test(nic_t * sp, uint64_t * data) * 0 on success. */ -static int s2io_link_test(nic_t * sp, uint64_t * data) +static int s2io_link_test(struct s2io_nic * sp, uint64_t * data) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; val64 = readq(&bar0->adapter_status); @@ -5276,9 +5247,9 @@ static int s2io_link_test(nic_t * sp, uint64_t * data) * 0 on success. */ -static int s2io_rldram_test(nic_t * sp, uint64_t * data) +static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data) { - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64; int cnt, iteration = 0, test_fail = 0; @@ -5380,7 +5351,7 @@ static void s2io_ethtool_test(struct net_device *dev, struct ethtool_test *ethtest, uint64_t * data) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; int orig_state = netif_running(sp->dev); if (ethtest->flags == ETH_TEST_FL_OFFLINE) { @@ -5436,8 +5407,8 @@ static void s2io_get_ethtool_stats(struct net_device *dev, u64 * tmp_stats) { int i = 0; - nic_t *sp = dev->priv; - StatInfo_t *stat_info = sp->mac_control.stats_info; + struct s2io_nic *sp = dev->priv; + struct stat_block *stat_info = sp->mac_control.stats_info; s2io_updt_stats(sp); tmp_stats[i++] = @@ -5664,14 +5635,14 @@ static int s2io_ethtool_get_regs_len(struct net_device *dev) static u32 s2io_ethtool_get_rx_csum(struct net_device * dev) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; return (sp->rx_csum); } static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; if (data) sp->rx_csum = 1; @@ -5750,10 +5721,8 @@ static const struct ethtool_ops netdev_ethtool_ops = { .set_tx_csum = s2io_ethtool_op_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, -#ifdef NETIF_F_TSO .get_tso = s2io_ethtool_op_get_tso, .set_tso = s2io_ethtool_op_set_tso, -#endif .get_ufo = ethtool_op_get_ufo, .set_ufo = ethtool_op_set_ufo, .self_test_count = s2io_ethtool_self_test_count, @@ -5794,7 +5763,7 @@ static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int s2io_change_mtu(struct net_device *dev, int new_mtu) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) { DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n", @@ -5813,7 +5782,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu) if (netif_queue_stopped(dev)) netif_wake_queue(dev); } else { /* Device is down */ - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = new_mtu; writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len); @@ -5838,9 +5807,9 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu) static void s2io_tasklet(unsigned long dev_addr) { struct net_device *dev = (struct net_device *) dev_addr; - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; int i, ret; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; mac_control = &sp->mac_control; @@ -5873,9 +5842,9 @@ static void s2io_tasklet(unsigned long dev_addr) static void s2io_set_link(struct work_struct *work) { - nic_t *nic = container_of(work, nic_t, set_link_task); + struct s2io_nic *nic = container_of(work, struct s2io_nic, set_link_task); struct net_device *dev = nic->dev; - XENA_dev_config_t __iomem *bar0 = nic->bar0; + struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64; u16 subid; @@ -5894,57 +5863,53 @@ static void s2io_set_link(struct work_struct *work) } val64 = readq(&bar0->adapter_status); - if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) { - if (LINK_IS_UP(val64)) { - val64 = readq(&bar0->adapter_control); - val64 |= ADAPTER_CNTL_EN; - writeq(val64, &bar0->adapter_control); - if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type, - subid)) { - val64 = readq(&bar0->gpio_control); - val64 |= GPIO_CTRL_GPIO_0; - writeq(val64, &bar0->gpio_control); - val64 = readq(&bar0->gpio_control); - } else { - val64 |= ADAPTER_LED_ON; + if (LINK_IS_UP(val64)) { + if (!(readq(&bar0->adapter_control) & ADAPTER_CNTL_EN)) { + if (verify_xena_quiescence(nic)) { + val64 = readq(&bar0->adapter_control); + val64 |= ADAPTER_CNTL_EN; writeq(val64, &bar0->adapter_control); - } - if (s2io_link_fault_indication(nic) == - MAC_RMAC_ERR_TIMER) { - val64 = readq(&bar0->adapter_status); - if (!LINK_IS_UP(val64)) { - DBG_PRINT(ERR_DBG, "%s:", dev->name); - DBG_PRINT(ERR_DBG, " Link down"); - DBG_PRINT(ERR_DBG, "after "); - DBG_PRINT(ERR_DBG, "enabling "); - DBG_PRINT(ERR_DBG, "device \n"); + if (CARDS_WITH_FAULTY_LINK_INDICATORS( + nic->device_type, subid)) { + val64 = readq(&bar0->gpio_control); + val64 |= GPIO_CTRL_GPIO_0; + writeq(val64, &bar0->gpio_control); + val64 = readq(&bar0->gpio_control); + } else { + val64 |= ADAPTER_LED_ON; + writeq(val64, &bar0->adapter_control); } - } - if (nic->device_enabled_once == FALSE) { nic->device_enabled_once = TRUE; + } else { + DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name); + DBG_PRINT(ERR_DBG, "device is not Quiescent\n"); + netif_stop_queue(dev); } - s2io_link(nic, LINK_UP); - } else { - if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type, - subid)) { - val64 = readq(&bar0->gpio_control); - val64 &= ~GPIO_CTRL_GPIO_0; - writeq(val64, &bar0->gpio_control); - val64 = readq(&bar0->gpio_control); - } - s2io_link(nic, LINK_DOWN); } - } else { /* NIC is not Quiescent. */ - DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name); - DBG_PRINT(ERR_DBG, "device is not Quiescent\n"); - netif_stop_queue(dev); + val64 = readq(&bar0->adapter_status); + if (!LINK_IS_UP(val64)) { + DBG_PRINT(ERR_DBG, "%s:", dev->name); + DBG_PRINT(ERR_DBG, " Link down after enabling "); + DBG_PRINT(ERR_DBG, "device \n"); + } else + s2io_link(nic, LINK_UP); + } else { + if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type, + subid)) { + val64 = readq(&bar0->gpio_control); + val64 &= ~GPIO_CTRL_GPIO_0; + writeq(val64, &bar0->gpio_control); + val64 = readq(&bar0->gpio_control); + } + s2io_link(nic, LINK_DOWN); } clear_bit(0, &(nic->link_state)); } -static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba, - struct sk_buff **skb, u64 *temp0, u64 *temp1, - u64 *temp2, int size) +static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, + struct buffAdd *ba, + struct sk_buff **skb, u64 *temp0, u64 *temp1, + u64 *temp2, int size) { struct net_device *dev = sp->dev; struct sk_buff *frag_list; @@ -5958,7 +5923,7 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba, * using same mapped address for the Rxd * buffer pointer */ - ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0; + ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0; } else { *skb = dev_alloc_skb(size); if (!(*skb)) { @@ -5970,7 +5935,7 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba, * such it will be used for next rxd whose * Host Control is NULL */ - ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0 = + ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0 = pci_map_single( sp->pdev, (*skb)->data, size - NET_IP_ALIGN, PCI_DMA_FROMDEVICE); @@ -5979,36 +5944,36 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba, } else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) { /* Two buffer Mode */ if (*skb) { - ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2; - ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0; - ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1; + ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2; + ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0; + ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1; } else { *skb = dev_alloc_skb(size); if (!(*skb)) { DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n", - dev->name); + dev->name); return -ENOMEM; } - ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 = + ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 = pci_map_single(sp->pdev, (*skb)->data, dev->mtu + 4, PCI_DMA_FROMDEVICE); - ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 = + ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 = pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN, PCI_DMA_FROMDEVICE); rxdp->Host_Control = (unsigned long) (*skb); /* Buffer-1 will be dummy buffer not used */ - ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 = + ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 = pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN, PCI_DMA_FROMDEVICE); } } else if ((rxdp->Host_Control == 0)) { /* Three buffer mode */ if (*skb) { - ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0; - ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1; - ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2; + ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0; + ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1; + ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2; } else { *skb = dev_alloc_skb(size); if (!(*skb)) { @@ -6016,11 +5981,11 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba, dev->name); return -ENOMEM; } - ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 = + ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 = pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN, PCI_DMA_FROMDEVICE); /* Buffer-1 receives L3/L4 headers */ - ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 = + ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 = pci_map_single( sp->pdev, (*skb)->data, l3l4hdr_size + 4, PCI_DMA_FROMDEVICE); @@ -6040,14 +6005,15 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba, /* * Buffer-2 receives L4 data payload */ - ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 = + ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 = pci_map_single( sp->pdev, frag_list->data, dev->mtu, PCI_DMA_FROMDEVICE); } } return 0; } -static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size) +static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp, + int size) { struct net_device *dev = sp->dev; if (sp->rxd_mode == RXD_MODE_1) { @@ -6063,15 +6029,15 @@ static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size) } } -static int rxd_owner_bit_reset(nic_t *sp) +static int rxd_owner_bit_reset(struct s2io_nic *sp) { int i, j, k, blk_cnt = 0, size; - mac_info_t * mac_control = &sp->mac_control; + struct mac_info * mac_control = &sp->mac_control; struct config_param *config = &sp->config; struct net_device *dev = sp->dev; - RxD_t *rxdp = NULL; + struct RxD_t *rxdp = NULL; struct sk_buff *skb = NULL; - buffAdd_t *ba = NULL; + struct buffAdd *ba = NULL; u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0; /* Calculate the size based on ring mode */ @@ -6110,7 +6076,7 @@ static int rxd_owner_bit_reset(nic_t *sp) } -static int s2io_add_isr(nic_t * sp) +static int s2io_add_isr(struct s2io_nic * sp) { int ret = 0; struct net_device *dev = sp->dev; @@ -6125,7 +6091,7 @@ static int s2io_add_isr(nic_t * sp) sp->intr_type = INTA; } - /* Store the values of the MSIX table in the nic_t structure */ + /* Store the values of the MSIX table in the struct s2io_nic structure */ store_xmsi_data(sp); /* After proper initialization of H/W, register ISR */ @@ -6180,7 +6146,7 @@ static int s2io_add_isr(nic_t * sp) } return 0; } -static void s2io_rem_isr(nic_t * sp) +static void s2io_rem_isr(struct s2io_nic * sp) { int cnt = 0; struct net_device *dev = sp->dev; @@ -6222,10 +6188,10 @@ static void s2io_rem_isr(nic_t * sp) } while(cnt < 5); } -static void s2io_card_down(nic_t * sp) +static void s2io_card_down(struct s2io_nic * sp) { int cnt = 0; - XENA_dev_config_t __iomem *bar0 = sp->bar0; + struct XENA_dev_config __iomem *bar0 = sp->bar0; unsigned long flags; register u64 val64 = 0; @@ -6256,7 +6222,8 @@ static void s2io_card_down(nic_t * sp) rxd_owner_bit_reset(sp); val64 = readq(&bar0->adapter_status); - if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) { + if (verify_xena_quiescence(sp)) { + if(verify_pcc_quiescent(sp, sp->device_enabled_once)) break; } @@ -6285,10 +6252,10 @@ static void s2io_card_down(nic_t * sp) clear_bit(0, &(sp->link_state)); } -static int s2io_card_up(nic_t * sp) +static int s2io_card_up(struct s2io_nic * sp) { int i, ret = 0; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; struct net_device *dev = (struct net_device *) sp->dev; u16 interruptible; @@ -6319,6 +6286,13 @@ static int s2io_card_up(nic_t * sp) DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i, atomic_read(&sp->rx_bufs_left[i])); } + /* Maintain the state prior to the open */ + if (sp->promisc_flg) + sp->promisc_flg = 0; + if (sp->m_cast_flg) { + sp->m_cast_flg = 0; + sp->all_multi_pos= 0; + } /* Setting its receive mode */ s2io_set_multicast(dev); @@ -6380,7 +6354,7 @@ static int s2io_card_up(nic_t * sp) static void s2io_restart_nic(struct work_struct *work) { - nic_t *sp = container_of(work, nic_t, rst_timer_task); + struct s2io_nic *sp = container_of(work, struct s2io_nic, rst_timer_task); struct net_device *dev = sp->dev; s2io_card_down(sp); @@ -6409,7 +6383,7 @@ static void s2io_restart_nic(struct work_struct *work) static void s2io_tx_watchdog(struct net_device *dev) { - nic_t *sp = dev->priv; + struct s2io_nic *sp = dev->priv; if (netif_carrier_ok(dev)) { schedule_work(&sp->rst_timer_task); @@ -6434,16 +6408,16 @@ static void s2io_tx_watchdog(struct net_device *dev) * Return value: * SUCCESS on success and -1 on failure. */ -static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) +static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) { - nic_t *sp = ring_data->nic; + struct s2io_nic *sp = ring_data->nic; struct net_device *dev = (struct net_device *) sp->dev; struct sk_buff *skb = (struct sk_buff *) ((unsigned long) rxdp->Host_Control); int ring_no = ring_data->ring_no; u16 l3_csum, l4_csum; unsigned long long err = rxdp->Control_1 & RXD_T_CODE; - lro_t *lro; + struct lro *lro; skb->dev = dev; @@ -6488,7 +6462,7 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2); unsigned char *buff = skb_push(skb, buf0_len); - buffAdd_t *ba = &ring_data->ba[get_block][get_off]; + struct buffAdd *ba = &ring_data->ba[get_block][get_off]; sp->stats.rx_bytes += buf0_len + buf2_len; memcpy(buff, ba->ba_0, buf0_len); @@ -6498,7 +6472,6 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) skb_put(skb, buf1_len); skb->len += buf2_len; skb->data_len += buf2_len; - skb->truesize += buf2_len; skb_put(skb_shinfo(skb)->frag_list, buf2_len); sp->stats.rx_bytes += buf1_len; @@ -6582,23 +6555,20 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) if (!sp->lro) { skb->protocol = eth_type_trans(skb, dev); -#ifdef CONFIG_S2IO_NAPI if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { /* Queueing the vlan frame to the upper layer */ - vlan_hwaccel_receive_skb(skb, sp->vlgrp, - RXD_GET_VLAN_TAG(rxdp->Control_2)); + if (napi) + vlan_hwaccel_receive_skb(skb, sp->vlgrp, + RXD_GET_VLAN_TAG(rxdp->Control_2)); + else + vlan_hwaccel_rx(skb, sp->vlgrp, + RXD_GET_VLAN_TAG(rxdp->Control_2)); } else { - netif_receive_skb(skb); + if (napi) + netif_receive_skb(skb); + else + netif_rx(skb); } -#else - if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { - /* Queueing the vlan frame to the upper layer */ - vlan_hwaccel_rx(skb, sp->vlgrp, - RXD_GET_VLAN_TAG(rxdp->Control_2)); - } else { - netif_rx(skb); - } -#endif } else { send_up: queue_rx_frame(skb); @@ -6622,7 +6592,7 @@ aggregate: * void. */ -static void s2io_link(nic_t * sp, int link) +static void s2io_link(struct s2io_nic * sp, int link) { struct net_device *dev = (struct net_device *) sp->dev; @@ -6666,7 +6636,7 @@ static int get_xena_rev_id(struct pci_dev *pdev) * void */ -static void s2io_init_pci(nic_t * sp) +static void s2io_init_pci(struct s2io_nic * sp) { u16 pci_cmd = 0, pcix_cmd = 0; @@ -6699,13 +6669,9 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type) DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n"); rx_ring_num = 8; } -#ifdef CONFIG_S2IO_NAPI - if (*dev_intr_type != INTA) { - DBG_PRINT(ERR_DBG, "s2io: NAPI cannot be enabled when " - "MSI/MSI-X is enabled. Defaulting to INTA\n"); - *dev_intr_type = INTA; - } -#endif + if (*dev_intr_type != INTA) + napi = 0; + #ifndef CONFIG_PCI_MSI if (*dev_intr_type != INTA) { DBG_PRINT(ERR_DBG, "s2io: This kernel does not support" @@ -6726,6 +6692,8 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type) "Defaulting to INTA\n"); *dev_intr_type = INTA; } + if ( (rx_ring_num > 1) && (*dev_intr_type != INTA) ) + napi = 0; if (rx_ring_mode > 3) { DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n"); DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n"); @@ -6751,15 +6719,15 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type) static int __devinit s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) { - nic_t *sp; + struct s2io_nic *sp; struct net_device *dev; int i, j, ret; int dma_flag = FALSE; u32 mac_up, mac_down; u64 val64 = 0, tmp64 = 0; - XENA_dev_config_t __iomem *bar0 = NULL; + struct XENA_dev_config __iomem *bar0 = NULL; u16 subid; - mac_info_t *mac_control; + struct mac_info *mac_control; struct config_param *config; int mode; u8 dev_intr_type = intr_type; @@ -6814,7 +6782,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } } - dev = alloc_etherdev(sizeof(nic_t)); + dev = alloc_etherdev(sizeof(struct s2io_nic)); if (dev == NULL) { DBG_PRINT(ERR_DBG, "Device allocation failed\n"); pci_disable_device(pdev); @@ -6829,7 +6797,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Private member variable initialized to s2io NIC structure */ sp = dev->priv; - memset(sp, 0, sizeof(nic_t)); + memset(sp, 0, sizeof(struct s2io_nic)); sp->dev = dev; sp->pdev = pdev; sp->high_dma_flag = dma_flag; @@ -6925,7 +6893,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->bar0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); if (!sp->bar0) { - DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem1\n", + DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n", dev->name); ret = -ENOMEM; goto bar0_remap_failed; @@ -6934,7 +6902,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->bar1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); if (!sp->bar1) { - DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem2\n", + DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n", dev->name); ret = -ENOMEM; goto bar1_remap_failed; @@ -6945,7 +6913,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Initializing the BAR1 address as the start of the FIFO pointer. */ for (j = 0; j < MAX_TX_FIFOS; j++) { - mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *) + mac_control->tx_FIFO_start[j] = (struct TxFIFO_element __iomem *) (sp->bar1 + (j * 0x00020000)); } @@ -6966,10 +6934,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) * will use eth_mac_addr() for dev->set_mac_address * mac address will be set every time dev->open() is called */ -#if defined(CONFIG_S2IO_NAPI) dev->poll = s2io_poll; dev->weight = 32; -#endif #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = s2io_netpoll; @@ -6978,13 +6944,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; if (sp->high_dma_flag == TRUE) dev->features |= NETIF_F_HIGHDMA; -#ifdef NETIF_F_TSO dev->features |= NETIF_F_TSO; -#endif -#ifdef NETIF_F_TSO6 dev->features |= NETIF_F_TSO6; -#endif - if (sp->device_type & XFRAME_II_DEVICE) { + if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) { dev->features |= NETIF_F_UFO; dev->features |= NETIF_F_HW_CSUM; } @@ -7065,9 +7027,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) /* Initialize spinlocks */ spin_lock_init(&sp->tx_lock); -#ifndef CONFIG_S2IO_NAPI - spin_lock_init(&sp->put_lock); -#endif + + if (!napi) + spin_lock_init(&sp->put_lock); spin_lock_init(&sp->rx_lock); /* @@ -7098,13 +7060,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, s2io_driver_version); DBG_PRINT(ERR_DBG, "%s: MAC ADDR: " - "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, + "%02x:%02x:%02x:%02x:%02x:%02x", dev->name, sp->def_mac_addr[0].mac_addr[0], sp->def_mac_addr[0].mac_addr[1], sp->def_mac_addr[0].mac_addr[2], sp->def_mac_addr[0].mac_addr[3], sp->def_mac_addr[0].mac_addr[4], sp->def_mac_addr[0].mac_addr[5]); + DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num); if (sp->device_type & XFRAME_II_DEVICE) { mode = s2io_print_pci_mode(sp); if (mode < 0) { @@ -7128,9 +7091,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->name); break; } -#ifdef CONFIG_S2IO_NAPI - DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name); -#endif + + if (napi) + DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name); switch(sp->intr_type) { case INTA: DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name); @@ -7145,7 +7108,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (sp->lro) DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n", dev->name); - + if (ufo) + DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)" + " enabled\n", dev->name); /* Initialize device name */ sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name); @@ -7202,7 +7167,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) { struct net_device *dev = (struct net_device *) pci_get_drvdata(pdev); - nic_t *sp; + struct s2io_nic *sp; if (dev == NULL) { DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n"); @@ -7215,7 +7180,6 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) free_shared_mem(sp); iounmap(sp->bar0); iounmap(sp->bar1); - pci_disable_device(pdev); if (sp->intr_type != MSI_X) pci_release_regions(pdev); else { @@ -7226,6 +7190,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) } pci_set_drvdata(pdev, NULL); free_netdev(dev); + pci_disable_device(pdev); } /** @@ -7244,7 +7209,7 @@ int __init s2io_starter(void) * Description: This function is the cleanup routine for the driver. It unregist * ers the driver. */ -static void s2io_closer(void) +static __exit void s2io_closer(void) { pci_unregister_driver(&s2io_driver); DBG_PRINT(INIT_DBG, "cleanup done\n"); @@ -7254,7 +7219,7 @@ module_init(s2io_starter); module_exit(s2io_closer); static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, - struct tcphdr **tcp, RxD_t *rxdp) + struct tcphdr **tcp, struct RxD_t *rxdp) { int ip_off; u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len; @@ -7288,7 +7253,7 @@ static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, return 0; } -static int check_for_socket_match(lro_t *lro, struct iphdr *ip, +static int check_for_socket_match(struct lro *lro, struct iphdr *ip, struct tcphdr *tcp) { DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); @@ -7303,7 +7268,7 @@ static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp) return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2)); } -static void initiate_new_session(lro_t *lro, u8 *l2h, +static void initiate_new_session(struct lro *lro, u8 *l2h, struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len) { DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); @@ -7329,12 +7294,12 @@ static void initiate_new_session(lro_t *lro, u8 *l2h, lro->in_use = 1; } -static void update_L3L4_header(nic_t *sp, lro_t *lro) +static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) { struct iphdr *ip = lro->iph; struct tcphdr *tcp = lro->tcph; u16 nchk; - StatInfo_t *statinfo = sp->mac_control.stats_info; + struct stat_block *statinfo = sp->mac_control.stats_info; DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); /* Update L3 header */ @@ -7360,7 +7325,7 @@ static void update_L3L4_header(nic_t *sp, lro_t *lro) statinfo->sw_stat.num_aggregations++; } -static void aggregate_new_rx(lro_t *lro, struct iphdr *ip, +static void aggregate_new_rx(struct lro *lro, struct iphdr *ip, struct tcphdr *tcp, u32 l4_pyld) { DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); @@ -7382,7 +7347,7 @@ static void aggregate_new_rx(lro_t *lro, struct iphdr *ip, } } -static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip, +static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len) { u8 *ptr; @@ -7440,8 +7405,8 @@ static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip, } static int -s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, - RxD_t *rxdp, nic_t *sp) +s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro, + struct RxD_t *rxdp, struct s2io_nic *sp) { struct iphdr *ip; struct tcphdr *tcph; @@ -7458,7 +7423,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, tcph = (struct tcphdr *)*tcp; *tcp_len = get_l4_pyld_length(ip, tcph); for (i=0; ilro0_n[i]; + struct lro *l_lro = &sp->lro0_n[i]; if (l_lro->in_use) { if (check_for_socket_match(l_lro, ip, tcph)) continue; @@ -7496,7 +7461,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, } for (i=0; ilro0_n[i]; + struct lro *l_lro = &sp->lro0_n[i]; if (!(l_lro->in_use)) { *lro = l_lro; ret = 3; /* Begin anew */ @@ -7535,9 +7500,9 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, return ret; } -static void clear_lro_session(lro_t *lro) +static void clear_lro_session(struct lro *lro) { - static u16 lro_struct_size = sizeof(lro_t); + static u16 lro_struct_size = sizeof(struct lro); memset(lro, 0, lro_struct_size); } @@ -7547,14 +7512,14 @@ static void queue_rx_frame(struct sk_buff *skb) struct net_device *dev = skb->dev; skb->protocol = eth_type_trans(skb, dev); -#ifdef CONFIG_S2IO_NAPI - netif_receive_skb(skb); -#else - netif_rx(skb); -#endif + if (napi) + netif_receive_skb(skb); + else + netif_rx(skb); } -static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, +static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, + struct sk_buff *skb, u32 tcp_len) { struct sk_buff *first = lro->parent; @@ -7566,6 +7531,7 @@ static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, lro->last_frag->next = skb; else skb_shinfo(first)->frag_list = skb; + first->truesize += skb->truesize; lro->last_frag = skb; sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++; return; diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 3b0bafd273c8..a5e1a513deb5 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -30,6 +30,8 @@ #undef SUCCESS #define SUCCESS 0 #define FAILURE -1 +#define S2IO_MINUS_ONE 0xFFFFFFFFFFFFFFFFULL +#define S2IO_MAX_PCI_CONFIG_SPACE_REINIT 100 #define CHECKBIT(value, nbit) (value & (1 << nbit)) @@ -37,7 +39,7 @@ #define MAX_FLICKER_TIME 60000 /* 60 Secs */ /* Maximum outstanding splits to be configured into xena. */ -typedef enum xena_max_outstanding_splits { +enum { XENA_ONE_SPLIT_TRANSACTION = 0, XENA_TWO_SPLIT_TRANSACTION = 1, XENA_THREE_SPLIT_TRANSACTION = 2, @@ -46,7 +48,7 @@ typedef enum xena_max_outstanding_splits { XENA_TWELVE_SPLIT_TRANSACTION = 5, XENA_SIXTEEN_SPLIT_TRANSACTION = 6, XENA_THIRTYTWO_SPLIT_TRANSACTION = 7 -} xena_max_outstanding_splits; +}; #define XENA_MAX_OUTSTANDING_SPLITS(n) (n << 4) /* OS concerned variables and constants */ @@ -77,7 +79,7 @@ static int debug_level = ERR_DBG; #define S2IO_JUMBO_SIZE 9600 /* Driver statistics maintained by driver */ -typedef struct { +struct swStat { unsigned long long single_ecc_errs; unsigned long long double_ecc_errs; unsigned long long parity_err_cnt; @@ -92,10 +94,10 @@ typedef struct { unsigned long long flush_max_pkts; unsigned long long sum_avg_pkts_aggregated; unsigned long long num_aggregations; -} swStat_t; +}; /* Xpak releated alarm and warnings */ -typedef struct { +struct xpakStat { u64 alarm_transceiver_temp_high; u64 alarm_transceiver_temp_low; u64 alarm_laser_bias_current_high; @@ -110,11 +112,11 @@ typedef struct { u64 warn_laser_output_power_low; u64 xpak_regs_stat; u32 xpak_timer_count; -} xpakStat_t; +}; /* The statistics block of Xena */ -typedef struct stat_block { +struct stat_block { /* Tx MAC statistics counters. */ __le32 tmac_data_octets; __le32 tmac_frms; @@ -290,9 +292,9 @@ typedef struct stat_block { __le32 reserved_14; __le32 link_fault_cnt; u8 buffer[20]; - swStat_t sw_stat; - xpakStat_t xpak_stat; -} StatInfo_t; + struct swStat sw_stat; + struct xpakStat xpak_stat; +}; /* * Structures representing different init time configuration @@ -315,7 +317,7 @@ static int fifo_map[][MAX_TX_FIFOS] = { }; /* Maintains Per FIFO related information. */ -typedef struct tx_fifo_config { +struct tx_fifo_config { #define MAX_AVAILABLE_TXDS 8192 u32 fifo_len; /* specifies len of FIFO upto 8192, ie no of TxDLs */ /* Priority definition */ @@ -332,11 +334,11 @@ typedef struct tx_fifo_config { u8 f_no_snoop; #define NO_SNOOP_TXD 0x01 #define NO_SNOOP_TXD_BUFFER 0x02 -} tx_fifo_config_t; +}; /* Maintains per Ring related information */ -typedef struct rx_ring_config { +struct rx_ring_config { u32 num_rxd; /*No of RxDs per Rx Ring */ #define RX_RING_PRI_0 0 /* highest */ #define RX_RING_PRI_1 1 @@ -357,7 +359,7 @@ typedef struct rx_ring_config { u8 f_no_snoop; #define NO_SNOOP_RXD 0x01 #define NO_SNOOP_RXD_BUFFER 0x02 -} rx_ring_config_t; +}; /* This structure provides contains values of the tunable parameters * of the H/W @@ -367,7 +369,7 @@ struct config_param { u32 tx_fifo_num; /*Number of Tx FIFOs */ u8 fifo_mapping[MAX_TX_FIFOS]; - tx_fifo_config_t tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */ + struct tx_fifo_config tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */ u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */ u64 tx_intr_type; /* Specifies if Tx Intr is UTILZ or PER_LIST type. */ @@ -376,7 +378,7 @@ struct config_param { u32 rx_ring_num; /*Number of receive rings */ #define MAX_RX_BLOCKS_PER_RING 150 - rx_ring_config_t rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */ + struct rx_ring_config rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */ u8 bimodal; /*Flag for setting bimodal interrupts*/ #define HEADER_ETHERNET_II_802_3_SIZE 14 @@ -395,14 +397,14 @@ struct config_param { }; /* Structure representing MAC Addrs */ -typedef struct mac_addr { +struct mac_addr { u8 mac_addr[ETH_ALEN]; -} macaddr_t; +}; /* Structure that represent every FIFO element in the BAR1 * Address location. */ -typedef struct _TxFIFO_element { +struct TxFIFO_element { u64 TxDL_Pointer; u64 List_Control; @@ -413,10 +415,10 @@ typedef struct _TxFIFO_element { #define TX_FIFO_SPECIAL_FUNC BIT(23) #define TX_FIFO_DS_NO_SNOOP BIT(31) #define TX_FIFO_BUFF_NO_SNOOP BIT(30) -} TxFIFO_element_t; +}; /* Tx descriptor structure */ -typedef struct _TxD { +struct TxD { u64 Control_1; /* bit mask */ #define TXD_LIST_OWN_XENA BIT(7) @@ -447,16 +449,16 @@ typedef struct _TxD { u64 Buffer_Pointer; u64 Host_Control; /* reserved for host */ -} TxD_t; +}; /* Structure to hold the phy and virt addr of every TxDL. */ -typedef struct list_info_hold { +struct list_info_hold { dma_addr_t list_phy_addr; void *list_virt_addr; -} list_info_hold_t; +}; /* Rx descriptor structure for 1 buffer mode */ -typedef struct _RxD_t { +struct RxD_t { u64 Host_Control; /* reserved for host */ u64 Control_1; #define RXD_OWN_XENA BIT(7) @@ -481,21 +483,21 @@ typedef struct _RxD_t { #define SET_NUM_TAG(val) vBIT(val,16,32) -} RxD_t; +}; /* Rx descriptor structure for 1 buffer mode */ -typedef struct _RxD1_t { - struct _RxD_t h; +struct RxD1 { + struct RxD_t h; #define MASK_BUFFER0_SIZE_1 vBIT(0x3FFF,2,14) #define SET_BUFFER0_SIZE_1(val) vBIT(val,2,14) #define RXD_GET_BUFFER0_SIZE_1(_Control_2) \ (u16)((_Control_2 & MASK_BUFFER0_SIZE_1) >> 48) u64 Buffer0_ptr; -} RxD1_t; +}; /* Rx descriptor structure for 3 or 2 buffer mode */ -typedef struct _RxD3_t { - struct _RxD_t h; +struct RxD3 { + struct RxD_t h; #define MASK_BUFFER0_SIZE_3 vBIT(0xFF,2,14) #define MASK_BUFFER1_SIZE_3 vBIT(0xFFFF,16,16) @@ -515,15 +517,15 @@ typedef struct _RxD3_t { u64 Buffer0_ptr; u64 Buffer1_ptr; u64 Buffer2_ptr; -} RxD3_t; +}; /* Structure that represents the Rx descriptor block which contains * 128 Rx descriptors. */ -typedef struct _RxD_block { +struct RxD_block { #define MAX_RXDS_PER_BLOCK_1 127 - RxD1_t rxd[MAX_RXDS_PER_BLOCK_1]; + struct RxD1 rxd[MAX_RXDS_PER_BLOCK_1]; u64 reserved_0; #define END_OF_BLOCK 0xFEFFFFFFFFFFFFFFULL @@ -533,22 +535,22 @@ typedef struct _RxD_block { u64 pNext_RxD_Blk_physical; /* Buff0_ptr.In a 32 bit arch * the upper 32 bits should * be 0 */ -} RxD_block_t; +}; #define SIZE_OF_BLOCK 4096 -#define RXD_MODE_1 0 -#define RXD_MODE_3A 1 -#define RXD_MODE_3B 2 +#define RXD_MODE_1 0 /* One Buffer mode */ +#define RXD_MODE_3A 1 /* Three Buffer mode */ +#define RXD_MODE_3B 2 /* Two Buffer mode */ /* Structure to hold virtual addresses of Buf0 and Buf1 in * 2buf mode. */ -typedef struct bufAdd { +struct buffAdd { void *ba_0_org; void *ba_1_org; void *ba_0; void *ba_1; -} buffAdd_t; +}; /* Structure which stores all the MAC control parameters */ @@ -556,43 +558,46 @@ typedef struct bufAdd { * from which the Rx Interrupt processor can start picking * up the RxDs for processing. */ -typedef struct _rx_curr_get_info_t { +struct rx_curr_get_info { u32 block_index; u32 offset; u32 ring_len; -} rx_curr_get_info_t; +}; -typedef rx_curr_get_info_t rx_curr_put_info_t; +struct rx_curr_put_info { + u32 block_index; + u32 offset; + u32 ring_len; +}; /* This structure stores the offset of the TxDl in the FIFO * from which the Tx Interrupt processor can start picking * up the TxDLs for send complete interrupt processing. */ -typedef struct { +struct tx_curr_get_info { u32 offset; u32 fifo_len; -} tx_curr_get_info_t; +}; -typedef tx_curr_get_info_t tx_curr_put_info_t; +struct tx_curr_put_info { + u32 offset; + u32 fifo_len; +}; - -typedef struct rxd_info { +struct rxd_info { void *virt_addr; dma_addr_t dma_addr; -}rxd_info_t; +}; /* Structure that holds the Phy and virt addresses of the Blocks */ -typedef struct rx_block_info { +struct rx_block_info { void *block_virt_addr; dma_addr_t block_dma_addr; - rxd_info_t *rxds; -} rx_block_info_t; - -/* pre declaration of the nic structure */ -typedef struct s2io_nic nic_t; + struct rxd_info *rxds; +}; /* Ring specific structure */ -typedef struct ring_info { +struct ring_info { /* The ring number */ int ring_no; @@ -600,7 +605,7 @@ typedef struct ring_info { * Place holders for the virtual and physical addresses of * all the Rx Blocks */ - rx_block_info_t rx_blocks[MAX_RX_BLOCKS_PER_RING]; + struct rx_block_info rx_blocks[MAX_RX_BLOCKS_PER_RING]; int block_count; int pkt_cnt; @@ -608,26 +613,24 @@ typedef struct ring_info { * Put pointer info which indictes which RxD has to be replenished * with a new buffer. */ - rx_curr_put_info_t rx_curr_put_info; + struct rx_curr_put_info rx_curr_put_info; /* * Get pointer info which indictes which is the last RxD that was * processed by the driver. */ - rx_curr_get_info_t rx_curr_get_info; + struct rx_curr_get_info rx_curr_get_info; -#ifndef CONFIG_S2IO_NAPI /* Index to the absolute position of the put pointer of Rx ring */ int put_pos; -#endif /* Buffer Address store. */ - buffAdd_t **ba; - nic_t *nic; -} ring_info_t; + struct buffAdd **ba; + struct s2io_nic *nic; +}; /* Fifo specific structure */ -typedef struct fifo_info { +struct fifo_info { /* FIFO number */ int fifo_no; @@ -635,40 +638,40 @@ typedef struct fifo_info { int max_txds; /* Place holder of all the TX List's Phy and Virt addresses. */ - list_info_hold_t *list_info; + struct list_info_hold *list_info; /* * Current offset within the tx FIFO where driver would write * new Tx frame */ - tx_curr_put_info_t tx_curr_put_info; + struct tx_curr_put_info tx_curr_put_info; /* * Current offset within tx FIFO from where the driver would start freeing * the buffers */ - tx_curr_get_info_t tx_curr_get_info; + struct tx_curr_get_info tx_curr_get_info; - nic_t *nic; -}fifo_info_t; + struct s2io_nic *nic; +}; /* Information related to the Tx and Rx FIFOs and Rings of Xena * is maintained in this structure. */ -typedef struct mac_info { +struct mac_info { /* tx side stuff */ /* logical pointer of start of each Tx FIFO */ - TxFIFO_element_t __iomem *tx_FIFO_start[MAX_TX_FIFOS]; + struct TxFIFO_element __iomem *tx_FIFO_start[MAX_TX_FIFOS]; /* Fifo specific structure */ - fifo_info_t fifos[MAX_TX_FIFOS]; + struct fifo_info fifos[MAX_TX_FIFOS]; /* Save virtual address of TxD page with zero DMA addr(if any) */ void *zerodma_virt_addr; /* rx side stuff */ /* Ring specific structure */ - ring_info_t rings[MAX_RX_RINGS]; + struct ring_info rings[MAX_RX_RINGS]; u16 rmac_pause_time; u16 mc_pause_threshold_q0q3; @@ -677,14 +680,14 @@ typedef struct mac_info { void *stats_mem; /* orignal pointer to allocated mem */ dma_addr_t stats_mem_phy; /* Physical address of the stat block */ u32 stats_mem_sz; - StatInfo_t *stats_info; /* Logical address of the stat block */ -} mac_info_t; + struct stat_block *stats_info; /* Logical address of the stat block */ +}; /* structure representing the user defined MAC addresses */ -typedef struct { +struct usr_addr { char addr[ETH_ALEN]; int usage_cnt; -} usr_addr_t; +}; /* Default Tunable parameters of the NIC. */ #define DEFAULT_FIFO_0_LEN 4096 @@ -717,7 +720,7 @@ struct msix_info_st { }; /* Data structure to represent a LRO session */ -typedef struct lro { +struct lro { struct sk_buff *parent; struct sk_buff *last_frag; u8 *l2h; @@ -733,20 +736,18 @@ typedef struct lro { u32 cur_tsval; u32 cur_tsecr; u8 saw_ts; -}lro_t; +}; /* Structure representing one instance of the NIC */ struct s2io_nic { int rxd_mode; -#ifdef CONFIG_S2IO_NAPI /* * Count of packets to be processed in a given iteration, it will be indicated * by the quota field of the device structure when NAPI is enabled. */ int pkts_to_process; -#endif struct net_device *dev; - mac_info_t mac_control; + struct mac_info mac_control; struct config_param config; struct pci_dev *pdev; void __iomem *bar0; @@ -754,8 +755,8 @@ struct s2io_nic { #define MAX_MAC_SUPPORTED 16 #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED - macaddr_t def_mac_addr[MAX_MAC_SUPPORTED]; - macaddr_t pre_mac_addr[MAX_MAC_SUPPORTED]; + struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED]; + struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED]; struct net_device_stats stats; int high_dma_flag; @@ -775,9 +776,7 @@ struct s2io_nic { atomic_t rx_bufs_left[MAX_RX_RINGS]; spinlock_t tx_lock; -#ifndef CONFIG_S2IO_NAPI spinlock_t put_lock; -#endif #define PROMISC 1 #define ALL_MULTI 2 @@ -785,7 +784,7 @@ struct s2io_nic { #define MAX_ADDRS_SUPPORTED 64 u16 usr_addr_count; u16 mc_addr_count; - usr_addr_t usr_addrs[MAX_ADDRS_SUPPORTED]; + struct usr_addr usr_addrs[MAX_ADDRS_SUPPORTED]; u16 m_cast_flg; u16 all_multi_pos; @@ -841,7 +840,7 @@ struct s2io_nic { u8 device_type; #define MAX_LRO_SESSIONS 32 - lro_t lro0_n[MAX_LRO_SESSIONS]; + struct lro lro0_n[MAX_LRO_SESSIONS]; unsigned long clubbed_frms_cnt; unsigned long sending_both; u8 lro; @@ -855,8 +854,9 @@ struct s2io_nic { spinlock_t rx_lock; atomic_t isr_cnt; u64 *ufo_in_band_v; -#define VPD_PRODUCT_NAME_LEN 50 - u8 product_name[VPD_PRODUCT_NAME_LEN]; +#define VPD_STRING_LEN 80 + u8 product_name[VPD_STRING_LEN]; + u8 serial_num[VPD_STRING_LEN]; }; #define RESET_ERROR 1; @@ -975,43 +975,50 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev); static int init_shared_mem(struct s2io_nic *sp); static void free_shared_mem(struct s2io_nic *sp); static int init_nic(struct s2io_nic *nic); -static void rx_intr_handler(ring_info_t *ring_data); -static void tx_intr_handler(fifo_info_t *fifo_data); +static void rx_intr_handler(struct ring_info *ring_data); +static void tx_intr_handler(struct fifo_info *fifo_data); static void alarm_intr_handler(struct s2io_nic *sp); static int s2io_starter(void); +static void s2io_closer(void); static void s2io_tx_watchdog(struct net_device *dev); static void s2io_tasklet(unsigned long dev_addr); static void s2io_set_multicast(struct net_device *dev); -static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp); -static void s2io_link(nic_t * sp, int link); -#if defined(CONFIG_S2IO_NAPI) +static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp); +static void s2io_link(struct s2io_nic * sp, int link); +static void s2io_reset(struct s2io_nic * sp); static int s2io_poll(struct net_device *dev, int *budget); -#endif -static void s2io_init_pci(nic_t * sp); +static void s2io_init_pci(struct s2io_nic * sp); static int s2io_set_mac_addr(struct net_device *dev, u8 * addr); static void s2io_alarm_handle(unsigned long data); -static int s2io_enable_msi(nic_t *nic); +static int s2io_enable_msi(struct s2io_nic *nic); static irqreturn_t s2io_msi_handle(int irq, void *dev_id); static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id); static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id); static irqreturn_t s2io_isr(int irq, void *dev_id); -static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag); +static int verify_xena_quiescence(struct s2io_nic *sp); static const struct ethtool_ops netdev_ethtool_ops; static void s2io_set_link(struct work_struct *work); -static int s2io_set_swapper(nic_t * sp); -static void s2io_card_down(nic_t *nic); -static int s2io_card_up(nic_t *nic); +static int s2io_set_swapper(struct s2io_nic * sp); +static void s2io_card_down(struct s2io_nic *nic); +static int s2io_card_up(struct s2io_nic *nic); static int get_xena_rev_id(struct pci_dev *pdev); -static void restore_xmsi_data(nic_t *nic); +static int wait_for_cmd_complete(void *addr, u64 busy_bit); +static int s2io_add_isr(struct s2io_nic * sp); +static void s2io_rem_isr(struct s2io_nic * sp); -static int s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, RxD_t *rxdp, nic_t *sp); -static void clear_lro_session(lro_t *lro); +static void restore_xmsi_data(struct s2io_nic *nic); + +static int +s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro, + struct RxD_t *rxdp, struct s2io_nic *sp); +static void clear_lro_session(struct lro *lro); static void queue_rx_frame(struct sk_buff *skb); -static void update_L3L4_header(nic_t *sp, lro_t *lro); -static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 tcp_len); +static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro); +static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, + struct sk_buff *skb, u32 tcp_len); #define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size #define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c new file mode 100644 index 000000000000..7f800feaa9a2 --- /dev/null +++ b/drivers/net/sc92031.c @@ -0,0 +1,1620 @@ +/* Silan SC92031 PCI Fast Ethernet Adapter driver + * + * Based on vendor drivers: + * Silan Fast Ethernet Netcard Driver: + * MODULE_AUTHOR ("gaoyonghong"); + * MODULE_DESCRIPTION ("SILAN Fast Ethernet driver"); + * MODULE_LICENSE("GPL"); + * 8139D Fast Ethernet driver: + * (C) 2002 by gaoyonghong + * MODULE_AUTHOR ("gaoyonghong"); + * MODULE_DESCRIPTION ("Rsltek 8139D PCI Fast Ethernet Adapter driver"); + * MODULE_LICENSE("GPL"); + * Both are almost identical and seem to be based on pci-skeleton.c + * + * Rewritten for 2.6 by Cesar Eduardo Barros + */ + +/* Note about set_mac_address: I don't know how to change the hardware + * matching, so you need to enable IFF_PROMISC when using it. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PCI_VENDOR_ID_SILAN 0x1904 +#define PCI_DEVICE_ID_SILAN_SC92031 0x2031 +#define PCI_DEVICE_ID_SILAN_8139D 0x8139 + +#define SC92031_NAME "sc92031" +#define SC92031_DESCRIPTION "Silan SC92031 PCI Fast Ethernet Adapter driver" +#define SC92031_VERSION "2.0c" + +/* BAR 0 is MMIO, BAR 1 is PIO */ +#ifndef SC92031_USE_BAR +#define SC92031_USE_BAR 0 +#endif + +/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */ +static int multicast_filter_limit = 64; +module_param(multicast_filter_limit, int, 0); +MODULE_PARM_DESC(multicast_filter_limit, + "Maximum number of filtered multicast addresses"); + +static int media; +module_param(media, int, 0); +MODULE_PARM_DESC(media, "Media type (0x00 = autodetect," + " 0x01 = 10M half, 0x02 = 10M full," + " 0x04 = 100M half, 0x08 = 100M full)"); + +/* Size of the in-memory receive ring. */ +#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K ,4==128K*/ +#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) + +/* Number of Tx descriptor registers. */ +#define NUM_TX_DESC 4 + +/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/ +#define MAX_ETH_FRAME_SIZE 1536 + +/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ +#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE +#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC) + +/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */ +#define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */ + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*HZ) + +#define SILAN_STATS_NUM 2 /* number of ETHTOOL_GSTATS */ + +/* media options */ +#define AUTOSELECT 0x00 +#define M10_HALF 0x01 +#define M10_FULL 0x02 +#define M100_HALF 0x04 +#define M100_FULL 0x08 + + /* Symbolic offsets to registers. */ +enum silan_registers { + Config0 = 0x00, // Config0 + Config1 = 0x04, // Config1 + RxBufWPtr = 0x08, // Rx buffer writer poiter + IntrStatus = 0x0C, // Interrupt status + IntrMask = 0x10, // Interrupt mask + RxbufAddr = 0x14, // Rx buffer start address + RxBufRPtr = 0x18, // Rx buffer read pointer + Txstatusall = 0x1C, // Transmit status of all descriptors + TxStatus0 = 0x20, // Transmit status (Four 32bit registers). + TxAddr0 = 0x30, // Tx descriptors (also four 32bit). + RxConfig = 0x40, // Rx configuration + MAC0 = 0x44, // Ethernet hardware address. + MAR0 = 0x4C, // Multicast filter. + RxStatus0 = 0x54, // Rx status + TxConfig = 0x5C, // Tx configuration + PhyCtrl = 0x60, // physical control + FlowCtrlConfig = 0x64, // flow control + Miicmd0 = 0x68, // Mii command0 register + Miicmd1 = 0x6C, // Mii command1 register + Miistatus = 0x70, // Mii status register + Timercnt = 0x74, // Timer counter register + TimerIntr = 0x78, // Timer interrupt register + PMConfig = 0x7C, // Power Manager configuration + CRC0 = 0x80, // Power Manager CRC ( Two 32bit regisers) + Wakeup0 = 0x88, // power Manager wakeup( Eight 64bit regiser) + LSBCRC0 = 0xC8, // power Manager LSBCRC(Two 32bit regiser) + TestD0 = 0xD0, + TestD4 = 0xD4, + TestD8 = 0xD8, +}; + +#define MII_BMCR 0 // Basic mode control register +#define MII_BMSR 1 // Basic mode status register +#define MII_JAB 16 +#define MII_OutputStatus 24 + +#define BMCR_FULLDPLX 0x0100 // Full duplex +#define BMCR_ANRESTART 0x0200 // Auto negotiation restart +#define BMCR_ANENABLE 0x1000 // Enable auto negotiation +#define BMCR_SPEED100 0x2000 // Select 100Mbps +#define BMSR_LSTATUS 0x0004 // Link status +#define PHY_16_JAB_ENB 0x1000 +#define PHY_16_PORT_ENB 0x1 + +enum IntrStatusBits { + LinkFail = 0x80000000, + LinkOK = 0x40000000, + TimeOut = 0x20000000, + RxOverflow = 0x0040, + RxOK = 0x0020, + TxOK = 0x0001, + IntrBits = LinkFail|LinkOK|TimeOut|RxOverflow|RxOK|TxOK, +}; + +enum TxStatusBits { + TxCarrierLost = 0x20000000, + TxAborted = 0x10000000, + TxOutOfWindow = 0x08000000, + TxNccShift = 22, + EarlyTxThresShift = 16, + TxStatOK = 0x8000, + TxUnderrun = 0x4000, + TxOwn = 0x2000, +}; + +enum RxStatusBits { + RxStatesOK = 0x80000, + RxBadAlign = 0x40000, + RxHugeFrame = 0x20000, + RxSmallFrame = 0x10000, + RxCRCOK = 0x8000, + RxCrlFrame = 0x4000, + Rx_Broadcast = 0x2000, + Rx_Multicast = 0x1000, + RxAddrMatch = 0x0800, + MiiErr = 0x0400, +}; + +enum RxConfigBits { + RxFullDx = 0x80000000, + RxEnb = 0x40000000, + RxSmall = 0x20000000, + RxHuge = 0x10000000, + RxErr = 0x08000000, + RxAllphys = 0x04000000, + RxMulticast = 0x02000000, + RxBroadcast = 0x01000000, + RxLoopBack = (1 << 23) | (1 << 22), + LowThresholdShift = 12, + HighThresholdShift = 2, +}; + +enum TxConfigBits { + TxFullDx = 0x80000000, + TxEnb = 0x40000000, + TxEnbPad = 0x20000000, + TxEnbHuge = 0x10000000, + TxEnbFCS = 0x08000000, + TxNoBackOff = 0x04000000, + TxEnbPrem = 0x02000000, + TxCareLostCrs = 0x1000000, + TxExdCollNum = 0xf00000, + TxDataRate = 0x80000, +}; + +enum PhyCtrlconfigbits { + PhyCtrlAne = 0x80000000, + PhyCtrlSpd100 = 0x40000000, + PhyCtrlSpd10 = 0x20000000, + PhyCtrlPhyBaseAddr = 0x1f000000, + PhyCtrlDux = 0x800000, + PhyCtrlReset = 0x400000, +}; + +enum FlowCtrlConfigBits { + FlowCtrlFullDX = 0x80000000, + FlowCtrlEnb = 0x40000000, +}; + +enum Config0Bits { + Cfg0_Reset = 0x80000000, + Cfg0_Anaoff = 0x40000000, + Cfg0_LDPS = 0x20000000, +}; + +enum Config1Bits { + Cfg1_EarlyRx = 1 << 31, + Cfg1_EarlyTx = 1 << 30, + + //rx buffer size + Cfg1_Rcv8K = 0x0, + Cfg1_Rcv16K = 0x1, + Cfg1_Rcv32K = 0x3, + Cfg1_Rcv64K = 0x7, + Cfg1_Rcv128K = 0xf, +}; + +enum MiiCmd0Bits { + Mii_Divider = 0x20000000, + Mii_WRITE = 0x400000, + Mii_READ = 0x200000, + Mii_SCAN = 0x100000, + Mii_Tamod = 0x80000, + Mii_Drvmod = 0x40000, + Mii_mdc = 0x20000, + Mii_mdoen = 0x10000, + Mii_mdo = 0x8000, + Mii_mdi = 0x4000, +}; + +enum MiiStatusBits { + Mii_StatusBusy = 0x80000000, +}; + +enum PMConfigBits { + PM_Enable = 1 << 31, + PM_LongWF = 1 << 30, + PM_Magic = 1 << 29, + PM_LANWake = 1 << 28, + PM_LWPTN = (1 << 27 | 1<< 26), + PM_LinkUp = 1 << 25, + PM_WakeUp = 1 << 24, +}; + +/* Locking rules: + * priv->lock protects most of the fields of priv and most of the + * hardware registers. It does not have to protect against softirqs + * between sc92031_disable_interrupts and sc92031_enable_interrupts; + * it also does not need to be used in ->open and ->stop while the + * device interrupts are off. + * Not having to protect against softirqs is very useful due to heavy + * use of mdelay() at _sc92031_reset. + * Functions prefixed with _sc92031_ must be called with the lock held; + * functions prefixed with sc92031_ must be called without the lock held. + * Use mmiowb() before unlocking if the hardware was written to. + */ + +/* Locking rules for the interrupt: + * - the interrupt and the tasklet never run at the same time + * - neither run between sc92031_disable_interrupts and + * sc92031_enable_interrupt + */ + +struct sc92031_priv { + spinlock_t lock; + /* iomap.h cookie */ + void __iomem *port_base; + /* pci device structure */ + struct pci_dev *pdev; + /* tasklet */ + struct tasklet_struct tasklet; + + /* CPU address of rx ring */ + void *rx_ring; + /* PCI address of rx ring */ + dma_addr_t rx_ring_dma_addr; + /* PCI address of rx ring read pointer */ + dma_addr_t rx_ring_tail; + + /* tx ring write index */ + unsigned tx_head; + /* tx ring read index */ + unsigned tx_tail; + /* CPU address of tx bounce buffer */ + void *tx_bufs; + /* PCI address of tx bounce buffer */ + dma_addr_t tx_bufs_dma_addr; + + /* copies of some hardware registers */ + u32 intr_status; + atomic_t intr_mask; + u32 rx_config; + u32 tx_config; + u32 pm_config; + + /* copy of some flags from dev->flags */ + unsigned int mc_flags; + + /* for ETHTOOL_GSTATS */ + u64 tx_timeouts; + u64 rx_loss; + + /* for dev->get_stats */ + long rx_value; + struct net_device_stats stats; +}; + +/* I don't know which registers can be safely read; however, I can guess + * MAC0 is one of them. */ +static inline void _sc92031_dummy_read(void __iomem *port_base) +{ + ioread32(port_base + MAC0); +} + +static u32 _sc92031_mii_wait(void __iomem *port_base) +{ + u32 mii_status; + + do { + udelay(10); + mii_status = ioread32(port_base + Miistatus); + } while (mii_status & Mii_StatusBusy); + + return mii_status; +} + +static u32 _sc92031_mii_cmd(void __iomem *port_base, u32 cmd0, u32 cmd1) +{ + iowrite32(Mii_Divider, port_base + Miicmd0); + + _sc92031_mii_wait(port_base); + + iowrite32(cmd1, port_base + Miicmd1); + iowrite32(Mii_Divider | cmd0, port_base + Miicmd0); + + return _sc92031_mii_wait(port_base); +} + +static void _sc92031_mii_scan(void __iomem *port_base) +{ + _sc92031_mii_cmd(port_base, Mii_SCAN, 0x1 << 6); +} + +static u16 _sc92031_mii_read(void __iomem *port_base, unsigned reg) +{ + return _sc92031_mii_cmd(port_base, Mii_READ, reg << 6) >> 13; +} + +static void _sc92031_mii_write(void __iomem *port_base, unsigned reg, u16 val) +{ + _sc92031_mii_cmd(port_base, Mii_WRITE, (reg << 6) | ((u32)val << 11)); +} + +static void sc92031_disable_interrupts(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + /* tell the tasklet/interrupt not to enable interrupts */ + atomic_set(&priv->intr_mask, 0); + wmb(); + + /* stop interrupts */ + iowrite32(0, port_base + IntrMask); + _sc92031_dummy_read(port_base); + mmiowb(); + + /* wait for any concurrent interrupt/tasklet to finish */ + synchronize_irq(dev->irq); + tasklet_disable(&priv->tasklet); +} + +static void sc92031_enable_interrupts(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + tasklet_enable(&priv->tasklet); + + atomic_set(&priv->intr_mask, IntrBits); + wmb(); + + iowrite32(IntrBits, port_base + IntrMask); + mmiowb(); +} + +static void _sc92031_disable_tx_rx(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + priv->rx_config &= ~RxEnb; + priv->tx_config &= ~TxEnb; + iowrite32(priv->rx_config, port_base + RxConfig); + iowrite32(priv->tx_config, port_base + TxConfig); +} + +static void _sc92031_enable_tx_rx(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + priv->rx_config |= RxEnb; + priv->tx_config |= TxEnb; + iowrite32(priv->rx_config, port_base + RxConfig); + iowrite32(priv->tx_config, port_base + TxConfig); +} + +static void _sc92031_tx_clear(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + while (priv->tx_head - priv->tx_tail > 0) { + priv->tx_tail++; + priv->stats.tx_dropped++; + } + priv->tx_head = priv->tx_tail = 0; +} + +static void _sc92031_set_mar(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 mar0 = 0, mar1 = 0; + + if ((dev->flags & IFF_PROMISC) + || dev->mc_count > multicast_filter_limit + || (dev->flags & IFF_ALLMULTI)) + mar0 = mar1 = 0xffffffff; + else if (dev->flags & IFF_MULTICAST) { + struct dev_mc_list *mc_list; + + for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) { + u32 crc; + unsigned bit = 0; + + crc = ~ether_crc(ETH_ALEN, mc_list->dmi_addr); + crc >>= 24; + + if (crc & 0x01) bit |= 0x02; + if (crc & 0x02) bit |= 0x01; + if (crc & 0x10) bit |= 0x20; + if (crc & 0x20) bit |= 0x10; + if (crc & 0x40) bit |= 0x08; + if (crc & 0x80) bit |= 0x04; + + if (bit > 31) + mar0 |= 0x1 << (bit - 32); + else + mar1 |= 0x1 << bit; + } + } + + iowrite32(mar0, port_base + MAR0); + iowrite32(mar1, port_base + MAR0 + 4); +} + +static void _sc92031_set_rx_config(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + unsigned int old_mc_flags; + u32 rx_config_bits = 0; + + old_mc_flags = priv->mc_flags; + + if (dev->flags & IFF_PROMISC) + rx_config_bits |= RxSmall | RxHuge | RxErr | RxBroadcast + | RxMulticast | RxAllphys; + + if (dev->flags & (IFF_ALLMULTI | IFF_MULTICAST)) + rx_config_bits |= RxMulticast; + + if (dev->flags & IFF_BROADCAST) + rx_config_bits |= RxBroadcast; + + priv->rx_config &= ~(RxSmall | RxHuge | RxErr | RxBroadcast + | RxMulticast | RxAllphys); + priv->rx_config |= rx_config_bits; + + priv->mc_flags = dev->flags & (IFF_PROMISC | IFF_ALLMULTI + | IFF_MULTICAST | IFF_BROADCAST); + + if (netif_carrier_ok(dev) && priv->mc_flags != old_mc_flags) + iowrite32(priv->rx_config, port_base + RxConfig); +} + +static bool _sc92031_check_media(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u16 bmsr; + + bmsr = _sc92031_mii_read(port_base, MII_BMSR); + rmb(); + if (bmsr & BMSR_LSTATUS) { + bool speed_100, duplex_full; + u32 flow_ctrl_config = 0; + u16 output_status = _sc92031_mii_read(port_base, + MII_OutputStatus); + _sc92031_mii_scan(port_base); + + speed_100 = output_status & 0x2; + duplex_full = output_status & 0x4; + + /* Initial Tx/Rx configuration */ + priv->rx_config = (0x40 << LowThresholdShift) | (0x1c0 << HighThresholdShift); + priv->tx_config = 0x48800000; + + /* NOTE: vendor driver had dead code here to enable tx padding */ + + if (!speed_100) + priv->tx_config |= 0x80000; + + // configure rx mode + _sc92031_set_rx_config(dev); + + if (duplex_full) { + priv->rx_config |= RxFullDx; + priv->tx_config |= TxFullDx; + flow_ctrl_config = FlowCtrlFullDX | FlowCtrlEnb; + } else { + priv->rx_config &= ~RxFullDx; + priv->tx_config &= ~TxFullDx; + } + + _sc92031_set_mar(dev); + _sc92031_set_rx_config(dev); + _sc92031_enable_tx_rx(dev); + iowrite32(flow_ctrl_config, port_base + FlowCtrlConfig); + + netif_carrier_on(dev); + + if (printk_ratelimit()) + printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n", + dev->name, + speed_100 ? "100" : "10", + duplex_full ? "full" : "half"); + return true; + } else { + _sc92031_mii_scan(port_base); + + netif_carrier_off(dev); + + _sc92031_disable_tx_rx(dev); + + if (printk_ratelimit()) + printk(KERN_INFO "%s: link down\n", dev->name); + return false; + } +} + +static void _sc92031_phy_reset(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 phy_ctrl; + + phy_ctrl = ioread32(port_base + PhyCtrl); + phy_ctrl &= ~(PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10); + phy_ctrl |= PhyCtrlAne | PhyCtrlReset; + + switch (media) { + default: + case AUTOSELECT: + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10; + break; + case M10_HALF: + phy_ctrl |= PhyCtrlSpd10; + break; + case M10_FULL: + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd10; + break; + case M100_HALF: + phy_ctrl |= PhyCtrlSpd100; + break; + case M100_FULL: + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100; + break; + } + + iowrite32(phy_ctrl, port_base + PhyCtrl); + mdelay(10); + + phy_ctrl &= ~PhyCtrlReset; + iowrite32(phy_ctrl, port_base + PhyCtrl); + mdelay(1); + + _sc92031_mii_write(port_base, MII_JAB, + PHY_16_JAB_ENB | PHY_16_PORT_ENB); + _sc92031_mii_scan(port_base); + + netif_carrier_off(dev); + netif_stop_queue(dev); +} + +static void _sc92031_reset(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + /* disable PM */ + iowrite32(0, port_base + PMConfig); + + /* soft reset the chip */ + iowrite32(Cfg0_Reset, port_base + Config0); + mdelay(200); + + iowrite32(0, port_base + Config0); + mdelay(10); + + /* disable interrupts */ + iowrite32(0, port_base + IntrMask); + + /* clear multicast address */ + iowrite32(0, port_base + MAR0); + iowrite32(0, port_base + MAR0 + 4); + + /* init rx ring */ + iowrite32(priv->rx_ring_dma_addr, port_base + RxbufAddr); + priv->rx_ring_tail = priv->rx_ring_dma_addr; + + /* init tx ring */ + _sc92031_tx_clear(dev); + + /* clear old register values */ + priv->intr_status = 0; + atomic_set(&priv->intr_mask, 0); + priv->rx_config = 0; + priv->tx_config = 0; + priv->mc_flags = 0; + + /* configure rx buffer size */ + /* NOTE: vendor driver had dead code here to enable early tx/rx */ + iowrite32(Cfg1_Rcv64K, port_base + Config1); + + _sc92031_phy_reset(dev); + _sc92031_check_media(dev); + + /* calculate rx fifo overflow */ + priv->rx_value = 0; + + /* enable PM */ + iowrite32(priv->pm_config, port_base + PMConfig); + + /* clear intr register */ + ioread32(port_base + IntrStatus); +} + +static void _sc92031_tx_tasklet(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + unsigned old_tx_tail; + unsigned entry; + u32 tx_status; + + old_tx_tail = priv->tx_tail; + while (priv->tx_head - priv->tx_tail > 0) { + entry = priv->tx_tail % NUM_TX_DESC; + tx_status = ioread32(port_base + TxStatus0 + entry * 4); + + if (!(tx_status & (TxStatOK | TxUnderrun | TxAborted))) + break; + + priv->tx_tail++; + + if (tx_status & TxStatOK) { + priv->stats.tx_bytes += tx_status & 0x1fff; + priv->stats.tx_packets++; + /* Note: TxCarrierLost is always asserted at 100mbps. */ + priv->stats.collisions += (tx_status >> 22) & 0xf; + } + + if (tx_status & (TxOutOfWindow | TxAborted)) { + priv->stats.tx_errors++; + + if (tx_status & TxAborted) + priv->stats.tx_aborted_errors++; + + if (tx_status & TxCarrierLost) + priv->stats.tx_carrier_errors++; + + if (tx_status & TxOutOfWindow) + priv->stats.tx_window_errors++; + } + + if (tx_status & TxUnderrun) + priv->stats.tx_fifo_errors++; + } + + if (priv->tx_tail != old_tx_tail) + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); +} + +static void _sc92031_rx_tasklet_error(u32 rx_status, + struct sc92031_priv *priv, unsigned rx_size) +{ + if(rx_size > (MAX_ETH_FRAME_SIZE + 4) || rx_size < 16) { + priv->stats.rx_errors++; + priv->stats.rx_length_errors++; + } + + if (!(rx_status & RxStatesOK)) { + priv->stats.rx_errors++; + + if (rx_status & (RxHugeFrame | RxSmallFrame)) + priv->stats.rx_length_errors++; + + if (rx_status & RxBadAlign) + priv->stats.rx_frame_errors++; + + if (!(rx_status & RxCRCOK)) + priv->stats.rx_crc_errors++; + } else + priv->rx_loss++; +} + +static void _sc92031_rx_tasklet(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + dma_addr_t rx_ring_head; + unsigned rx_len; + unsigned rx_ring_offset; + void *rx_ring = priv->rx_ring; + + rx_ring_head = ioread32(port_base + RxBufWPtr); + rmb(); + + /* rx_ring_head is only 17 bits in the RxBufWPtr register. + * we need to change it to 32 bits physical address + */ + rx_ring_head &= (dma_addr_t)(RX_BUF_LEN - 1); + rx_ring_head |= priv->rx_ring_dma_addr & ~(dma_addr_t)(RX_BUF_LEN - 1); + if (rx_ring_head < priv->rx_ring_dma_addr) + rx_ring_head += RX_BUF_LEN; + + if (rx_ring_head >= priv->rx_ring_tail) + rx_len = rx_ring_head - priv->rx_ring_tail; + else + rx_len = RX_BUF_LEN - (priv->rx_ring_tail - rx_ring_head); + + if (!rx_len) + return; + + if (unlikely(rx_len > RX_BUF_LEN)) { + if (printk_ratelimit()) + printk(KERN_ERR "%s: rx packets length > rx buffer\n", + dev->name); + return; + } + + rx_ring_offset = (priv->rx_ring_tail - priv->rx_ring_dma_addr) % RX_BUF_LEN; + + while (rx_len) { + u32 rx_status; + unsigned rx_size, rx_size_align, pkt_size; + struct sk_buff *skb; + + rx_status = le32_to_cpup((__le32 *)(rx_ring + rx_ring_offset)); + rmb(); + + rx_size = rx_status >> 20; + rx_size_align = (rx_size + 3) & ~3; // for 4 bytes aligned + pkt_size = rx_size - 4; // Omit the four octet CRC from the length. + + rx_ring_offset = (rx_ring_offset + 4) % RX_BUF_LEN; + + if (unlikely(rx_status == 0 + || rx_size > (MAX_ETH_FRAME_SIZE + 4) + || rx_size < 16 + || !(rx_status & RxStatesOK))) { + _sc92031_rx_tasklet_error(rx_status, priv, rx_size); + break; + } + + if (unlikely(rx_size_align + 4 > rx_len)) { + if (printk_ratelimit()) + printk(KERN_ERR "%s: rx_len is too small\n", dev->name); + break; + } + + rx_len -= rx_size_align + 4; + + skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN); + if (unlikely(!skb)) { + if (printk_ratelimit()) + printk(KERN_ERR "%s: Couldn't allocate a skb_buff for a packet of size %u\n", + dev->name, pkt_size); + goto next; + } + + skb_reserve(skb, NET_IP_ALIGN); + + if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) { + memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset), + rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset); + memcpy(skb_put(skb, pkt_size - (RX_BUF_LEN - rx_ring_offset)), + rx_ring, pkt_size - (RX_BUF_LEN - rx_ring_offset)); + } else { + memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size); + } + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + dev->last_rx = jiffies; + netif_rx(skb); + + priv->stats.rx_bytes += pkt_size; + priv->stats.rx_packets++; + + if (rx_status & Rx_Multicast) + priv->stats.multicast++; + + next: + rx_ring_offset = (rx_ring_offset + rx_size_align) % RX_BUF_LEN; + } + mb(); + + priv->rx_ring_tail = rx_ring_head; + iowrite32(priv->rx_ring_tail, port_base + RxBufRPtr); +} + +static void _sc92031_link_tasklet(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + if (_sc92031_check_media(dev)) + netif_wake_queue(dev); + else { + netif_stop_queue(dev); + priv->stats.tx_carrier_errors++; + } +} + +static void sc92031_tasklet(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 intr_status, intr_mask; + + intr_status = priv->intr_status; + + spin_lock(&priv->lock); + + if (unlikely(!netif_running(dev))) + goto out; + + if (intr_status & TxOK) + _sc92031_tx_tasklet(dev); + + if (intr_status & RxOK) + _sc92031_rx_tasklet(dev); + + if (intr_status & RxOverflow) + priv->stats.rx_errors++; + + if (intr_status & TimeOut) { + priv->stats.rx_errors++; + priv->stats.rx_length_errors++; + } + + if (intr_status & (LinkFail | LinkOK)) + _sc92031_link_tasklet(dev); + +out: + intr_mask = atomic_read(&priv->intr_mask); + rmb(); + + iowrite32(intr_mask, port_base + IntrMask); + mmiowb(); + + spin_unlock(&priv->lock); +} + +static irqreturn_t sc92031_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 intr_status, intr_mask; + + /* mask interrupts before clearing IntrStatus */ + iowrite32(0, port_base + IntrMask); + _sc92031_dummy_read(port_base); + + intr_status = ioread32(port_base + IntrStatus); + if (unlikely(intr_status == 0xffffffff)) + return IRQ_NONE; // hardware has gone missing + + intr_status &= IntrBits; + if (!intr_status) + goto out_none; + + priv->intr_status = intr_status; + tasklet_schedule(&priv->tasklet); + + return IRQ_HANDLED; + +out_none: + intr_mask = atomic_read(&priv->intr_mask); + rmb(); + + iowrite32(intr_mask, port_base + IntrMask); + mmiowb(); + + return IRQ_NONE; +} + +static struct net_device_stats *sc92031_get_stats(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + // FIXME I do not understand what is this trying to do. + if (netif_running(dev)) { + int temp; + + spin_lock_bh(&priv->lock); + + /* Update the error count. */ + temp = (ioread32(port_base + RxStatus0) >> 16) & 0xffff; + + if (temp == 0xffff) { + priv->rx_value += temp; + priv->stats.rx_fifo_errors = priv->rx_value; + } else { + priv->stats.rx_fifo_errors = temp + priv->rx_value; + } + + spin_unlock_bh(&priv->lock); + } + + return &priv->stats; +} + +static int sc92031_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int err = 0; + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + unsigned len; + unsigned entry; + u32 tx_status; + + if (unlikely(skb->len > TX_BUF_SIZE)) { + err = -EMSGSIZE; + priv->stats.tx_dropped++; + goto out; + } + + spin_lock_bh(&priv->lock); + + if (unlikely(!netif_carrier_ok(dev))) { + err = -ENOLINK; + priv->stats.tx_dropped++; + goto out_unlock; + } + + BUG_ON(priv->tx_head - priv->tx_tail >= NUM_TX_DESC); + + entry = priv->tx_head++ % NUM_TX_DESC; + + skb_copy_and_csum_dev(skb, priv->tx_bufs + entry * TX_BUF_SIZE); + + len = skb->len; + if (unlikely(len < ETH_ZLEN)) { + memset(priv->tx_bufs + entry * TX_BUF_SIZE + len, + 0, ETH_ZLEN - len); + len = ETH_ZLEN; + } + + wmb(); + + if (len < 100) + tx_status = len; + else if (len < 300) + tx_status = 0x30000 | len; + else + tx_status = 0x50000 | len; + + iowrite32(priv->tx_bufs_dma_addr + entry * TX_BUF_SIZE, + port_base + TxAddr0 + entry * 4); + iowrite32(tx_status, port_base + TxStatus0 + entry * 4); + mmiowb(); + + dev->trans_start = jiffies; + + if (priv->tx_head - priv->tx_tail >= NUM_TX_DESC) + netif_stop_queue(dev); + +out_unlock: + spin_unlock_bh(&priv->lock); + +out: + dev_kfree_skb(skb); + + return err; +} + +static int sc92031_open(struct net_device *dev) +{ + int err; + struct sc92031_priv *priv = netdev_priv(dev); + struct pci_dev *pdev = priv->pdev; + + priv->rx_ring = pci_alloc_consistent(pdev, RX_BUF_LEN, + &priv->rx_ring_dma_addr); + if (unlikely(!priv->rx_ring)) { + err = -ENOMEM; + goto out_alloc_rx_ring; + } + + priv->tx_bufs = pci_alloc_consistent(pdev, TX_BUF_TOT_LEN, + &priv->tx_bufs_dma_addr); + if (unlikely(!priv->tx_bufs)) { + err = -ENOMEM; + goto out_alloc_tx_bufs; + } + priv->tx_head = priv->tx_tail = 0; + + err = request_irq(pdev->irq, sc92031_interrupt, + SA_SHIRQ, dev->name, dev); + if (unlikely(err < 0)) + goto out_request_irq; + + priv->pm_config = 0; + + /* Interrupts already disabled by sc92031_stop or sc92031_probe */ + spin_lock(&priv->lock); + + _sc92031_reset(dev); + mmiowb(); + + spin_unlock(&priv->lock); + sc92031_enable_interrupts(dev); + + if (netif_carrier_ok(dev)) + netif_start_queue(dev); + else + netif_tx_disable(dev); + + return 0; + +out_request_irq: + pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs, + priv->tx_bufs_dma_addr); +out_alloc_tx_bufs: + pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring, + priv->rx_ring_dma_addr); +out_alloc_rx_ring: + return err; +} + +static int sc92031_stop(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + struct pci_dev *pdev = priv->pdev; + + netif_tx_disable(dev); + + /* Disable interrupts, stop Tx and Rx. */ + sc92031_disable_interrupts(dev); + + spin_lock(&priv->lock); + + _sc92031_disable_tx_rx(dev); + _sc92031_tx_clear(dev); + mmiowb(); + + spin_unlock(&priv->lock); + + free_irq(pdev->irq, dev); + pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs, + priv->tx_bufs_dma_addr); + pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring, + priv->rx_ring_dma_addr); + + return 0; +} + +static void sc92031_set_multicast_list(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + spin_lock_bh(&priv->lock); + + _sc92031_set_mar(dev); + _sc92031_set_rx_config(dev); + mmiowb(); + + spin_unlock_bh(&priv->lock); +} + +static void sc92031_tx_timeout(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + /* Disable interrupts by clearing the interrupt mask.*/ + sc92031_disable_interrupts(dev); + + spin_lock(&priv->lock); + + priv->tx_timeouts++; + + _sc92031_reset(dev); + mmiowb(); + + spin_unlock(&priv->lock); + + /* enable interrupts */ + sc92031_enable_interrupts(dev); + + if (netif_carrier_ok(dev)) + netif_wake_queue(dev); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void sc92031_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + if (sc92031_interrupt(dev->irq, dev) != IRQ_NONE) + sc92031_tasklet((unsigned long)dev); + enable_irq(dev->irq); +} +#endif + +static int sc92031_ethtool_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u8 phy_address; + u32 phy_ctrl; + u16 output_status; + + spin_lock_bh(&priv->lock); + + phy_address = ioread32(port_base + Miicmd1) >> 27; + phy_ctrl = ioread32(port_base + PhyCtrl); + + output_status = _sc92031_mii_read(port_base, MII_OutputStatus); + _sc92031_mii_scan(port_base); + mmiowb(); + + spin_unlock_bh(&priv->lock); + + cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full + | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII; + + cmd->advertising = ADVERTISED_TP | ADVERTISED_MII; + + if ((phy_ctrl & (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10)) + == (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10)) + cmd->advertising |= ADVERTISED_Autoneg; + + if ((phy_ctrl & PhyCtrlSpd10) == PhyCtrlSpd10) + cmd->advertising |= ADVERTISED_10baseT_Half; + + if ((phy_ctrl & (PhyCtrlSpd10 | PhyCtrlDux)) + == (PhyCtrlSpd10 | PhyCtrlDux)) + cmd->advertising |= ADVERTISED_10baseT_Full; + + if ((phy_ctrl & PhyCtrlSpd100) == PhyCtrlSpd100) + cmd->advertising |= ADVERTISED_100baseT_Half; + + if ((phy_ctrl & (PhyCtrlSpd100 | PhyCtrlDux)) + == (PhyCtrlSpd100 | PhyCtrlDux)) + cmd->advertising |= ADVERTISED_100baseT_Full; + + if (phy_ctrl & PhyCtrlAne) + cmd->advertising |= ADVERTISED_Autoneg; + + cmd->speed = (output_status & 0x2) ? SPEED_100 : SPEED_10; + cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF; + cmd->port = PORT_MII; + cmd->phy_address = phy_address; + cmd->transceiver = XCVR_INTERNAL; + cmd->autoneg = (phy_ctrl & PhyCtrlAne) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + + return 0; +} + +static int sc92031_ethtool_set_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 phy_ctrl; + u32 old_phy_ctrl; + + if (!(cmd->speed == SPEED_10 || cmd->speed == SPEED_100)) + return -EINVAL; + if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL)) + return -EINVAL; + if (!(cmd->port == PORT_MII)) + return -EINVAL; + if (!(cmd->phy_address == 0x1f)) + return -EINVAL; + if (!(cmd->transceiver == XCVR_INTERNAL)) + return -EINVAL; + if (!(cmd->autoneg == AUTONEG_DISABLE || cmd->autoneg == AUTONEG_ENABLE)) + return -EINVAL; + + if (cmd->autoneg == AUTONEG_ENABLE) { + if (!(cmd->advertising & (ADVERTISED_Autoneg + | ADVERTISED_100baseT_Full + | ADVERTISED_100baseT_Half + | ADVERTISED_10baseT_Full + | ADVERTISED_10baseT_Half))) + return -EINVAL; + + phy_ctrl = PhyCtrlAne; + + // FIXME: I'm not sure what the original code was trying to do + if (cmd->advertising & ADVERTISED_Autoneg) + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10; + if (cmd->advertising & ADVERTISED_100baseT_Full) + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100; + if (cmd->advertising & ADVERTISED_100baseT_Half) + phy_ctrl |= PhyCtrlSpd100; + if (cmd->advertising & ADVERTISED_10baseT_Full) + phy_ctrl |= PhyCtrlSpd10 | PhyCtrlDux; + if (cmd->advertising & ADVERTISED_10baseT_Half) + phy_ctrl |= PhyCtrlSpd10; + } else { + // FIXME: Whole branch guessed + phy_ctrl = 0; + + if (cmd->speed == SPEED_10) + phy_ctrl |= PhyCtrlSpd10; + else /* cmd->speed == SPEED_100 */ + phy_ctrl |= PhyCtrlSpd100; + + if (cmd->duplex == DUPLEX_FULL) + phy_ctrl |= PhyCtrlDux; + } + + spin_lock_bh(&priv->lock); + + old_phy_ctrl = ioread32(port_base + PhyCtrl); + phy_ctrl |= old_phy_ctrl & ~(PhyCtrlAne | PhyCtrlDux + | PhyCtrlSpd100 | PhyCtrlSpd10); + if (phy_ctrl != old_phy_ctrl) + iowrite32(phy_ctrl, port_base + PhyCtrl); + + spin_unlock_bh(&priv->lock); + + return 0; +} + +static void sc92031_ethtool_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *drvinfo) +{ + struct sc92031_priv *priv = netdev_priv(dev); + struct pci_dev *pdev = priv->pdev; + + strcpy(drvinfo->driver, SC92031_NAME); + strcpy(drvinfo->version, SC92031_VERSION); + strcpy(drvinfo->bus_info, pci_name(pdev)); +} + +static void sc92031_ethtool_get_wol(struct net_device *dev, + struct ethtool_wolinfo *wolinfo) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 pm_config; + + spin_lock_bh(&priv->lock); + pm_config = ioread32(port_base + PMConfig); + spin_unlock_bh(&priv->lock); + + // FIXME: Guessed + wolinfo->supported = WAKE_PHY | WAKE_MAGIC + | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; + wolinfo->wolopts = 0; + + if (pm_config & PM_LinkUp) + wolinfo->wolopts |= WAKE_PHY; + + if (pm_config & PM_Magic) + wolinfo->wolopts |= WAKE_MAGIC; + + if (pm_config & PM_WakeUp) + // FIXME: Guessed + wolinfo->wolopts |= WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; +} + +static int sc92031_ethtool_set_wol(struct net_device *dev, + struct ethtool_wolinfo *wolinfo) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 pm_config; + + spin_lock_bh(&priv->lock); + + pm_config = ioread32(port_base + PMConfig) + & ~(PM_LinkUp | PM_Magic | PM_WakeUp); + + if (wolinfo->wolopts & WAKE_PHY) + pm_config |= PM_LinkUp; + + if (wolinfo->wolopts & WAKE_MAGIC) + pm_config |= PM_Magic; + + // FIXME: Guessed + if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST)) + pm_config |= PM_WakeUp; + + priv->pm_config = pm_config; + iowrite32(pm_config, port_base + PMConfig); + mmiowb(); + + spin_unlock_bh(&priv->lock); + + return 0; +} + +static int sc92031_ethtool_nway_reset(struct net_device *dev) +{ + int err = 0; + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u16 bmcr; + + spin_lock_bh(&priv->lock); + + bmcr = _sc92031_mii_read(port_base, MII_BMCR); + if (!(bmcr & BMCR_ANENABLE)) { + err = -EINVAL; + goto out; + } + + _sc92031_mii_write(port_base, MII_BMCR, bmcr | BMCR_ANRESTART); + +out: + _sc92031_mii_scan(port_base); + mmiowb(); + + spin_unlock_bh(&priv->lock); + + return err; +} + +static const char sc92031_ethtool_stats_strings[SILAN_STATS_NUM][ETH_GSTRING_LEN] = { + "tx_timeout", + "rx_loss", +}; + +static void sc92031_ethtool_get_strings(struct net_device *dev, + u32 stringset, u8 *data) +{ + if (stringset == ETH_SS_STATS) + memcpy(data, sc92031_ethtool_stats_strings, + SILAN_STATS_NUM * ETH_GSTRING_LEN); +} + +static int sc92031_ethtool_get_stats_count(struct net_device *dev) +{ + return SILAN_STATS_NUM; +} + +static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + spin_lock_bh(&priv->lock); + data[0] = priv->tx_timeouts; + data[1] = priv->rx_loss; + spin_unlock_bh(&priv->lock); +} + +static struct ethtool_ops sc92031_ethtool_ops = { + .get_settings = sc92031_ethtool_get_settings, + .set_settings = sc92031_ethtool_set_settings, + .get_drvinfo = sc92031_ethtool_get_drvinfo, + .get_wol = sc92031_ethtool_get_wol, + .set_wol = sc92031_ethtool_set_wol, + .nway_reset = sc92031_ethtool_nway_reset, + .get_link = ethtool_op_get_link, + .get_tx_csum = ethtool_op_get_tx_csum, + .get_sg = ethtool_op_get_sg, + .get_tso = ethtool_op_get_tso, + .get_strings = sc92031_ethtool_get_strings, + .get_stats_count = sc92031_ethtool_get_stats_count, + .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats, + .get_perm_addr = ethtool_op_get_perm_addr, + .get_ufo = ethtool_op_get_ufo, +}; + +static int __devinit sc92031_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int err; + void __iomem* port_base; + struct net_device *dev; + struct sc92031_priv *priv; + u32 mac0, mac1; + + err = pci_enable_device(pdev); + if (unlikely(err < 0)) + goto out_enable_device; + + pci_set_master(pdev); + + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (unlikely(err < 0)) + goto out_set_dma_mask; + + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (unlikely(err < 0)) + goto out_set_dma_mask; + + err = pci_request_regions(pdev, SC92031_NAME); + if (unlikely(err < 0)) + goto out_request_regions; + + port_base = pci_iomap(pdev, SC92031_USE_BAR, 0); + if (unlikely(!port_base)) { + err = -EIO; + goto out_iomap; + } + + dev = alloc_etherdev(sizeof(struct sc92031_priv)); + if (unlikely(!dev)) { + err = -ENOMEM; + goto out_alloc_etherdev; + } + + pci_set_drvdata(pdev, dev); + +#if SC92031_USE_BAR == 0 + dev->mem_start = pci_resource_start(pdev, SC92031_USE_BAR); + dev->mem_end = pci_resource_end(pdev, SC92031_USE_BAR); +#elif SC92031_USE_BAR == 1 + dev->base_addr = pci_resource_start(pdev, SC92031_USE_BAR); +#endif + dev->irq = pdev->irq; + + /* faked with skb_copy_and_csum_dev */ + dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA; + + dev->get_stats = sc92031_get_stats; + dev->ethtool_ops = &sc92031_ethtool_ops; + dev->hard_start_xmit = sc92031_start_xmit; + dev->watchdog_timeo = TX_TIMEOUT; + dev->open = sc92031_open; + dev->stop = sc92031_stop; + dev->set_multicast_list = sc92031_set_multicast_list; + dev->tx_timeout = sc92031_tx_timeout; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = sc92031_poll_controller; +#endif + + priv = netdev_priv(dev); + spin_lock_init(&priv->lock); + priv->port_base = port_base; + priv->pdev = pdev; + tasklet_init(&priv->tasklet, sc92031_tasklet, (unsigned long)dev); + /* Fudge tasklet count so the call to sc92031_enable_interrupts at + * sc92031_open will work correctly */ + tasklet_disable_nosync(&priv->tasklet); + + /* PCI PM Wakeup */ + iowrite32((~PM_LongWF & ~PM_LWPTN) | PM_Enable, port_base + PMConfig); + + mac0 = ioread32(port_base + MAC0); + mac1 = ioread32(port_base + MAC0 + 4); + dev->dev_addr[0] = dev->perm_addr[0] = mac0 >> 24; + dev->dev_addr[1] = dev->perm_addr[1] = mac0 >> 16; + dev->dev_addr[2] = dev->perm_addr[2] = mac0 >> 8; + dev->dev_addr[3] = dev->perm_addr[3] = mac0; + dev->dev_addr[4] = dev->perm_addr[4] = mac1 >> 8; + dev->dev_addr[5] = dev->perm_addr[5] = mac1; + + err = register_netdev(dev); + if (err < 0) + goto out_register_netdev; + + return 0; + +out_register_netdev: + free_netdev(dev); +out_alloc_etherdev: + pci_iounmap(pdev, port_base); +out_iomap: + pci_release_regions(pdev); +out_request_regions: +out_set_dma_mask: + pci_disable_device(pdev); +out_enable_device: + return err; +} + +static void __devexit sc92031_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem* port_base = priv->port_base; + + unregister_netdev(dev); + free_netdev(dev); + pci_iounmap(pdev, port_base); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static int sc92031_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct sc92031_priv *priv = netdev_priv(dev); + + pci_save_state(pdev); + + if (!netif_running(dev)) + goto out; + + netif_device_detach(dev); + + /* Disable interrupts, stop Tx and Rx. */ + sc92031_disable_interrupts(dev); + + spin_lock(&priv->lock); + + _sc92031_disable_tx_rx(dev); + _sc92031_tx_clear(dev); + mmiowb(); + + spin_unlock(&priv->lock); + +out: + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int sc92031_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct sc92031_priv *priv = netdev_priv(dev); + + pci_restore_state(pdev); + pci_set_power_state(pdev, PCI_D0); + + if (!netif_running(dev)) + goto out; + + /* Interrupts already disabled by sc92031_suspend */ + spin_lock(&priv->lock); + + _sc92031_reset(dev); + mmiowb(); + + spin_unlock(&priv->lock); + sc92031_enable_interrupts(dev); + + netif_device_attach(dev); + + if (netif_carrier_ok(dev)) + netif_wake_queue(dev); + else + netif_tx_disable(dev); + +out: + return 0; +} + +static struct pci_device_id sc92031_pci_device_id_table[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_SC92031) }, + { PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_8139D) }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sc92031_pci_device_id_table); + +static struct pci_driver sc92031_pci_driver = { + .name = SC92031_NAME, + .id_table = sc92031_pci_device_id_table, + .probe = sc92031_probe, + .remove = __devexit_p(sc92031_remove), + .suspend = sc92031_suspend, + .resume = sc92031_resume, +}; + +static int __init sc92031_init(void) +{ + printk(KERN_INFO SC92031_DESCRIPTION " " SC92031_VERSION "\n"); + return pci_register_driver(&sc92031_pci_driver); +} + +static void __exit sc92031_exit(void) +{ + pci_unregister_driver(&sc92031_pci_driver); +} + +module_init(sc92031_init); +module_exit(sc92031_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Cesar Eduardo Barros "); +MODULE_DESCRIPTION(SC92031_DESCRIPTION); +MODULE_VERSION(SC92031_VERSION); diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c deleted file mode 100644 index 96e06c51b75d..000000000000 --- a/drivers/net/sk_mca.c +++ /dev/null @@ -1,1216 +0,0 @@ -/* -net-3-driver for the SKNET MCA-based cards - -This is an extension to the Linux operating system, and is covered by the -same GNU General Public License that covers that work. - -Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de, - alfred.arnold@lancom.de) - -This driver is based both on the 3C523 driver and the SK_G16 driver. - -paper sources: - 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by - Hans-Peter Messmer for the basic Microchannel stuff - - 'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer - for help on Ethernet driver programming - - 'Ethernet/IEEE 802.3 Family 1992 World Network Data Book/Handbook' by AMD - for documentation on the AM7990 LANCE - - 'SKNET Personal Technisches Manual', Version 1.2 by Schneider&Koch - for documentation on the Junior board - - 'SK-NET MC2+ Technical Manual", Version 1.1 by Schneider&Koch for - documentation on the MC2 bord - - A big thank you to the S&K support for providing me so quickly with - documentation! - - Also see http://www.syskonnect.com/ - - Missing things: - - -> set debug level via ioctl instead of compile-time switches - -> I didn't follow the development of the 2.1.x kernels, so my - assumptions about which things changed with which kernel version - are probably nonsense - -History: - May 16th, 1999 - startup - May 22st, 1999 - added private structure, methods - begun building data structures in RAM - May 23nd, 1999 - can receive frames, send frames - May 24th, 1999 - modularized initialization of LANCE - loadable as module - still Tx problem :-( - May 26th, 1999 - MC2 works - support for multiple devices - display media type for MC2+ - May 28th, 1999 - fixed problem in GetLANCE leaving interrupts turned off - increase TX queue to 4 packets to improve send performance - May 29th, 1999 - a few corrections in statistics, caught rcvr overruns - reinitialization of LANCE/board in critical situations - MCA info implemented - implemented LANCE multicast filter - Jun 6th, 1999 - additions for Linux 2.2 - Dec 25th, 1999 - unfortunately there seem to be newer MC2+ boards that react - on IRQ 3/5/9/10 instead of 3/5/10/11, so we have to autoprobe - in questionable cases... - Dec 28th, 1999 - integrated patches from David Weinehall & Bill Wendling for 2.3 - kernels (isa_...functions). Things are defined in a way that - it still works with 2.0.x 8-) - Dec 30th, 1999 - added handling of the remaining interrupt conditions. That - should cure the spurious hangs. - Jan 30th, 2000 - newer kernels automatically probe more than one board, so the - 'startslot' as a variable is also needed here - June 1st, 2000 - added changes for recent 2.3 kernels - - *************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define _SK_MCA_DRIVER_ -#include "sk_mca.h" - -/* ------------------------------------------------------------------------ - * global static data - not more since we can handle multiple boards and - * have to pack all state info into the device struct! - * ------------------------------------------------------------------------ */ - -static char *MediaNames[Media_Count] = - { "10Base2", "10BaseT", "10Base5", "Unknown" }; - -static unsigned char poly[] = - { 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 -}; - -/* ------------------------------------------------------------------------ - * private subfunctions - * ------------------------------------------------------------------------ */ - -/* dump parts of shared memory - only needed during debugging */ - -#ifdef DEBUG -static void dumpmem(struct net_device *dev, u32 start, u32 len) -{ - skmca_priv *priv = netdev_priv(dev); - int z; - - for (z = 0; z < len; z++) { - if ((z & 15) == 0) - printk("%04x:", z); - printk(" %02x", readb(priv->base + start + z)); - if ((z & 15) == 15) - printk("\n"); - } -} - -/* print exact time - ditto */ - -static void PrTime(void) -{ - struct timeval tv; - - do_gettimeofday(&tv); - printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec); -} -#endif - -/* deduce resources out of POS registers */ - -static void __init getaddrs(int slot, int junior, int *base, int *irq, - skmca_medium * medium) -{ - u_char pos0, pos1, pos2; - - if (junior) { - pos0 = mca_read_stored_pos(slot, 2); - *base = ((pos0 & 0x0e) << 13) + 0xc0000; - *irq = ((pos0 & 0x10) >> 4) + 10; - *medium = Media_Unknown; - } else { - /* reset POS 104 Bits 0+1 so the shared memory region goes to the - configured area between 640K and 1M. Afterwards, enable the MC2. - I really don't know what rode SK to do this... */ - - mca_write_pos(slot, 4, - mca_read_stored_pos(slot, 4) & 0xfc); - mca_write_pos(slot, 2, - mca_read_stored_pos(slot, 2) | 0x01); - - pos1 = mca_read_stored_pos(slot, 3); - pos2 = mca_read_stored_pos(slot, 4); - *base = ((pos1 & 0x07) << 14) + 0xc0000; - switch (pos2 & 0x0c) { - case 0: - *irq = 3; - break; - case 4: - *irq = 5; - break; - case 8: - *irq = -10; - break; - case 12: - *irq = -11; - break; - } - *medium = (pos2 >> 6) & 3; - } -} - -/* check for both cards: - When the MC2 is turned off, it was configured for more than 15MB RAM, - is disabled and won't get detected using the standard probe. We - therefore have to scan the slots manually :-( */ - -static int __init dofind(int *junior, int firstslot) -{ - int slot; - unsigned int id; - - for (slot = firstslot; slot < MCA_MAX_SLOT_NR; slot++) { - id = mca_read_stored_pos(slot, 0) - + (((unsigned int) mca_read_stored_pos(slot, 1)) << 8); - - *junior = 0; - if (id == SKNET_MCA_ID) - return slot; - *junior = 1; - if (id == SKNET_JUNIOR_MCA_ID) - return slot; - } - return MCA_NOTFOUND; -} - -/* reset the whole board */ - -static void ResetBoard(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - - writeb(CTRL_RESET_ON, priv->ctrladdr); - udelay(10); - writeb(CTRL_RESET_OFF, priv->ctrladdr); -} - -/* wait for LANCE interface to become not busy */ - -static int WaitLANCE(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - int t = 0; - - while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == - STAT_IO_BUSY) { - udelay(1); - if (++t > 1000) { - printk("%s: LANCE access timeout", dev->name); - return 0; - } - } - - return 1; -} - -/* set LANCE register - must be atomic */ - -static void SetLANCE(struct net_device *dev, u16 addr, u16 value) -{ - skmca_priv *priv = netdev_priv(dev); - unsigned long flags; - - /* disable interrupts */ - - spin_lock_irqsave(&priv->lock, flags); - - /* wait until no transfer is pending */ - - WaitLANCE(dev); - - /* transfer register address to RAP */ - - writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr); - writew(addr, priv->ioregaddr); - writeb(IOCMD_GO, priv->cmdaddr); - udelay(1); - WaitLANCE(dev); - - /* transfer data to register */ - - writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, priv->ctrladdr); - writew(value, priv->ioregaddr); - writeb(IOCMD_GO, priv->cmdaddr); - udelay(1); - WaitLANCE(dev); - - /* reenable interrupts */ - - spin_unlock_irqrestore(&priv->lock, flags); -} - -/* get LANCE register */ - -static u16 GetLANCE(struct net_device *dev, u16 addr) -{ - skmca_priv *priv = netdev_priv(dev); - unsigned long flags; - unsigned int res; - - /* disable interrupts */ - - spin_lock_irqsave(&priv->lock, flags); - - /* wait until no transfer is pending */ - - WaitLANCE(dev); - - /* transfer register address to RAP */ - - writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr); - writew(addr, priv->ioregaddr); - writeb(IOCMD_GO, priv->cmdaddr); - udelay(1); - WaitLANCE(dev); - - /* transfer data from register */ - - writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, priv->ctrladdr); - writeb(IOCMD_GO, priv->cmdaddr); - udelay(1); - WaitLANCE(dev); - res = readw(priv->ioregaddr); - - /* reenable interrupts */ - - spin_unlock_irqrestore(&priv->lock, flags); - - return res; -} - -/* build up descriptors in shared RAM */ - -static void InitDscrs(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - u32 bufaddr; - - /* Set up Tx descriptors. The board has only 16K RAM so bits 16..23 - are always 0. */ - - bufaddr = RAM_DATABASE; - { - LANCE_TxDescr descr; - int z; - - for (z = 0; z < TXCOUNT; z++) { - descr.LowAddr = bufaddr; - descr.Flags = 0; - descr.Len = 0xf000; - descr.Status = 0; - memcpy_toio(priv->base + RAM_TXBASE + - (z * sizeof(LANCE_TxDescr)), &descr, - sizeof(LANCE_TxDescr)); - memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE); - bufaddr += RAM_BUFSIZE; - } - } - - /* do the same for the Rx descriptors */ - - { - LANCE_RxDescr descr; - int z; - - for (z = 0; z < RXCOUNT; z++) { - descr.LowAddr = bufaddr; - descr.Flags = RXDSCR_FLAGS_OWN; - descr.MaxLen = -RAM_BUFSIZE; - descr.Len = 0; - memcpy_toio(priv->base + RAM_RXBASE + - (z * sizeof(LANCE_RxDescr)), &descr, - sizeof(LANCE_RxDescr)); - memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE); - bufaddr += RAM_BUFSIZE; - } - } -} - -/* calculate the hash bit position for a given multicast address - taken more or less directly from the AMD datasheet... */ - -static void UpdateCRC(unsigned char *CRC, int bit) -{ - int j; - - /* shift CRC one bit */ - - memmove(CRC + 1, CRC, 32 * sizeof(unsigned char)); - CRC[0] = 0; - - /* if bit XOR controlbit = 1, set CRC = CRC XOR polynomial */ - - if (bit ^ CRC[32]) - for (j = 0; j < 32; j++) - CRC[j] ^= poly[j]; -} - -static unsigned int GetHash(char *address) -{ - unsigned char CRC[33]; - int i, byte, hashcode; - - /* a multicast address has bit 0 in the first byte set */ - - if ((address[0] & 1) == 0) - return -1; - - /* initialize CRC */ - - memset(CRC, 1, sizeof(CRC)); - - /* loop through address bits */ - - for (byte = 0; byte < 6; byte++) - for (i = 0; i < 8; i++) - UpdateCRC(CRC, (address[byte] >> i) & 1); - - /* hashcode is the 6 least significant bits of the CRC */ - - hashcode = 0; - for (i = 0; i < 6; i++) - hashcode = (hashcode << 1) + CRC[i]; - return hashcode; -} - -/* feed ready-built initialization block into LANCE */ - -static void InitLANCE(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - - /* build up descriptors. */ - - InitDscrs(dev); - - /* next RX descriptor to be read is the first one. Since the LANCE - will start from the beginning after initialization, we have to - reset out pointers too. */ - - priv->nextrx = 0; - - /* no TX descriptors active */ - - priv->nexttxput = priv->nexttxdone = priv->txbusy = 0; - - /* set up the LANCE bus control register - constant for SKnet boards */ - - SetLANCE(dev, LANCE_CSR3, - CSR3_BSWAP_OFF | CSR3_ALE_LOW | CSR3_BCON_HOLD); - - /* write address of initialization block into LANCE */ - - SetLANCE(dev, LANCE_CSR1, RAM_INITBASE & 0xffff); - SetLANCE(dev, LANCE_CSR2, (RAM_INITBASE >> 16) & 0xff); - - /* we don't get ready until the LANCE has read the init block */ - - netif_stop_queue(dev); - - /* let LANCE read the initialization block. LANCE is ready - when we receive the corresponding interrupt. */ - - SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_INIT); -} - -/* stop the LANCE so we can reinitialize it */ - -static void StopLANCE(struct net_device *dev) -{ - /* can't take frames any more */ - - netif_stop_queue(dev); - - /* disable interrupts, stop it */ - - SetLANCE(dev, LANCE_CSR0, CSR0_STOP); -} - -/* initialize card and LANCE for proper operation */ - -static void InitBoard(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - LANCE_InitBlock block; - - /* Lay out the shared RAM - first we create the init block for the LANCE. - We do not overwrite it later because we need it again when we switch - promiscous mode on/off. */ - - block.Mode = 0; - if (dev->flags & IFF_PROMISC) - block.Mode |= LANCE_INIT_PROM; - memcpy(block.PAdr, dev->dev_addr, 6); - memset(block.LAdrF, 0, sizeof(block.LAdrF)); - block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29); - block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29); - - memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block)); - - /* initialize LANCE. Implicitly sets up other structures in RAM. */ - - InitLANCE(dev); -} - -/* deinitialize card and LANCE */ - -static void DeinitBoard(struct net_device *dev) -{ - /* stop LANCE */ - - StopLANCE(dev); - - /* reset board */ - - ResetBoard(dev); -} - -/* probe for device's irq */ - -static int __init ProbeIRQ(struct net_device *dev) -{ - unsigned long imaskval, njiffies, irq; - u16 csr0val; - - /* enable all interrupts */ - - imaskval = probe_irq_on(); - - /* initialize the board. Wait for interrupt 'Initialization done'. */ - - ResetBoard(dev); - InitBoard(dev); - - njiffies = jiffies + HZ; - do { - csr0val = GetLANCE(dev, LANCE_CSR0); - } - while (((csr0val & CSR0_IDON) == 0) && (jiffies != njiffies)); - - /* turn of interrupts again */ - - irq = probe_irq_off(imaskval); - - /* if we found something, ack the interrupt */ - - if (irq) - SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_IDON); - - /* back to idle state */ - - DeinitBoard(dev); - - return irq; -} - -/* ------------------------------------------------------------------------ - * interrupt handler(s) - * ------------------------------------------------------------------------ */ - -/* LANCE has read initialization block -> start it */ - -static u16 irqstart_handler(struct net_device *dev, u16 oldcsr0) -{ - /* now we're ready to transmit */ - - netif_wake_queue(dev); - - /* reset IDON bit, start LANCE */ - - SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT); - return GetLANCE(dev, LANCE_CSR0); -} - -/* did we lose blocks due to a FIFO overrun ? */ - -static u16 irqmiss_handler(struct net_device *dev, u16 oldcsr0) -{ - skmca_priv *priv = netdev_priv(dev); - - /* update statistics */ - - priv->stat.rx_fifo_errors++; - - /* reset MISS bit */ - - SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_MISS); - return GetLANCE(dev, LANCE_CSR0); -} - -/* receive interrupt */ - -static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0) -{ - skmca_priv *priv = netdev_priv(dev); - LANCE_RxDescr descr; - unsigned int descraddr; - - /* run through queue until we reach a descriptor we do not own */ - - descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr)); - while (1) { - /* read descriptor */ - memcpy_fromio(&descr, priv->base + descraddr, - sizeof(LANCE_RxDescr)); - - /* if we reach a descriptor we do not own, we're done */ - if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0) - break; - -#ifdef DEBUG - PrTime(); - printk("Receive packet on descr %d len %d\n", priv->nextrx, - descr.Len); -#endif - - /* erroneous packet ? */ - if ((descr.Flags & RXDSCR_FLAGS_ERR) != 0) { - priv->stat.rx_errors++; - if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0) - priv->stat.rx_crc_errors++; - else if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0) - priv->stat.rx_frame_errors++; - else if ((descr.Flags & RXDSCR_FLAGS_OFLO) != 0) - priv->stat.rx_fifo_errors++; - } - - /* good packet ? */ - else { - struct sk_buff *skb; - - skb = dev_alloc_skb(descr.Len + 2); - if (skb == NULL) - priv->stat.rx_dropped++; - else { - memcpy_fromio(skb_put(skb, descr.Len), - priv->base + - descr.LowAddr, descr.Len); - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_NONE; - priv->stat.rx_packets++; - priv->stat.rx_bytes += descr.Len; - netif_rx(skb); - dev->last_rx = jiffies; - } - } - - /* give descriptor back to LANCE */ - descr.Len = 0; - descr.Flags |= RXDSCR_FLAGS_OWN; - - /* update descriptor in shared RAM */ - memcpy_toio(priv->base + descraddr, &descr, - sizeof(LANCE_RxDescr)); - - /* go to next descriptor */ - priv->nextrx++; - descraddr += sizeof(LANCE_RxDescr); - if (priv->nextrx >= RXCOUNT) { - priv->nextrx = 0; - descraddr = RAM_RXBASE; - } - } - - /* reset RINT bit */ - - SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_RINT); - return GetLANCE(dev, LANCE_CSR0); -} - -/* transmit interrupt */ - -static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0) -{ - skmca_priv *priv = netdev_priv(dev); - LANCE_TxDescr descr; - unsigned int descraddr; - - /* check descriptors at most until no busy one is left */ - - descraddr = - RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr)); - while (priv->txbusy > 0) { - /* read descriptor */ - memcpy_fromio(&descr, priv->base + descraddr, - sizeof(LANCE_TxDescr)); - - /* if the LANCE still owns this one, we've worked out all sent packets */ - if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0) - break; - -#ifdef DEBUG - PrTime(); - printk("Send packet done on descr %d\n", priv->nexttxdone); -#endif - - /* update statistics */ - if ((descr.Flags & TXDSCR_FLAGS_ERR) == 0) { - priv->stat.tx_packets++; - priv->stat.tx_bytes++; - } else { - priv->stat.tx_errors++; - if ((descr.Status & TXDSCR_STATUS_UFLO) != 0) { - priv->stat.tx_fifo_errors++; - InitLANCE(dev); - } - else - if ((descr.Status & TXDSCR_STATUS_LCOL) != - 0) priv->stat.tx_window_errors++; - else if ((descr.Status & TXDSCR_STATUS_LCAR) != 0) - priv->stat.tx_carrier_errors++; - else if ((descr.Status & TXDSCR_STATUS_RTRY) != 0) - priv->stat.tx_aborted_errors++; - } - - /* go to next descriptor */ - priv->nexttxdone++; - descraddr += sizeof(LANCE_TxDescr); - if (priv->nexttxdone >= TXCOUNT) { - priv->nexttxdone = 0; - descraddr = RAM_TXBASE; - } - priv->txbusy--; - } - - /* reset TX interrupt bit */ - - SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_TINT); - oldcsr0 = GetLANCE(dev, LANCE_CSR0); - - /* at least one descriptor is freed. Therefore we can accept - a new one */ - /* inform upper layers we're in business again */ - - netif_wake_queue(dev); - - return oldcsr0; -} - -/* general interrupt entry */ - -static irqreturn_t irq_handler(int irq, void *device) -{ - struct net_device *dev = (struct net_device *) device; - u16 csr0val; - - /* read CSR0 to get interrupt cause */ - - csr0val = GetLANCE(dev, LANCE_CSR0); - - /* in case we're not meant... */ - - if ((csr0val & CSR0_INTR) == 0) - return IRQ_NONE; - -#if 0 - set_bit(LINK_STATE_RXSEM, &dev->state); -#endif - - /* loop through the interrupt bits until everything is clear */ - - do { - if ((csr0val & CSR0_IDON) != 0) - csr0val = irqstart_handler(dev, csr0val); - if ((csr0val & CSR0_RINT) != 0) - csr0val = irqrx_handler(dev, csr0val); - if ((csr0val & CSR0_MISS) != 0) - csr0val = irqmiss_handler(dev, csr0val); - if ((csr0val & CSR0_TINT) != 0) - csr0val = irqtx_handler(dev, csr0val); - if ((csr0val & CSR0_MERR) != 0) { - SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_MERR); - csr0val = GetLANCE(dev, LANCE_CSR0); - } - if ((csr0val & CSR0_BABL) != 0) { - SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_BABL); - csr0val = GetLANCE(dev, LANCE_CSR0); - } - } - while ((csr0val & CSR0_INTR) != 0); - -#if 0 - clear_bit(LINK_STATE_RXSEM, &dev->state); -#endif - return IRQ_HANDLED; -} - -/* ------------------------------------------------------------------------ - * driver methods - * ------------------------------------------------------------------------ */ - -/* MCA info */ - -static int skmca_getinfo(char *buf, int slot, void *d) -{ - int len = 0, i; - struct net_device *dev = (struct net_device *) d; - skmca_priv *priv; - - /* can't say anything about an uninitialized device... */ - - if (dev == NULL) - return len; - priv = netdev_priv(dev); - - /* print info */ - - len += sprintf(buf + len, "IRQ: %d\n", priv->realirq); - len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start, - dev->mem_end - 1); - len += - sprintf(buf + len, "Transceiver: %s\n", - MediaNames[priv->medium]); - len += sprintf(buf + len, "Device: %s\n", dev->name); - len += sprintf(buf + len, "MAC address:"); - for (i = 0; i < 6; i++) - len += sprintf(buf + len, " %02x", dev->dev_addr[i]); - buf[len++] = '\n'; - buf[len] = 0; - - return len; -} - -/* open driver. Means also initialization and start of LANCE */ - -static int skmca_open(struct net_device *dev) -{ - int result; - skmca_priv *priv = netdev_priv(dev); - - /* register resources - only necessary for IRQ */ - result = - request_irq(priv->realirq, irq_handler, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, "sk_mca", dev); - if (result != 0) { - printk("%s: failed to register irq %d\n", dev->name, - dev->irq); - return result; - } - dev->irq = priv->realirq; - - /* set up the card and LANCE */ - - InitBoard(dev); - - /* set up flags */ - - netif_start_queue(dev); - - return 0; -} - -/* close driver. Shut down board and free allocated resources */ - -static int skmca_close(struct net_device *dev) -{ - /* turn off board */ - DeinitBoard(dev); - - /* release resources */ - if (dev->irq != 0) - free_irq(dev->irq, dev); - dev->irq = 0; - - return 0; -} - -/* transmit a block. */ - -static int skmca_tx(struct sk_buff *skb, struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - LANCE_TxDescr descr; - unsigned int address; - int tmplen, retval = 0; - unsigned long flags; - - /* if we get called with a NULL descriptor, the Ethernet layer thinks - our card is stuck an we should reset it. We'll do this completely: */ - - if (skb == NULL) { - DeinitBoard(dev); - InitBoard(dev); - return 0; /* don't try to free the block here ;-) */ - } - - /* is there space in the Tx queue ? If no, the upper layer gave us a - packet in spite of us not being ready and is really in trouble. - We'll do the dropping for him: */ - if (priv->txbusy >= TXCOUNT) { - priv->stat.tx_dropped++; - retval = -EIO; - goto tx_done; - } - - /* get TX descriptor */ - address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr)); - memcpy_fromio(&descr, priv->base + address, sizeof(LANCE_TxDescr)); - - /* enter packet length as 2s complement - assure minimum length */ - tmplen = skb->len; - if (tmplen < 60) - tmplen = 60; - descr.Len = 65536 - tmplen; - - /* copy filler into RAM - in case we're filling up... - we're filling a bit more than necessary, but that doesn't harm - since the buffer is far larger... */ - if (tmplen > skb->len) { - char *fill = "NetBSD is a nice OS too! "; - unsigned int destoffs = 0, l = strlen(fill); - - while (destoffs < tmplen) { - memcpy_toio(priv->base + descr.LowAddr + - destoffs, fill, l); - destoffs += l; - } - } - - /* do the real data copying */ - memcpy_toio(priv->base + descr.LowAddr, skb->data, skb->len); - - /* hand descriptor over to LANCE - this is the first and last chunk */ - descr.Flags = - TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP; - -#ifdef DEBUG - PrTime(); - printk("Send packet on descr %d len %d\n", priv->nexttxput, - skb->len); -#endif - - /* one more descriptor busy */ - - spin_lock_irqsave(&priv->lock, flags); - - priv->nexttxput++; - if (priv->nexttxput >= TXCOUNT) - priv->nexttxput = 0; - priv->txbusy++; - - /* are we saturated ? */ - - if (priv->txbusy >= TXCOUNT) - netif_stop_queue(dev); - - /* write descriptor back to RAM */ - memcpy_toio(priv->base + address, &descr, sizeof(LANCE_TxDescr)); - - /* if no descriptors were active, give the LANCE a hint to read it - immediately */ - - if (priv->txbusy == 0) - SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD); - - spin_unlock_irqrestore(&priv->lock, flags); - - tx_done: - - dev_kfree_skb(skb); - - return retval; -} - -/* return pointer to Ethernet statistics */ - -static struct net_device_stats *skmca_stats(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - - return &(priv->stat); -} - -/* switch receiver mode. We use the LANCE's multicast filter to prefilter - multicast addresses. */ - -static void skmca_set_multicast_list(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - LANCE_InitBlock block; - - /* first stop the LANCE... */ - StopLANCE(dev); - - /* ...then modify the initialization block... */ - memcpy_fromio(&block, priv->base + RAM_INITBASE, sizeof(block)); - if (dev->flags & IFF_PROMISC) - block.Mode |= LANCE_INIT_PROM; - else - block.Mode &= ~LANCE_INIT_PROM; - - if (dev->flags & IFF_ALLMULTI) { /* get all multicasts */ - memset(block.LAdrF, 0xff, sizeof(block.LAdrF)); - } else { /* get selected/no multicasts */ - - struct dev_mc_list *mptr; - int code; - - memset(block.LAdrF, 0, sizeof(block.LAdrF)); - for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next) { - code = GetHash(mptr->dmi_addr); - block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7); - } - } - - memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block)); - - /* ...then reinit LANCE with the correct flags */ - InitLANCE(dev); -} - -/* ------------------------------------------------------------------------ - * hardware check - * ------------------------------------------------------------------------ */ - -static int startslot; /* counts through slots when probing multiple devices */ - -static void cleanup_card(struct net_device *dev) -{ - skmca_priv *priv = netdev_priv(dev); - DeinitBoard(dev); - if (dev->irq != 0) - free_irq(dev->irq, dev); - iounmap(priv->base); - mca_mark_as_unused(priv->slot); - mca_set_adapter_procfn(priv->slot, NULL, NULL); -} - -struct net_device * __init skmca_probe(int unit) -{ - struct net_device *dev; - int force_detect = 0; - int junior, slot, i; - int base = 0, irq = 0; - skmca_priv *priv; - skmca_medium medium; - int err; - - /* can't work without an MCA bus ;-) */ - - if (MCA_bus == 0) - return ERR_PTR(-ENODEV); - - dev = alloc_etherdev(sizeof(skmca_priv)); - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) { - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - } - - SET_MODULE_OWNER(dev); - - /* start address of 1 --> forced detection */ - - if (dev->mem_start == 1) - force_detect = 1; - - /* search through slots */ - - base = dev->mem_start; - irq = dev->base_addr; - for (slot = startslot; (slot = dofind(&junior, slot)) != -1; slot++) { - /* deduce card addresses */ - - getaddrs(slot, junior, &base, &irq, &medium); - - /* slot already in use ? */ - - if (mca_is_adapter_used(slot)) - continue; - - /* were we looking for something different ? */ - - if (dev->irq && dev->irq != irq) - continue; - if (dev->mem_start && dev->mem_start != base) - continue; - - /* found something that matches */ - - break; - } - - /* nothing found ? */ - - if (slot == -1) { - free_netdev(dev); - return (base || irq) ? ERR_PTR(-ENXIO) : ERR_PTR(-ENODEV); - } - - /* make procfs entries */ - - if (junior) - mca_set_adapter_name(slot, - "SKNET junior MC2 Ethernet Adapter"); - else - mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter"); - mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev); - - mca_mark_as_used(slot); - - /* announce success */ - printk("%s: SKNet %s adapter found in slot %d\n", dev->name, - junior ? "Junior MC2" : "MC2+", slot + 1); - - priv = netdev_priv(dev); - priv->base = ioremap(base, 0x4000); - if (!priv->base) { - mca_set_adapter_procfn(slot, NULL, NULL); - mca_mark_as_unused(slot); - free_netdev(dev); - return ERR_PTR(-ENOMEM); - } - - priv->slot = slot; - priv->macbase = priv->base + 0x3fc0; - priv->ioregaddr = priv->base + 0x3ff0; - priv->ctrladdr = priv->base + 0x3ff2; - priv->cmdaddr = priv->base + 0x3ff3; - priv->medium = medium; - memset(&priv->stat, 0, sizeof(struct net_device_stats)); - spin_lock_init(&priv->lock); - - /* set base + irq for this device (irq not allocated so far) */ - dev->irq = 0; - dev->mem_start = base; - dev->mem_end = base + 0x4000; - - /* autoprobe ? */ - if (irq < 0) { - int nirq; - - printk - ("%s: ambigous POS bit combination, must probe for IRQ...\n", - dev->name); - nirq = ProbeIRQ(dev); - if (nirq <= 0) - printk("%s: IRQ probe failed, assuming IRQ %d", - dev->name, priv->realirq = -irq); - else - priv->realirq = nirq; - } else - priv->realirq = irq; - - /* set methods */ - dev->open = skmca_open; - dev->stop = skmca_close; - dev->hard_start_xmit = skmca_tx; - dev->do_ioctl = NULL; - dev->get_stats = skmca_stats; - dev->set_multicast_list = skmca_set_multicast_list; - dev->flags |= IFF_MULTICAST; - - /* copy out MAC address */ - for (i = 0; i < 6; i++) - dev->dev_addr[i] = readb(priv->macbase + (i << 1)); - - /* print config */ - printk("%s: IRQ %d, memory %#lx-%#lx, " - "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n", - dev->name, priv->realirq, dev->mem_start, dev->mem_end - 1, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); - printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]); - - /* reset board */ - - ResetBoard(dev); - - startslot = slot + 1; - - err = register_netdev(dev); - if (err) { - cleanup_card(dev); - free_netdev(dev); - dev = ERR_PTR(err); - } - return dev; -} - -/* ------------------------------------------------------------------------ - * modularization support - * ------------------------------------------------------------------------ */ - -#ifdef MODULE -MODULE_LICENSE("GPL"); - -#define DEVMAX 5 - -static struct net_device *moddevs[DEVMAX]; - -int init_module(void) -{ - int z; - - startslot = 0; - for (z = 0; z < DEVMAX; z++) { - struct net_device *dev = skmca_probe(-1); - if (IS_ERR(dev)) - break; - moddevs[z] = dev; - } - if (!z) - return -EIO; - return 0; -} - -void cleanup_module(void) -{ - int z; - - for (z = 0; z < DEVMAX; z++) { - struct net_device *dev = moddevs[z]; - if (dev) { - unregister_netdev(dev); - cleanup_card(dev); - free_netdev(dev); - } - } -} -#endif /* MODULE */ diff --git a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h deleted file mode 100644 index 0dae056fed99..000000000000 --- a/drivers/net/sk_mca.h +++ /dev/null @@ -1,170 +0,0 @@ -#ifndef _SK_MCA_INCLUDE_ -#define _SK_MCA_INCLUDE_ - -#ifdef _SK_MCA_DRIVER_ - -/* Adapter ID's */ -#define SKNET_MCA_ID 0x6afd -#define SKNET_JUNIOR_MCA_ID 0x6be9 - -/* media enumeration - defined in a way that it fits onto the MC2+'s - POS registers... */ - -typedef enum { Media_10Base2, Media_10BaseT, - Media_10Base5, Media_Unknown, Media_Count -} skmca_medium; - -/* private structure */ -typedef struct { - unsigned int slot; /* MCA-Slot-# */ - void __iomem *base; - void __iomem *macbase; /* base address of MAC address PROM */ - void __iomem *ioregaddr;/* address of I/O-register (Lo) */ - void __iomem *ctrladdr; /* address of control/stat register */ - void __iomem *cmdaddr; /* address of I/O-command register */ - int nextrx; /* index of next RX descriptor to - be read */ - int nexttxput; /* index of next free TX descriptor */ - int nexttxdone; /* index of next TX descriptor to - be finished */ - int txbusy; /* # of busy TX descriptors */ - struct net_device_stats stat; /* packet statistics */ - int realirq; /* memorizes actual IRQ, even when - currently not allocated */ - skmca_medium medium; /* physical cannector */ - spinlock_t lock; -} skmca_priv; - -/* card registers: control/status register bits */ - -#define CTRL_ADR_DATA 0 /* Bit 0 = 0 ->access data register */ -#define CTRL_ADR_RAP 1 /* Bit 0 = 1 ->access RAP register */ -#define CTRL_RW_WRITE 0 /* Bit 1 = 0 ->write register */ -#define CTRL_RW_READ 2 /* Bit 1 = 1 ->read register */ -#define CTRL_RESET_ON 0 /* Bit 3 = 0 ->reset board */ -#define CTRL_RESET_OFF 8 /* Bit 3 = 1 ->no reset of board */ - -#define STAT_ADR_DATA 0 /* Bit 0 of ctrl register read back */ -#define STAT_ADR_RAP 1 -#define STAT_RW_WRITE 0 /* Bit 1 of ctrl register read back */ -#define STAT_RW_READ 2 -#define STAT_RESET_ON 0 /* Bit 3 of ctrl register read back */ -#define STAT_RESET_OFF 8 -#define STAT_IRQ_ACT 0 /* interrupt pending */ -#define STAT_IRQ_NOACT 16 /* no interrupt pending */ -#define STAT_IO_NOBUSY 0 /* no transfer busy */ -#define STAT_IO_BUSY 32 /* transfer busy */ - -/* I/O command register bits */ - -#define IOCMD_GO 128 /* Bit 7 = 1 -> start register xfer */ - -/* LANCE registers */ - -#define LANCE_CSR0 0 /* Status/Control */ - -#define CSR0_ERR 0x8000 /* general error flag */ -#define CSR0_BABL 0x4000 /* transmitter timeout */ -#define CSR0_CERR 0x2000 /* collision error */ -#define CSR0_MISS 0x1000 /* lost Rx block */ -#define CSR0_MERR 0x0800 /* memory access error */ -#define CSR0_RINT 0x0400 /* receiver interrupt */ -#define CSR0_TINT 0x0200 /* transmitter interrupt */ -#define CSR0_IDON 0x0100 /* initialization done */ -#define CSR0_INTR 0x0080 /* general interrupt flag */ -#define CSR0_INEA 0x0040 /* interrupt enable */ -#define CSR0_RXON 0x0020 /* receiver enabled */ -#define CSR0_TXON 0x0010 /* transmitter enabled */ -#define CSR0_TDMD 0x0008 /* force transmission now */ -#define CSR0_STOP 0x0004 /* stop LANCE */ -#define CSR0_STRT 0x0002 /* start LANCE */ -#define CSR0_INIT 0x0001 /* read initialization block */ - -#define LANCE_CSR1 1 /* addr bit 0..15 of initialization */ -#define LANCE_CSR2 2 /* 16..23 block */ - -#define LANCE_CSR3 3 /* Bus control */ -#define CSR3_BCON_HOLD 0 /* Bit 0 = 0 -> BM1,BM0,HOLD */ -#define CSR3_BCON_BUSRQ 1 /* Bit 0 = 1 -> BUSAK0,BYTE,BUSRQ */ -#define CSR3_ALE_HIGH 0 /* Bit 1 = 0 -> ALE asserted high */ -#define CSR3_ALE_LOW 2 /* Bit 1 = 1 -> ALE asserted low */ -#define CSR3_BSWAP_OFF 0 /* Bit 2 = 0 -> no byte swap */ -#define CSR3_BSWAP_ON 4 /* Bit 2 = 1 -> byte swap */ - -/* LANCE structures */ - -typedef struct { /* LANCE initialization block */ - u16 Mode; /* mode flags */ - u8 PAdr[6]; /* MAC address */ - u8 LAdrF[8]; /* Multicast filter */ - u32 RdrP; /* Receive descriptor */ - u32 TdrP; /* Transmit descriptor */ -} LANCE_InitBlock; - -/* Mode flags init block */ - -#define LANCE_INIT_PROM 0x8000 /* enable promiscous mode */ -#define LANCE_INIT_INTL 0x0040 /* internal loopback */ -#define LANCE_INIT_DRTY 0x0020 /* disable retry */ -#define LANCE_INIT_COLL 0x0010 /* force collision */ -#define LANCE_INIT_DTCR 0x0008 /* disable transmit CRC */ -#define LANCE_INIT_LOOP 0x0004 /* loopback */ -#define LANCE_INIT_DTX 0x0002 /* disable transmitter */ -#define LANCE_INIT_DRX 0x0001 /* disable receiver */ - -typedef struct { /* LANCE Tx descriptor */ - u16 LowAddr; /* bit 0..15 of address */ - u16 Flags; /* bit 16..23 of address + Flags */ - u16 Len; /* 2s complement of packet length */ - u16 Status; /* Result of transmission */ -} LANCE_TxDescr; - -#define TXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */ -#define TXDSCR_FLAGS_ERR 0x4000 /* summary error flag */ -#define TXDSCR_FLAGS_MORE 0x1000 /* more than one retry needed? */ -#define TXDSCR_FLAGS_ONE 0x0800 /* one retry? */ -#define TXDSCR_FLAGS_DEF 0x0400 /* transmission deferred? */ -#define TXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */ -#define TXDSCR_FLAGS_ENP 0x0100 /* last packet in chain? */ - -#define TXDSCR_STATUS_BUFF 0x8000 /* buffer error? */ -#define TXDSCR_STATUS_UFLO 0x4000 /* silo underflow during transmit? */ -#define TXDSCR_STATUS_LCOL 0x1000 /* late collision? */ -#define TXDSCR_STATUS_LCAR 0x0800 /* loss of carrier? */ -#define TXDSCR_STATUS_RTRY 0x0400 /* retry error? */ - -typedef struct { /* LANCE Rx descriptor */ - u16 LowAddr; /* bit 0..15 of address */ - u16 Flags; /* bit 16..23 of address + Flags */ - u16 MaxLen; /* 2s complement of buffer length */ - u16 Len; /* packet length */ -} LANCE_RxDescr; - -#define RXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */ -#define RXDSCR_FLAGS_ERR 0x4000 /* summary error flag */ -#define RXDSCR_FLAGS_FRAM 0x2000 /* framing error flag */ -#define RXDSCR_FLAGS_OFLO 0x1000 /* FIFO overflow? */ -#define RXDSCR_FLAGS_CRC 0x0800 /* CRC error? */ -#define RXDSCR_FLAGS_BUFF 0x0400 /* buffer error? */ -#define RXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */ -#define RXDCSR_FLAGS_ENP 0x0100 /* last packet in chain? */ - -/* RAM layout */ - -#define TXCOUNT 4 /* length of TX descriptor queue */ -#define LTXCOUNT 2 /* log2 of it */ -#define RXCOUNT 4 /* length of RX descriptor queue */ -#define LRXCOUNT 2 /* log2 of it */ - -#define RAM_INITBASE 0 /* LANCE init block */ -#define RAM_TXBASE 24 /* Start of TX descriptor queue */ -#define RAM_RXBASE \ -(RAM_TXBASE + (TXCOUNT * 8)) /* Start of RX descriptor queue */ -#define RAM_DATABASE \ -(RAM_RXBASE + (RXCOUNT * 8)) /* Start of data area for frames */ -#define RAM_BUFSIZE 1580 /* max. frame size - should never be - reached */ - -#endif /* _SK_MCA_DRIVER_ */ - -#endif /* _SK_MCA_INCLUDE_ */ diff --git a/drivers/net/skfp/can.c b/drivers/net/skfp/can.c deleted file mode 100644 index 8a49abce7961..000000000000 --- a/drivers/net/skfp/can.c +++ /dev/null @@ -1,83 +0,0 @@ -/****************************************************************************** - * - * (C)Copyright 1998,1999 SysKonnect, - * a business unit of Schneider & Koch & Co. Datensysteme GmbH. - * - * See the file "skfddi.c" for further information. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * The information in this file is provided "AS IS" without warranty. - * - ******************************************************************************/ - -#ifndef lint -static const char xID_sccs[] = "@(#)can.c 1.5 97/04/07 (C) SK " ; -#endif - -/* - * canonical bit order - */ -const u_char canonical[256] = { - 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0, - 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, - 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8, - 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, - 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4, - 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, - 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec, - 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, - 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2, - 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, - 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea, - 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, - 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6, - 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, - 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee, - 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, - 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1, - 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, - 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9, - 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, - 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5, - 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, - 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed, - 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, - 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3, - 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, - 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb, - 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, - 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7, - 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, - 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef, - 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff -} ; - -#ifdef MAKE_TABLE -int byte_reverse(x) -int x ; -{ - int y = 0 ; - - if (x & 0x01) - y |= 0x80 ; - if (x & 0x02) - y |= 0x40 ; - if (x & 0x04) - y |= 0x20 ; - if (x & 0x08) - y |= 0x10 ; - if (x & 0x10) - y |= 0x08 ; - if (x & 0x20) - y |= 0x04 ; - if (x & 0x40) - y |= 0x02 ; - if (x & 0x80) - y |= 0x01 ; - return(y) ; -} -#endif diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c index 5b475833f645..4fe624b0dd25 100644 --- a/drivers/net/skfp/drvfbi.c +++ b/drivers/net/skfp/drvfbi.c @@ -23,6 +23,7 @@ #include "h/smc.h" #include "h/supern_2.h" #include "h/skfbiinc.h" +#include #ifndef lint static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ; @@ -445,16 +446,14 @@ void read_address(struct s_smc *smc, u_char *mac_addr) char PmdType ; int i ; - extern const u_char canonical[256] ; - #if (defined(ISA) || defined(MCA)) for (i = 0; i < 4 ;i++) { /* read mac address from board */ smc->hw.fddi_phys_addr.a[i] = - canonical[(inpw(PR_A(i+SA_MAC))&0xff)] ; + bitrev8(inpw(PR_A(i+SA_MAC))); } for (i = 4; i < 6; i++) { smc->hw.fddi_phys_addr.a[i] = - canonical[(inpw(PR_A(i+SA_MAC+PRA_OFF))&0xff)] ; + bitrev8(inpw(PR_A(i+SA_MAC+PRA_OFF))); } #endif #ifdef EISA @@ -464,17 +463,17 @@ void read_address(struct s_smc *smc, u_char *mac_addr) */ for (i = 0; i < 4 ;i++) { /* read mac address from board */ smc->hw.fddi_phys_addr.a[i] = - canonical[inp(PR_A(i+SA_MAC))] ; + bitrev8(inp(PR_A(i+SA_MAC))); } for (i = 4; i < 6; i++) { smc->hw.fddi_phys_addr.a[i] = - canonical[inp(PR_A(i+SA_MAC+PRA_OFF))] ; + bitrev8(inp(PR_A(i+SA_MAC+PRA_OFF))); } #endif #ifdef PCI for (i = 0; i < 6; i++) { /* read mac address from board */ smc->hw.fddi_phys_addr.a[i] = - canonical[inp(ADDR(B2_MAC_0+i))] ; + bitrev8(inp(ADDR(B2_MAC_0+i))); } #endif #ifndef PCI @@ -493,7 +492,7 @@ void read_address(struct s_smc *smc, u_char *mac_addr) if (mac_addr) { for (i = 0; i < 6 ;i++) { smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ; - smc->hw.fddi_home_addr.a[i] = canonical[mac_addr[i]] ; + smc->hw.fddi_home_addr.a[i] = bitrev8(mac_addr[i]); } return ; } @@ -501,7 +500,7 @@ void read_address(struct s_smc *smc, u_char *mac_addr) for (i = 0; i < 6 ;i++) { smc->hw.fddi_canon_addr.a[i] = - canonical[smc->hw.fddi_phys_addr.a[i]] ; + bitrev8(smc->hw.fddi_phys_addr.a[i]); } } @@ -1269,11 +1268,8 @@ void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr) { int i ; - extern const u_char canonical[256] ; - - for (i = 0 ; i < 6 ; i++) { - bia_addr->a[i] = canonical[smc->hw.fddi_phys_addr.a[i]] ; - } + for (i = 0 ; i < 6 ; i++) + bia_addr->a[i] = bitrev8(smc->hw.fddi_phys_addr.a[i]); } void smt_start_watchdog(struct s_smc *smc) diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c index 0784f558ca9a..a45205da8033 100644 --- a/drivers/net/skfp/fplustm.c +++ b/drivers/net/skfp/fplustm.c @@ -22,7 +22,7 @@ #include "h/fddi.h" #include "h/smc.h" #include "h/supern_2.h" -#include "can.c" +#include #ifndef lint static const char ID_sccs[] = "@(#)fplustm.c 1.32 99/02/23 (C) SK " ; @@ -1073,7 +1073,7 @@ static struct s_fpmc* mac_get_mc_table(struct s_smc *smc, if (can) { p = own->a ; for (i = 0 ; i < 6 ; i++, p++) - *p = canonical[*p] ; + *p = bitrev8(*p); } slot = NULL; for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){ diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c index 99a776a51fb5..fe847800acdc 100644 --- a/drivers/net/skfp/smt.c +++ b/drivers/net/skfp/smt.c @@ -18,6 +18,7 @@ #include "h/fddi.h" #include "h/smc.h" #include "h/smt_p.h" +#include #define KERNEL #include "h/smtstate.h" @@ -26,8 +27,6 @@ static const char ID_sccs[] = "@(#)smt.c 2.43 98/11/23 (C) SK " ; #endif -extern const u_char canonical[256] ; - /* * FC in SMbuf */ @@ -180,7 +179,7 @@ void smt_agent_init(struct s_smc *smc) driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ; for (i = 0 ; i < 6 ; i ++) { smc->mib.fddiSMTStationId.sid_node.a[i] = - canonical[smc->mib.fddiSMTStationId.sid_node.a[i]] ; + bitrev8(smc->mib.fddiSMTStationId.sid_node.a[i]); } smc->mib.fddiSMTManufacturerData[0] = smc->mib.fddiSMTStationId.sid_node.a[0] ; @@ -2049,9 +2048,8 @@ static void hwm_conv_can(struct s_smc *smc, char *data, int len) SK_UNUSED(smc) ; - for (i = len; i ; i--, data++) { - *data = canonical[*(u_char *)data] ; - } + for (i = len; i ; i--, data++) + *data = bitrev8(*data); } #endif diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 45283f3f95e4..e482e7fcbb2b 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -42,7 +42,7 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "1.9" +#define DRV_VERSION "1.10" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 @@ -132,18 +132,93 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs, } /* Wake on Lan only supported on Yukon chips with rev 1 or above */ -static int wol_supported(const struct skge_hw *hw) +static u32 wol_supported(const struct skge_hw *hw) { - return !((hw->chip_id == CHIP_ID_GENESIS || - (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0))); + if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev != 0) + return WAKE_MAGIC | WAKE_PHY; + else + return 0; +} + +static u32 pci_wake_enabled(struct pci_dev *dev) +{ + int pm = pci_find_capability(dev, PCI_CAP_ID_PM); + u16 value; + + /* If device doesn't support PM Capabilities, but request is to disable + * wake events, it's a nop; otherwise fail */ + if (!pm) + return 0; + + pci_read_config_word(dev, pm + PCI_PM_PMC, &value); + + value &= PCI_PM_CAP_PME_MASK; + value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */ + + return value != 0; +} + +static void skge_wol_init(struct skge_port *skge) +{ + struct skge_hw *hw = skge->hw; + int port = skge->port; + enum pause_control save_mode; + u32 ctrl; + + /* Bring hardware out of reset */ + skge_write16(hw, B0_CTST, CS_RST_CLR); + skge_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR); + + skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR); + skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR); + + /* Force to 10/100 skge_reset will re-enable on resume */ + save_mode = skge->flow_control; + skge->flow_control = FLOW_MODE_SYMMETRIC; + + ctrl = skge->advertising; + skge->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full); + + skge_phy_reset(skge); + + skge->flow_control = save_mode; + skge->advertising = ctrl; + + /* Set GMAC to no flow control and auto update for speed/duplex */ + gma_write16(hw, port, GM_GP_CTRL, + GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA| + GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS); + + /* Set WOL address */ + memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR), + skge->netdev->dev_addr, ETH_ALEN); + + /* Turn on appropriate WOL control bits */ + skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT); + ctrl = 0; + if (skge->wol & WAKE_PHY) + ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT; + else + ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT; + + if (skge->wol & WAKE_MAGIC) + ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT; + else + ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;; + + ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT; + skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl); + + /* block receiver */ + skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); } static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct skge_port *skge = netdev_priv(dev); - wol->supported = wol_supported(skge->hw) ? WAKE_MAGIC : 0; - wol->wolopts = skge->wol ? WAKE_MAGIC : 0; + wol->supported = wol_supported(skge->hw); + wol->wolopts = skge->wol; } static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) @@ -151,23 +226,12 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; - if (wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) + if (wol->wolopts & wol_supported(hw)) return -EOPNOTSUPP; - if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw)) - return -EOPNOTSUPP; - - skge->wol = wol->wolopts == WAKE_MAGIC; - - if (skge->wol) { - memcpy_toio(hw->regs + WOL_MAC_ADDR, dev->dev_addr, ETH_ALEN); - - skge_write16(hw, WOL_CTRL_STAT, - WOL_CTL_ENA_PME_ON_MAGIC_PKT | - WOL_CTL_ENA_MAGIC_PKT_UNIT); - } else - skge_write16(hw, WOL_CTRL_STAT, WOL_CTL_DEFAULT); - + skge->wol = wol->wolopts; + if (!netif_running(dev)) + skge_wol_init(skge); return 0; } @@ -2373,6 +2437,9 @@ static int skge_up(struct net_device *dev) size_t rx_size, tx_size; int err; + if (!is_valid_ether_addr(dev->dev_addr)) + return -EINVAL; + if (netif_msg_ifup(skge)) printk(KERN_INFO PFX "%s: enabling interface\n", dev->name); @@ -2392,7 +2459,7 @@ static int skge_up(struct net_device *dev) BUG_ON(skge->dma & 7); if ((u64)skge->dma >> 32 != ((u64) skge->dma + skge->mem_size) >> 32) { - printk(KERN_ERR PFX "pci_alloc_consistent region crosses 4G boundary\n"); + dev_err(&hw->pdev->dev, "pci_alloc_consistent region crosses 4G boundary\n"); err = -EINVAL; goto free_pci_mem; } @@ -3001,6 +3068,7 @@ static void skge_mac_intr(struct skge_hw *hw, int port) /* Handle device specific framing and timeout interrupts */ static void skge_error_irq(struct skge_hw *hw) { + struct pci_dev *pdev = hw->pdev; u32 hwstatus = skge_read32(hw, B0_HWE_ISRC); if (hw->chip_id == CHIP_ID_GENESIS) { @@ -3016,12 +3084,12 @@ static void skge_error_irq(struct skge_hw *hw) } if (hwstatus & IS_RAM_RD_PAR) { - printk(KERN_ERR PFX "Ram read data parity error\n"); + dev_err(&pdev->dev, "Ram read data parity error\n"); skge_write16(hw, B3_RI_CTRL, RI_CLR_RD_PERR); } if (hwstatus & IS_RAM_WR_PAR) { - printk(KERN_ERR PFX "Ram write data parity error\n"); + dev_err(&pdev->dev, "Ram write data parity error\n"); skge_write16(hw, B3_RI_CTRL, RI_CLR_WR_PERR); } @@ -3032,38 +3100,38 @@ static void skge_error_irq(struct skge_hw *hw) skge_mac_parity(hw, 1); if (hwstatus & IS_R1_PAR_ERR) { - printk(KERN_ERR PFX "%s: receive queue parity error\n", - hw->dev[0]->name); + dev_err(&pdev->dev, "%s: receive queue parity error\n", + hw->dev[0]->name); skge_write32(hw, B0_R1_CSR, CSR_IRQ_CL_P); } if (hwstatus & IS_R2_PAR_ERR) { - printk(KERN_ERR PFX "%s: receive queue parity error\n", - hw->dev[1]->name); + dev_err(&pdev->dev, "%s: receive queue parity error\n", + hw->dev[1]->name); skge_write32(hw, B0_R2_CSR, CSR_IRQ_CL_P); } if (hwstatus & (IS_IRQ_MST_ERR|IS_IRQ_STAT)) { u16 pci_status, pci_cmd; - pci_read_config_word(hw->pdev, PCI_COMMAND, &pci_cmd); - pci_read_config_word(hw->pdev, PCI_STATUS, &pci_status); + pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); + pci_read_config_word(pdev, PCI_STATUS, &pci_status); - printk(KERN_ERR PFX "%s: PCI error cmd=%#x status=%#x\n", - pci_name(hw->pdev), pci_cmd, pci_status); + dev_err(&pdev->dev, "PCI error cmd=%#x status=%#x\n", + pci_cmd, pci_status); /* Write the error bits back to clear them. */ pci_status &= PCI_STATUS_ERROR_BITS; skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); - pci_write_config_word(hw->pdev, PCI_COMMAND, + pci_write_config_word(pdev, PCI_COMMAND, pci_cmd | PCI_COMMAND_SERR | PCI_COMMAND_PARITY); - pci_write_config_word(hw->pdev, PCI_STATUS, pci_status); + pci_write_config_word(pdev, PCI_STATUS, pci_status); skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); /* if error still set then just ignore it */ hwstatus = skge_read32(hw, B0_HWE_ISRC); if (hwstatus & IS_IRQ_STAT) { - printk(KERN_INFO PFX "unable to clear error (so ignoring them)\n"); + dev_warn(&hw->pdev->dev, "unable to clear error (so ignoring them)\n"); hw->intr_mask &= ~IS_HW_ERR; } } @@ -3277,8 +3345,8 @@ static int skge_reset(struct skge_hw *hw) hw->phy_addr = PHY_ADDR_BCOM; break; default: - printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n", - pci_name(hw->pdev), hw->phy_type); + dev_err(&hw->pdev->dev, "unsupported phy type 0x%x\n", + hw->phy_type); return -EOPNOTSUPP; } break; @@ -3293,8 +3361,8 @@ static int skge_reset(struct skge_hw *hw) break; default: - printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n", - pci_name(hw->pdev), hw->chip_id); + dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n", + hw->chip_id); return -EOPNOTSUPP; } @@ -3334,7 +3402,7 @@ static int skge_reset(struct skge_hw *hw) /* avoid boards with stuck Hardware error bits */ if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) && (skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) { - printk(KERN_WARNING PFX "stuck hardware sensor bit\n"); + dev_warn(&hw->pdev->dev, "stuck hardware sensor bit\n"); hw->intr_mask &= ~IS_HW_ERR; } @@ -3408,7 +3476,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, struct net_device *dev = alloc_etherdev(sizeof(*skge)); if (!dev) { - printk(KERN_ERR "skge etherdev alloc failed"); + dev_err(&hw->pdev->dev, "etherdev alloc failed\n"); return NULL; } @@ -3452,6 +3520,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, skge->duplex = -1; skge->speed = -1; skge->advertising = skge_supported_modes(hw); + skge->wol = pci_wake_enabled(hw->pdev) ? wol_supported(hw) : 0; hw->dev[port] = dev; @@ -3496,15 +3565,13 @@ static int __devinit skge_probe(struct pci_dev *pdev, err = pci_enable_device(pdev); if (err) { - printk(KERN_ERR PFX "%s cannot enable PCI device\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot enable PCI device\n"); goto err_out; } err = pci_request_regions(pdev, DRV_NAME); if (err) { - printk(KERN_ERR PFX "%s cannot obtain PCI resources\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot obtain PCI resources\n"); goto err_out_disable_pdev; } @@ -3519,8 +3586,7 @@ static int __devinit skge_probe(struct pci_dev *pdev, } if (err) { - printk(KERN_ERR PFX "%s no usable DMA configuration\n", - pci_name(pdev)); + dev_err(&pdev->dev, "no usable DMA configuration\n"); goto err_out_free_regions; } @@ -3538,8 +3604,7 @@ static int __devinit skge_probe(struct pci_dev *pdev, err = -ENOMEM; hw = kzalloc(sizeof(*hw), GFP_KERNEL); if (!hw) { - printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot allocate hardware struct\n"); goto err_out_free_regions; } @@ -3550,8 +3615,7 @@ static int __devinit skge_probe(struct pci_dev *pdev, hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); if (!hw->regs) { - printk(KERN_ERR PFX "%s: cannot map device registers\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot map device registers\n"); goto err_out_free_hw; } @@ -3567,23 +3631,19 @@ static int __devinit skge_probe(struct pci_dev *pdev, if (!dev) goto err_out_led_off; - if (!is_valid_ether_addr(dev->dev_addr)) { - printk(KERN_ERR PFX "%s: bad (zero?) ethernet address in rom\n", - pci_name(pdev)); - err = -EIO; - goto err_out_free_netdev; - } + /* Some motherboards are broken and has zero in ROM. */ + if (!is_valid_ether_addr(dev->dev_addr)) + dev_warn(&pdev->dev, "bad (zero?) ethernet address in rom\n"); err = register_netdev(dev); if (err) { - printk(KERN_ERR PFX "%s: cannot register net device\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot register net device\n"); goto err_out_free_netdev; } err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, dev->name, hw); if (err) { - printk(KERN_ERR PFX "%s: cannot assign irq %d\n", + dev_err(&pdev->dev, "%s: cannot assign irq %d\n", dev->name, pdev->irq); goto err_out_unregister; } @@ -3594,7 +3654,7 @@ static int __devinit skge_probe(struct pci_dev *pdev, skge_show_addr(dev1); else { /* Failure to register second port need not be fatal */ - printk(KERN_WARNING PFX "register of second port failed\n"); + dev_warn(&pdev->dev, "register of second port failed\n"); hw->dev[1] = NULL; free_netdev(dev1); } @@ -3659,28 +3719,46 @@ static void __devexit skge_remove(struct pci_dev *pdev) } #ifdef CONFIG_PM +static int vaux_avail(struct pci_dev *pdev) +{ + int pm_cap; + + pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (pm_cap) { + u16 ctl; + pci_read_config_word(pdev, pm_cap + PCI_PM_PMC, &ctl); + if (ctl & PCI_PM_CAP_AUX_POWER) + return 1; + } + return 0; +} + + static int skge_suspend(struct pci_dev *pdev, pm_message_t state) { struct skge_hw *hw = pci_get_drvdata(pdev); - int i, wol = 0; + int i, err, wol = 0; + + err = pci_save_state(pdev); + if (err) + return err; - pci_save_state(pdev); for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; + struct skge_port *skge = netdev_priv(dev); - if (netif_running(dev)) { - struct skge_port *skge = netdev_priv(dev); + if (netif_running(dev)) + skge_down(dev); + if (skge->wol) + skge_wol_init(skge); - netif_carrier_off(dev); - if (skge->wol) - netif_stop_queue(dev); - else - skge_down(dev); - wol |= skge->wol; - } - netif_device_detach(dev); + wol |= skge->wol; } + if (wol && vaux_avail(pdev)) + skge_write8(hw, B0_POWER_CTRL, + PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF); + skge_write32(hw, B0_IMSK, 0); pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); pci_set_power_state(pdev, pci_choose_state(pdev, state)); @@ -3693,8 +3771,14 @@ static int skge_resume(struct pci_dev *pdev) struct skge_hw *hw = pci_get_drvdata(pdev); int i, err; - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); + err = pci_set_power_state(pdev, PCI_D0); + if (err) + goto out; + + err = pci_restore_state(pdev); + if (err) + goto out; + pci_enable_wake(pdev, PCI_D0, 0); err = skge_reset(hw); @@ -3704,7 +3788,6 @@ static int skge_resume(struct pci_dev *pdev) for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; - netif_device_attach(dev); if (netif_running(dev)) { err = skge_up(dev); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index f6223c533c01..17b1b479dff5 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -876,11 +876,13 @@ enum { WOL_PATT_CNT_0 = 0x0f38,/* 32 bit WOL Pattern Counter 3..0 */ WOL_PATT_CNT_4 = 0x0f3c,/* 24 bit WOL Pattern Counter 6..4 */ }; +#define WOL_REGS(port, x) (x + (port)*0x80) enum { WOL_PATT_RAM_1 = 0x1000,/* WOL Pattern RAM Link 1 */ WOL_PATT_RAM_2 = 0x1400,/* WOL Pattern RAM Link 2 */ }; +#define WOL_PATT_RAM_BASE(port) (WOL_PATT_RAM_1 + (port)*0x400) enum { BASE_XMAC_1 = 0x2000,/* XMAC 1 registers */ diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 822dd0b13133..f2ab3d56e565 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -49,7 +49,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.10" +#define DRV_VERSION "1.12" #define PFX DRV_NAME " " /* @@ -105,6 +105,7 @@ static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, /* DGE-560T */ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4001) }, /* DGE-550SX */ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B02) }, /* DGE-560SX */ + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B03) }, /* DGE-550T */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) }, /* 88E8021 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) }, /* 88E8022 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) }, /* 88E8061 */ @@ -126,6 +127,9 @@ static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) }, /* 88EC042 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */ { 0 } }; @@ -140,7 +144,7 @@ static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 }; static const char *yukon2_name[] = { "XL", /* 0xb3 */ "EC Ultra", /* 0xb4 */ - "UNKNOWN", /* 0xb5 */ + "Extreme", /* 0xb5 */ "EC", /* 0xb6 */ "FE", /* 0xb7 */ }; @@ -192,76 +196,52 @@ static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg) return v; } -static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state) + +static void sky2_power_on(struct sky2_hw *hw) { - u16 power_control; - int vaux; + /* switch power to VCC (WA for VAUX problem) */ + sky2_write8(hw, B0_POWER_CTRL, + PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON); - pr_debug("sky2_set_power_state %d\n", state); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); + /* disable Core Clock Division, */ + sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS); - power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_PMC); - vaux = (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) && - (power_control & PCI_PM_CAP_PME_D3cold); + if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) + /* enable bits are inverted */ + sky2_write8(hw, B2_Y2_CLK_GATE, + Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS | + Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | + Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS); + else + sky2_write8(hw, B2_Y2_CLK_GATE, 0); - power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL); + if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) { + u32 reg1; - power_control |= PCI_PM_CTRL_PME_STATUS; - power_control &= ~(PCI_PM_CTRL_STATE_MASK); - - switch (state) { - case PCI_D0: - /* switch power to VCC (WA for VAUX problem) */ - sky2_write8(hw, B0_POWER_CTRL, - PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON); - - /* disable Core Clock Division, */ - sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS); - - if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) - /* enable bits are inverted */ - sky2_write8(hw, B2_Y2_CLK_GATE, - Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS | - Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | - Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS); - else - sky2_write8(hw, B2_Y2_CLK_GATE, 0); - - if (hw->chip_id == CHIP_ID_YUKON_EC_U) { - u32 reg1; - - sky2_pci_write32(hw, PCI_DEV_REG3, 0); - reg1 = sky2_pci_read32(hw, PCI_DEV_REG4); - reg1 &= P_ASPM_CONTROL_MSK; - sky2_pci_write32(hw, PCI_DEV_REG4, reg1); - sky2_pci_write32(hw, PCI_DEV_REG5, 0); - } - - break; - - case PCI_D3hot: - case PCI_D3cold: - if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) - sky2_write8(hw, B2_Y2_CLK_GATE, 0); - else - /* enable bits are inverted */ - sky2_write8(hw, B2_Y2_CLK_GATE, - Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS | - Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | - Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS); - - /* switch power to VAUX */ - if (vaux && state != PCI_D3cold) - sky2_write8(hw, B0_POWER_CTRL, - (PC_VAUX_ENA | PC_VCC_ENA | - PC_VAUX_ON | PC_VCC_OFF)); - break; - default: - printk(KERN_ERR PFX "Unknown power state %d\n", state); + sky2_pci_write32(hw, PCI_DEV_REG3, 0); + reg1 = sky2_pci_read32(hw, PCI_DEV_REG4); + reg1 &= P_ASPM_CONTROL_MSK; + sky2_pci_write32(hw, PCI_DEV_REG4, reg1); + sky2_pci_write32(hw, PCI_DEV_REG5, 0); } +} - sky2_pci_write16(hw, hw->pm_cap + PCI_PM_CTRL, power_control); - sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); +static void sky2_power_aux(struct sky2_hw *hw) +{ + if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) + sky2_write8(hw, B2_Y2_CLK_GATE, 0); + else + /* enable bits are inverted */ + sky2_write8(hw, B2_Y2_CLK_GATE, + Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS | + Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | + Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS); + + /* switch power to VAUX */ + if (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) + sky2_write8(hw, B0_POWER_CTRL, + (PC_VAUX_ENA | PC_VCC_ENA | + PC_VAUX_ON | PC_VCC_OFF)); } static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port) @@ -313,8 +293,10 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) struct sky2_port *sky2 = netdev_priv(hw->dev[port]); u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg; - if (sky2->autoneg == AUTONEG_ENABLE && - !(hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) { + if (sky2->autoneg == AUTONEG_ENABLE + && !(hw->chip_id == CHIP_ID_YUKON_XL + || hw->chip_id == CHIP_ID_YUKON_EC_U + || hw->chip_id == CHIP_ID_YUKON_EX)) { u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK | @@ -341,8 +323,10 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* enable automatic crossover */ ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO); - if (sky2->autoneg == AUTONEG_ENABLE && - (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) { + if (sky2->autoneg == AUTONEG_ENABLE + && (hw->chip_id == CHIP_ID_YUKON_XL + || hw->chip_id == CHIP_ID_YUKON_EC_U + || hw->chip_id == CHIP_ID_YUKON_EX)) { ctrl &= ~PHY_M_PC_DSC_MSK; ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA; } @@ -497,7 +481,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* restore page register */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); break; + case CHIP_ID_YUKON_EC_U: + case CHIP_ID_YUKON_EX: pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); /* select page 3 to access LED control register */ @@ -539,7 +525,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* set page register to 0 */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg); - } else { + } else if (hw->chip_id != CHIP_ID_YUKON_EX) { gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { @@ -591,6 +577,73 @@ static void sky2_phy_reinit(struct sky2_port *sky2) spin_unlock_bh(&sky2->phy_lock); } +/* Put device in state to listen for Wake On Lan */ +static void sky2_wol_init(struct sky2_port *sky2) +{ + struct sky2_hw *hw = sky2->hw; + unsigned port = sky2->port; + enum flow_control save_mode; + u16 ctrl; + u32 reg1; + + /* Bring hardware out of reset */ + sky2_write16(hw, B0_CTST, CS_RST_CLR); + sky2_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR); + + sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR); + sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR); + + /* Force to 10/100 + * sky2_reset will re-enable on resume + */ + save_mode = sky2->flow_mode; + ctrl = sky2->advertising; + + sky2->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full); + sky2->flow_mode = FC_NONE; + sky2_phy_power(hw, port, 1); + sky2_phy_reinit(sky2); + + sky2->flow_mode = save_mode; + sky2->advertising = ctrl; + + /* Set GMAC to no flow control and auto update for speed/duplex */ + gma_write16(hw, port, GM_GP_CTRL, + GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA| + GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS); + + /* Set WOL address */ + memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR), + sky2->netdev->dev_addr, ETH_ALEN); + + /* Turn on appropriate WOL control bits */ + sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT); + ctrl = 0; + if (sky2->wol & WAKE_PHY) + ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT; + else + ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT; + + if (sky2->wol & WAKE_MAGIC) + ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT; + else + ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;; + + ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT; + sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl); + + /* Turn on legacy PCI-Express PME mode */ + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); + reg1 = sky2_pci_read32(hw, PCI_DEV_REG1); + reg1 |= PCI_Y2_PME_LEGACY; + sky2_pci_write32(hw, PCI_DEV_REG1, reg1); + sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); + + /* block receiver */ + sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); + +} + static void sky2_mac_init(struct sky2_hw *hw, unsigned port) { struct sky2_port *sky2 = netdev_priv(hw->dev[port]); @@ -684,7 +737,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); - if (hw->chip_id == CHIP_ID_YUKON_EC_U) { + if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) { sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8); sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8); if (hw->dev[port]->mtu > ETH_DATA_LEN) { @@ -1467,6 +1520,9 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) if (unlikely(netif_msg_tx_done(sky2))) printk(KERN_DEBUG "%s: tx done %u\n", dev->name, idx); + sky2->net_stats.tx_packets++; + sky2->net_stats.tx_bytes += re->skb->len; + dev_kfree_skb_any(re->skb); } @@ -1641,7 +1697,9 @@ static void sky2_link_up(struct sky2_port *sky2) sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF); - if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) { + if (hw->chip_id == CHIP_ID_YUKON_XL + || hw->chip_id == CHIP_ID_YUKON_EC_U + || hw->chip_id == CHIP_ID_YUKON_EX) { u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */ @@ -1734,14 +1792,16 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF; /* Pause bits are offset (9..8) */ - if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) + if (hw->chip_id == CHIP_ID_YUKON_XL + || hw->chip_id == CHIP_ID_YUKON_EC_U + || hw->chip_id == CHIP_ID_YUKON_EX) aux >>= 6; sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN, aux & PHY_M_PS_TX_P_EN); if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000 - && hw->chip_id != CHIP_ID_YUKON_EC_U) + && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)) sky2->flow_status = FC_NONE; if (aux & PHY_M_PS_RX_P_EN) @@ -1794,48 +1854,37 @@ out: } -/* Transmit timeout is only called if we are running, carries is up +/* Transmit timeout is only called if we are running, carrier is up * and tx queue is full (stopped). + * Called with netif_tx_lock held. */ static void sky2_tx_timeout(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; - unsigned txq = txqaddr[sky2->port]; - u16 report, done; + u32 imask; if (netif_msg_timer(sky2)) printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); - report = sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX); - done = sky2_read16(hw, Q_ADDR(txq, Q_DONE)); - printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n", - dev->name, - sky2->tx_cons, sky2->tx_prod, report, done); + dev->name, sky2->tx_cons, sky2->tx_prod, + sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX), + sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE))); - if (report != done) { - printk(KERN_INFO PFX "status burst pending (irq moderation?)\n"); + imask = sky2_read32(hw, B0_IMSK); /* block IRQ in hw */ + sky2_write32(hw, B0_IMSK, 0); + sky2_read32(hw, B0_IMSK); - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); - } else if (report != sky2->tx_cons) { - printk(KERN_INFO PFX "status report lost?\n"); + netif_poll_disable(hw->dev[0]); /* stop NAPI poll */ + synchronize_irq(hw->pdev->irq); - netif_tx_lock_bh(dev); - sky2_tx_complete(sky2, report); - netif_tx_unlock_bh(dev); - } else { - printk(KERN_INFO PFX "hardware hung? flushing\n"); + netif_start_queue(dev); /* don't wakeup during flush */ + sky2_tx_complete(sky2, sky2->tx_prod); /* Flush transmit queue */ - sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP); - sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); + sky2_write32(hw, B0_IMSK, imask); - sky2_tx_clean(dev); - - sky2_qset(hw, txq); - sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1); - } + sky2_phy_reinit(sky2); /* this clears flow control etc */ } static int sky2_change_mtu(struct net_device *dev, int new_mtu) @@ -1849,8 +1898,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) return -EINVAL; + /* TSO on Yukon Ultra and MTU > 1500 not supported */ if (hw->chip_id == CHIP_ID_YUKON_EC_U && new_mtu > ETH_DATA_LEN) - return -EINVAL; + dev->features &= ~NETIF_F_TSO; if (!netif_running(dev)) { dev->mtu = new_mtu; @@ -2089,6 +2139,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) goto force_update; skb->protocol = eth_type_trans(skb, dev); + sky2->net_stats.rx_packets++; + sky2->net_stats.rx_bytes += skb->len; dev->last_rx = jiffies; #ifdef SKY2_VLAN_TAG_USED @@ -2218,8 +2270,8 @@ static void sky2_hw_intr(struct sky2_hw *hw) pci_err = sky2_pci_read16(hw, PCI_STATUS); if (net_ratelimit()) - printk(KERN_ERR PFX "%s: pci hw error (0x%x)\n", - pci_name(hw->pdev), pci_err); + dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n", + pci_err); sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); sky2_pci_write16(hw, PCI_STATUS, @@ -2234,8 +2286,8 @@ static void sky2_hw_intr(struct sky2_hw *hw) pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT); if (net_ratelimit()) - printk(KERN_ERR PFX "%s: pci express error (0x%x)\n", - pci_name(hw->pdev), pex_err); + dev_err(&hw->pdev->dev, "PCI Express error (0x%x)\n", + pex_err); /* clear the interrupt */ sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); @@ -2404,6 +2456,7 @@ static inline u32 sky2_mhz(const struct sky2_hw *hw) switch (hw->chip_id) { case CHIP_ID_YUKON_EC: case CHIP_ID_YUKON_EC_U: + case CHIP_ID_YUKON_EX: return 125; /* 125 Mhz */ case CHIP_ID_YUKON_FE: return 100; /* 100 Mhz */ @@ -2423,34 +2476,62 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk) } -static int sky2_reset(struct sky2_hw *hw) +static int __devinit sky2_init(struct sky2_hw *hw) { - u16 status; u8 t8; - int i; sky2_write8(hw, B0_CTST, CS_RST_CLR); hw->chip_id = sky2_read8(hw, B2_CHIP_ID); if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) { - printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n", - pci_name(hw->pdev), hw->chip_id); + dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n", + hw->chip_id); return -EOPNOTSUPP; } + if (hw->chip_id == CHIP_ID_YUKON_EX) + dev_warn(&hw->pdev->dev, "this driver not yet tested on this chip type\n" + "Please report success or failure to \n"); + + /* Make sure and enable all clocks */ + if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U) + sky2_pci_write32(hw, PCI_DEV_REG3, 0); + hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4; /* This rev is really old, and requires untested workarounds */ if (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == CHIP_REV_YU_EC_A1) { - printk(KERN_ERR PFX "%s: unsupported revision Yukon-%s (0x%x) rev %d\n", - pci_name(hw->pdev), yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], - hw->chip_id, hw->chip_rev); + dev_err(&hw->pdev->dev, "unsupported revision Yukon-%s (0x%x) rev %d\n", + yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], + hw->chip_id, hw->chip_rev); return -EOPNOTSUPP; } + hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); + hw->ports = 1; + t8 = sky2_read8(hw, B2_Y2_HW_RES); + if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) { + if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC)) + ++hw->ports; + } + + return 0; +} + +static void sky2_reset(struct sky2_hw *hw) +{ + u16 status; + int i; + /* disable ASF */ if (hw->chip_id <= CHIP_ID_YUKON_EC) { - sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); + if (hw->chip_id == CHIP_ID_YUKON_EX) { + status = sky2_read16(hw, HCU_CCSR); + status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE | + HCU_CCSR_UC_STATE_MSK); + sky2_write16(hw, HCU_CCSR, status); + } else + sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE); } @@ -2472,15 +2553,7 @@ static int sky2_reset(struct sky2_hw *hw) sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); - hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); - hw->ports = 1; - t8 = sky2_read8(hw, B2_Y2_HW_RES); - if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) { - if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC)) - ++hw->ports; - } - - sky2_set_power_state(hw, PCI_D0); + sky2_power_on(hw); for (i = 0; i < hw->ports; i++) { sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET); @@ -2563,7 +2636,37 @@ static int sky2_reset(struct sky2_hw *hw) sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START); sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START); +} +static inline u8 sky2_wol_supported(const struct sky2_hw *hw) +{ + return sky2_is_copper(hw) ? (WAKE_PHY | WAKE_MAGIC) : 0; +} + +static void sky2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + const struct sky2_port *sky2 = netdev_priv(dev); + + wol->supported = sky2_wol_supported(sky2->hw); + wol->wolopts = sky2->wol; +} + +static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_hw *hw = sky2->hw; + + if (wol->wolopts & ~sky2_wol_supported(sky2->hw)) + return -EOPNOTSUPP; + + sky2->wol = wol->wolopts; + + if (hw->chip_id == CHIP_ID_YUKON_EC_U) + sky2_write32(hw, B0_CTST, sky2->wol + ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF); + + if (!netif_running(dev)) + sky2_wol_init(sky2); return 0; } @@ -2814,25 +2917,9 @@ static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data) } } -/* Use hardware MIB variables for critical path statistics and - * transmit feedback not reported at interrupt. - * Other errors are accounted for in interrupt handler. - */ static struct net_device_stats *sky2_get_stats(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); - u64 data[13]; - - sky2_phy_stats(sky2, data, ARRAY_SIZE(data)); - - sky2->net_stats.tx_bytes = data[0]; - sky2->net_stats.rx_bytes = data[1]; - sky2->net_stats.tx_packets = data[2] + data[4] + data[6]; - sky2->net_stats.rx_packets = data[3] + data[5] + data[7]; - sky2->net_stats.multicast = data[3] + data[5]; - sky2->net_stats.collisions = data[10]; - sky2->net_stats.tx_aborted_errors = data[12]; - return &sky2->net_stats; } @@ -3191,7 +3278,9 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs, static const struct ethtool_ops sky2_ethtool_ops = { .get_settings = sky2_get_settings, .set_settings = sky2_set_settings, - .get_drvinfo = sky2_get_drvinfo, + .get_drvinfo = sky2_get_drvinfo, + .get_wol = sky2_get_wol, + .set_wol = sky2_set_wol, .get_msglevel = sky2_get_msglevel, .set_msglevel = sky2_set_msglevel, .nway_reset = sky2_nway_reset, @@ -3221,13 +3310,14 @@ static const struct ethtool_ops sky2_ethtool_ops = { /* Initialize network device */ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, - unsigned port, int highmem) + unsigned port, + int highmem, int wol) { struct sky2_port *sky2; struct net_device *dev = alloc_etherdev(sizeof(*sky2)); if (!dev) { - printk(KERN_ERR "sky2 etherdev alloc failed"); + dev_err(&hw->pdev->dev, "etherdev alloc failed"); return NULL; } @@ -3269,6 +3359,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, sky2->speed = -1; sky2->advertising = sky2_supported_modes(hw); sky2->rx_csum = 1; + sky2->wol = wol; spin_lock_init(&sky2->phy_lock); sky2->tx_pending = TX_DEF_PENDING; @@ -3278,11 +3369,9 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, sky2->port = port; - if (hw->chip_id != CHIP_ID_YUKON_EC_U) - dev->features |= NETIF_F_TSO; + dev->features |= NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_SG; if (highmem) dev->features |= NETIF_F_HIGHDMA; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; #ifdef SKY2_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; @@ -3343,8 +3432,7 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) err = request_irq(pdev->irq, sky2_test_intr, 0, DRV_NAME, hw); if (err) { - printk(KERN_ERR PFX "%s: cannot assign irq %d\n", - pci_name(pdev), pdev->irq); + dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq); return err; } @@ -3355,9 +3443,8 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) if (!hw->msi) { /* MSI test failed, go back to INTx mode */ - printk(KERN_INFO PFX "%s: No interrupt generated using MSI, " - "switching to INTx mode.\n", - pci_name(pdev)); + dev_info(&pdev->dev, "No interrupt generated using MSI, " + "switching to INTx mode.\n"); err = -EOPNOTSUPP; sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ); @@ -3371,62 +3458,62 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) return err; } +static int __devinit pci_wake_enabled(struct pci_dev *dev) +{ + int pm = pci_find_capability(dev, PCI_CAP_ID_PM); + u16 value; + + if (!pm) + return 0; + if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value)) + return 0; + return value & PCI_PM_CTRL_PME_ENABLE; +} + static int __devinit sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct net_device *dev, *dev1 = NULL; + struct net_device *dev; struct sky2_hw *hw; - int err, pm_cap, using_dac = 0; + int err, using_dac = 0, wol_default; err = pci_enable_device(pdev); if (err) { - printk(KERN_ERR PFX "%s cannot enable PCI device\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot enable PCI device\n"); goto err_out; } err = pci_request_regions(pdev, DRV_NAME); if (err) { - printk(KERN_ERR PFX "%s cannot obtain PCI resources\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot obtain PCI resources\n"); goto err_out; } pci_set_master(pdev); - /* Find power-management capability. */ - pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (pm_cap == 0) { - printk(KERN_ERR PFX "Cannot find PowerManagement capability, " - "aborting.\n"); - err = -EIO; - goto err_out_free_regions; - } - if (sizeof(dma_addr_t) > sizeof(u32) && !(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { using_dac = 1; err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); if (err < 0) { - printk(KERN_ERR PFX "%s unable to obtain 64 bit DMA " - "for consistent allocations\n", pci_name(pdev)); + dev_err(&pdev->dev, "unable to obtain 64 bit DMA " + "for consistent allocations\n"); goto err_out_free_regions; } - } else { err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (err) { - printk(KERN_ERR PFX "%s no usable DMA configuration\n", - pci_name(pdev)); + dev_err(&pdev->dev, "no usable DMA configuration\n"); goto err_out_free_regions; } } + wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0; + err = -ENOMEM; hw = kzalloc(sizeof(*hw), GFP_KERNEL); if (!hw) { - printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot allocate hardware struct\n"); goto err_out_free_regions; } @@ -3434,11 +3521,9 @@ static int __devinit sky2_probe(struct pci_dev *pdev, hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); if (!hw->regs) { - printk(KERN_ERR PFX "%s: cannot map device registers\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot map device registers\n"); goto err_out_free_hw; } - hw->pm_cap = pm_cap; #ifdef __BIG_ENDIAN /* The sk98lin vendor driver uses hardware byte swapping but @@ -3458,18 +3543,22 @@ static int __devinit sky2_probe(struct pci_dev *pdev, if (!hw->st_le) goto err_out_iounmap; - err = sky2_reset(hw); + err = sky2_init(hw); if (err) goto err_out_iounmap; - printk(KERN_INFO PFX "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n", + dev_info(&pdev->dev, "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n", DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0), pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], hw->chip_id, hw->chip_rev); - dev = sky2_init_netdev(hw, 0, using_dac); - if (!dev) + sky2_reset(hw); + + dev = sky2_init_netdev(hw, 0, using_dac, wol_default); + if (!dev) { + err = -ENOMEM; goto err_out_free_pci; + } if (!disable_msi && pci_enable_msi(pdev) == 0) { err = sky2_test_msi(hw); @@ -3481,32 +3570,33 @@ static int __devinit sky2_probe(struct pci_dev *pdev, err = register_netdev(dev); if (err) { - printk(KERN_ERR PFX "%s: cannot register net device\n", - pci_name(pdev)); + dev_err(&pdev->dev, "cannot register net device\n"); goto err_out_free_netdev; } err = request_irq(pdev->irq, sky2_intr, hw->msi ? 0 : IRQF_SHARED, dev->name, hw); if (err) { - printk(KERN_ERR PFX "%s: cannot assign irq %d\n", - pci_name(pdev), pdev->irq); + dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq); goto err_out_unregister; } sky2_write32(hw, B0_IMSK, Y2_IS_BASE); sky2_show_addr(dev); - if (hw->ports > 1 && (dev1 = sky2_init_netdev(hw, 1, using_dac))) { - if (register_netdev(dev1) == 0) - sky2_show_addr(dev1); - else { - /* Failure to register second port need not be fatal */ - printk(KERN_WARNING PFX - "register of second port failed\n"); + if (hw->ports > 1) { + struct net_device *dev1; + + dev1 = sky2_init_netdev(hw, 1, using_dac, wol_default); + if (!dev1) + dev_warn(&pdev->dev, "allocation for second device failed\n"); + else if ((err = register_netdev(dev1))) { + dev_warn(&pdev->dev, + "register of second port failed (%d)\n", err); hw->dev[1] = NULL; free_netdev(dev1); - } + } else + sky2_show_addr(dev1); } setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw); @@ -3555,7 +3645,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev) unregister_netdev(dev1); unregister_netdev(dev0); - sky2_set_power_state(hw, PCI_D3hot); + sky2_power_aux(hw); + sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); sky2_write8(hw, B0_CTST, CS_RST_SET); sky2_read8(hw, B0_CTST); @@ -3580,27 +3671,31 @@ static void __devexit sky2_remove(struct pci_dev *pdev) static int sky2_suspend(struct pci_dev *pdev, pm_message_t state) { struct sky2_hw *hw = pci_get_drvdata(pdev); - int i; - pci_power_t pstate = pci_choose_state(pdev, state); - - if (!(pstate == PCI_D3hot || pstate == PCI_D3cold)) - return -EINVAL; + int i, wol = 0; del_timer_sync(&hw->idle_timer); netif_poll_disable(hw->dev[0]); for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; + struct sky2_port *sky2 = netdev_priv(dev); - if (netif_running(dev)) { + if (netif_running(dev)) sky2_down(dev); - netif_device_detach(dev); - } + + if (sky2->wol) + sky2_wol_init(sky2); + + wol |= sky2->wol; } sky2_write32(hw, B0_IMSK, 0); + sky2_power_aux(hw); + pci_save_state(pdev); - sky2_set_power_state(hw, pstate); + pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; } @@ -3609,21 +3704,22 @@ static int sky2_resume(struct pci_dev *pdev) struct sky2_hw *hw = pci_get_drvdata(pdev); int i, err; - pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D0, 0); - sky2_set_power_state(hw, PCI_D0); - - err = sky2_reset(hw); + err = pci_set_power_state(pdev, PCI_D0); if (err) goto out; + err = pci_restore_state(pdev); + if (err) + goto out; + + pci_enable_wake(pdev, PCI_D0, 0); + sky2_reset(hw); + sky2_write32(hw, B0_IMSK, Y2_IS_BASE); for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; if (netif_running(dev)) { - netif_device_attach(dev); - err = sky2_up(dev); if (err) { printk(KERN_ERR PFX "%s: could not up: %d\n", @@ -3636,11 +3732,43 @@ static int sky2_resume(struct pci_dev *pdev) netif_poll_enable(hw->dev[0]); sky2_idle_start(hw); + return 0; out: + dev_err(&pdev->dev, "resume failed (%d)\n", err); + pci_disable_device(pdev); return err; } #endif +static void sky2_shutdown(struct pci_dev *pdev) +{ + struct sky2_hw *hw = pci_get_drvdata(pdev); + int i, wol = 0; + + del_timer_sync(&hw->idle_timer); + netif_poll_disable(hw->dev[0]); + + for (i = 0; i < hw->ports; i++) { + struct net_device *dev = hw->dev[i]; + struct sky2_port *sky2 = netdev_priv(dev); + + if (sky2->wol) { + wol = 1; + sky2_wol_init(sky2); + } + } + + if (wol) + sky2_power_aux(hw); + + pci_enable_wake(pdev, PCI_D3hot, wol); + pci_enable_wake(pdev, PCI_D3cold, wol); + + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + +} + static struct pci_driver sky2_driver = { .name = DRV_NAME, .id_table = sky2_id_table, @@ -3650,6 +3778,7 @@ static struct pci_driver sky2_driver = { .suspend = sky2_suspend, .resume = sky2_resume, #endif + .shutdown = sky2_shutdown, }; static int __init sky2_init_module(void) diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 6ed1d47dbbd3..3b0189569d52 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -32,6 +32,7 @@ enum pci_dev_reg_1 { PCI_Y2_PHY1_COMA = 1<<28, /* Set PHY 1 to Coma Mode (YUKON-2) */ PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */ PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */ + PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */ }; enum pci_dev_reg_2 { @@ -370,12 +371,9 @@ enum { /* B2_CHIP_ID 8 bit Chip Identification Number */ enum { - CHIP_ID_GENESIS = 0x0a, /* Chip ID for GENESIS */ - CHIP_ID_YUKON = 0xb0, /* Chip ID for YUKON */ - CHIP_ID_YUKON_LITE = 0xb1, /* Chip ID for YUKON-Lite (Rev. A1-A3) */ - CHIP_ID_YUKON_LP = 0xb2, /* Chip ID for YUKON-LP */ CHIP_ID_YUKON_XL = 0xb3, /* Chip ID for YUKON-2 XL */ CHIP_ID_YUKON_EC_U = 0xb4, /* Chip ID for YUKON-2 EC Ultra */ + CHIP_ID_YUKON_EX = 0xb5, /* Chip ID for YUKON-2 Extreme */ CHIP_ID_YUKON_EC = 0xb6, /* Chip ID for YUKON-2 EC */ CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */ @@ -767,6 +765,24 @@ enum { POLL_LIST_ADDR_HI= 0x0e2c,/* 32 bit Poll. List Start Addr (high) */ }; +enum { + SMB_CFG = 0x0e40, /* 32 bit SMBus Config Register */ + SMB_CSR = 0x0e44, /* 32 bit SMBus Control/Status Register */ +}; + +enum { + CPU_WDOG = 0x0e48, /* 32 bit Watchdog Register */ + CPU_CNTR = 0x0e4C, /* 32 bit Counter Register */ + CPU_TIM = 0x0e50,/* 32 bit Timer Compare Register */ + CPU_AHB_ADDR = 0x0e54, /* 32 bit CPU AHB Debug Register */ + CPU_AHB_WDATA = 0x0e58, /* 32 bit CPU AHB Debug Register */ + CPU_AHB_RDATA = 0x0e5C, /* 32 bit CPU AHB Debug Register */ + HCU_MAP_BASE = 0x0e60, /* 32 bit Reset Mapping Base */ + CPU_AHB_CTRL = 0x0e64, /* 32 bit CPU AHB Debug Register */ + HCU_CCSR = 0x0e68, /* 32 bit CPU Control and Status Register */ + HCU_HCSR = 0x0e6C, /* 32 bit Host Control and Status Register */ +}; + /* ASF Subsystem Registers (Yukon-2 only) */ enum { B28_Y2_SMB_CONFIG = 0x0e40,/* 32 bit ASF SMBus Config Register */ @@ -837,33 +853,27 @@ enum { GMAC_LINK_CTRL = 0x0f10,/* 16 bit Link Control Reg */ /* Wake-up Frame Pattern Match Control Registers (YUKON only) */ - - WOL_REG_OFFS = 0x20,/* HW-Bug: Address is + 0x20 against spec. */ - WOL_CTRL_STAT = 0x0f20,/* 16 bit WOL Control/Status Reg */ WOL_MATCH_CTL = 0x0f22,/* 8 bit WOL Match Control Reg */ WOL_MATCH_RES = 0x0f23,/* 8 bit WOL Match Result Reg */ WOL_MAC_ADDR = 0x0f24,/* 32 bit WOL MAC Address */ - WOL_PATT_PME = 0x0f2a,/* 8 bit WOL PME Match Enable (Yukon-2) */ - WOL_PATT_ASFM = 0x0f2b,/* 8 bit WOL ASF Match Enable (Yukon-2) */ WOL_PATT_RPTR = 0x0f2c,/* 8 bit WOL Pattern Read Pointer */ /* WOL Pattern Length Registers (YUKON only) */ - WOL_PATT_LEN_LO = 0x0f30,/* 32 bit WOL Pattern Length 3..0 */ WOL_PATT_LEN_HI = 0x0f34,/* 24 bit WOL Pattern Length 6..4 */ /* WOL Pattern Counter Registers (YUKON only) */ - - WOL_PATT_CNT_0 = 0x0f38,/* 32 bit WOL Pattern Counter 3..0 */ WOL_PATT_CNT_4 = 0x0f3c,/* 24 bit WOL Pattern Counter 6..4 */ }; +#define WOL_REGS(port, x) (x + (port)*0x80) enum { WOL_PATT_RAM_1 = 0x1000,/* WOL Pattern RAM Link 1 */ WOL_PATT_RAM_2 = 0x1400,/* WOL Pattern RAM Link 2 */ }; +#define WOL_PATT_RAM_BASE(port) (WOL_PATT_RAM_1 + (port)*0x400) enum { BASE_GMAC_1 = 0x2800,/* GMAC 1 registers */ @@ -1654,6 +1664,39 @@ enum { Y2_ASF_CLR_ASFI = 1<<1, /* Clear host IRQ */ Y2_ASF_HOST_IRQ = 1<<0, /* Issue an IRQ to HOST system */ }; +/* HCU_CCSR CPU Control and Status Register */ +enum { + HCU_CCSR_SMBALERT_MONITOR= 1<<27, /* SMBALERT pin monitor */ + HCU_CCSR_CPU_SLEEP = 1<<26, /* CPU sleep status */ + /* Clock Stretching Timeout */ + HCU_CCSR_CS_TO = 1<<25, + HCU_CCSR_WDOG = 1<<24, /* Watchdog Reset */ + + HCU_CCSR_CLR_IRQ_HOST = 1<<17, /* Clear IRQ_HOST */ + HCU_CCSR_SET_IRQ_HCU = 1<<16, /* Set IRQ_HCU */ + + HCU_CCSR_AHB_RST = 1<<9, /* Reset AHB bridge */ + HCU_CCSR_CPU_RST_MODE = 1<<8, /* CPU Reset Mode */ + + HCU_CCSR_SET_SYNC_CPU = 1<<5, + HCU_CCSR_CPU_CLK_DIVIDE_MSK = 3<<3,/* CPU Clock Divide */ + HCU_CCSR_CPU_CLK_DIVIDE_BASE= 1<<3, + HCU_CCSR_OS_PRSNT = 1<<2, /* ASF OS Present */ +/* Microcontroller State */ + HCU_CCSR_UC_STATE_MSK = 3, + HCU_CCSR_UC_STATE_BASE = 1<<0, + HCU_CCSR_ASF_RESET = 0, + HCU_CCSR_ASF_HALTED = 1<<1, + HCU_CCSR_ASF_RUNNING = 1<<0, +}; + +/* HCU_HCSR Host Control and Status Register */ +enum { + HCU_HCSR_SET_IRQ_CPU = 1<<16, /* Set IRQ_CPU */ + + HCU_HCSR_CLR_IRQ_HCU = 1<<1, /* Clear IRQ_HCU */ + HCU_HCSR_SET_IRQ_HOST = 1<<0, /* Set IRQ_HOST */ +}; /* STAT_CTRL 32 bit Status BMU control register (Yukon-2 only) */ enum { @@ -1715,14 +1758,17 @@ enum { GM_IS_RX_COMPL = 1<<0, /* Frame Reception Complete */ #define GMAC_DEF_MSK GM_IS_TX_FF_UR +}; /* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */ - /* Bits 15.. 2: reserved */ +enum { /* Bits 15.. 2: reserved */ GMLC_RST_CLR = 1<<1, /* Clear GMAC Link Reset */ GMLC_RST_SET = 1<<0, /* Set GMAC Link Reset */ +}; /* WOL_CTRL_STAT 16 bit WOL Control/Status Reg */ +enum { WOL_CTL_LINK_CHG_OCC = 1<<15, WOL_CTL_MAGIC_PKT_OCC = 1<<14, WOL_CTL_PATTERN_OCC = 1<<13, @@ -1741,17 +1787,6 @@ enum { WOL_CTL_DIS_PATTERN_UNIT = 1<<0, }; -#define WOL_CTL_DEFAULT \ - (WOL_CTL_DIS_PME_ON_LINK_CHG | \ - WOL_CTL_DIS_PME_ON_PATTERN | \ - WOL_CTL_DIS_PME_ON_MAGIC_PKT | \ - WOL_CTL_DIS_LINK_CHG_UNIT | \ - WOL_CTL_DIS_PATTERN_UNIT | \ - WOL_CTL_DIS_MAGIC_PKT_UNIT) - -/* WOL_MATCH_CTL 8 bit WOL Match Control Reg */ -#define WOL_CTL_PATT_ENA(x) (1 << (x)) - /* Control flags */ enum { @@ -1875,6 +1910,7 @@ struct sky2_port { u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ u8 rx_csum; + u8 wol; enum flow_control flow_mode; enum flow_control flow_status; @@ -1887,7 +1923,6 @@ struct sky2_hw { struct pci_dev *pdev; struct net_device *dev[2]; - int pm_cap; u8 chip_id; u8 chip_rev; u8 pmd_type; 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/spider_net.c b/drivers/net/spider_net.c index 8ea2fc1b96cb..bf6ff39e02bb 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -280,72 +280,67 @@ spider_net_free_chain(struct spider_net_card *card, { struct spider_net_descr *descr; - for (descr = chain->tail; !descr->bus_addr; descr = descr->next) { - pci_unmap_single(card->pdev, descr->bus_addr, - SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL); + descr = chain->ring; + do { descr->bus_addr = 0; - } + descr->next_descr_addr = 0; + descr = descr->next; + } while (descr != chain->ring); + + dma_free_coherent(&card->pdev->dev, chain->num_desc, + chain->ring, chain->dma_addr); } /** - * spider_net_init_chain - links descriptor chain + * spider_net_init_chain - alloc and link descriptor chain * @card: card structure * @chain: address of chain - * @start_descr: address of descriptor array - * @no: number of descriptors * - * we manage a circular list that mirrors the hardware structure, + * We manage a circular list that mirrors the hardware structure, * except that the hardware uses bus addresses. * - * returns 0 on success, <0 on failure + * Returns 0 on success, <0 on failure */ static int spider_net_init_chain(struct spider_net_card *card, - struct spider_net_descr_chain *chain, - struct spider_net_descr *start_descr, - int no) + struct spider_net_descr_chain *chain) { int i; struct spider_net_descr *descr; dma_addr_t buf; + size_t alloc_size; - descr = start_descr; - memset(descr, 0, sizeof(*descr) * no); + alloc_size = chain->num_desc * sizeof (struct spider_net_descr); - /* set up the hardware pointers in each descriptor */ - for (i=0; iring = dma_alloc_coherent(&card->pdev->dev, alloc_size, + &chain->dma_addr, GFP_KERNEL); + + if (!chain->ring) + return -ENOMEM; + + descr = chain->ring; + memset(descr, 0, alloc_size); + + /* Set up the hardware pointers in each descriptor */ + buf = chain->dma_addr; + for (i=0; i < chain->num_desc; i++, descr++) { descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; - buf = pci_map_single(card->pdev, descr, - SPIDER_NET_DESCR_SIZE, - PCI_DMA_BIDIRECTIONAL); - - if (pci_dma_mapping_error(buf)) - goto iommu_error; - descr->bus_addr = buf; + descr->next_descr_addr = 0; descr->next = descr + 1; descr->prev = descr - 1; + buf += sizeof(struct spider_net_descr); } /* do actual circular list */ - (descr-1)->next = start_descr; - start_descr->prev = descr-1; + (descr-1)->next = chain->ring; + chain->ring->prev = descr-1; spin_lock_init(&chain->lock); - chain->head = start_descr; - chain->tail = start_descr; - + chain->head = chain->ring; + chain->tail = chain->ring; return 0; - -iommu_error: - descr = start_descr; - for (i=0; i < no; i++, descr++) - if (descr->bus_addr) - pci_unmap_single(card->pdev, descr->bus_addr, - SPIDER_NET_DESCR_SIZE, - PCI_DMA_BIDIRECTIONAL); - return -ENOMEM; } /** @@ -372,21 +367,20 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card) } /** - * spider_net_prepare_rx_descr - reinitializes a rx descriptor + * spider_net_prepare_rx_descr - Reinitialize RX descriptor * @card: card structure * @descr: descriptor to re-init * - * return 0 on succes, <0 on failure + * Return 0 on succes, <0 on failure. * - * allocates a new rx skb, iommu-maps it and attaches it to the descriptor. - * Activate the descriptor state-wise + * Allocates a new rx skb, iommu-maps it and attaches it to the + * descriptor. Mark the descriptor as activated, ready-to-use. */ static int spider_net_prepare_rx_descr(struct spider_net_card *card, struct spider_net_descr *descr) { dma_addr_t buf; - int error = 0; int offset; int bufsize; @@ -414,7 +408,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, (SPIDER_NET_RXBUF_ALIGN - 1); if (offset) skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset); - /* io-mmu-map the skb */ + /* iommu-map the skb */ buf = pci_map_single(card->pdev, descr->skb->data, SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); descr->buf_addr = buf; @@ -425,11 +419,16 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, card->spider_stats.rx_iommu_map_error++; descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; } else { + descr->next_descr_addr = 0; + wmb(); descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOINTR_COMPLETE; + + wmb(); + descr->prev->next_descr_addr = descr->bus_addr; } - return error; + return 0; } /** @@ -493,10 +492,10 @@ spider_net_refill_rx_chain(struct spider_net_card *card) } /** - * spider_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains + * spider_net_alloc_rx_skbs - Allocates rx skbs in rx descriptor chains * @card: card structure * - * returns 0 on success, <0 on failure + * Returns 0 on success, <0 on failure. */ static int spider_net_alloc_rx_skbs(struct spider_net_card *card) @@ -507,16 +506,16 @@ spider_net_alloc_rx_skbs(struct spider_net_card *card) result = -ENOMEM; chain = &card->rx_chain; - /* put at least one buffer into the chain. if this fails, - * we've got a problem. if not, spider_net_refill_rx_chain - * will do the rest at the end of this function */ + /* Put at least one buffer into the chain. if this fails, + * we've got a problem. If not, spider_net_refill_rx_chain + * will do the rest at the end of this function. */ if (spider_net_prepare_rx_descr(card, chain->head)) goto error; else chain->head = chain->head->next; - /* this will allocate the rest of the rx buffers; if not, it's - * business as usual later on */ + /* This will allocate the rest of the rx buffers; + * if not, it's business as usual later on. */ spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); return 0; @@ -707,7 +706,7 @@ spider_net_set_low_watermark(struct spider_net_card *card) } /* If TX queue is short, don't even bother with interrupts */ - if (cnt < card->num_tx_desc/4) + if (cnt < card->tx_chain.num_desc/4) return cnt; /* Set low-watermark 3/4th's of the way into the queue. */ @@ -915,16 +914,13 @@ spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) * spider_net_pass_skb_up - takes an skb from a descriptor and passes it on * @descr: descriptor to process * @card: card structure - * @napi: whether caller is in NAPI context * - * returns 1 on success, 0 if no packet was passed to the stack - * - * iommu-unmaps the skb, fills out skb structure and passes the data to the - * stack. The descriptor state is not changed. + * Fills out skb structure and passes the data to the stack. + * The descriptor state is not changed. */ -static int +static void spider_net_pass_skb_up(struct spider_net_descr *descr, - struct spider_net_card *card, int napi) + struct spider_net_card *card) { struct sk_buff *skb; struct net_device *netdev; @@ -932,23 +928,8 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, data_status = descr->data_status; data_error = descr->data_error; - netdev = card->netdev; - /* unmap descriptor */ - pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME, - PCI_DMA_FROMDEVICE); - - /* the cases we'll throw away the packet immediately */ - if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) { - if (netif_msg_rx_err(card)) - pr_err("error in received descriptor found, " - "data_status=x%08x, data_error=x%08x\n", - data_status, data_error); - card->spider_stats.rx_desc_error++; - return 0; - } - skb = descr->skb; skb->dev = netdev; skb_put(skb, descr->valid_size); @@ -977,57 +958,72 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, } /* pass skb up to stack */ - if (napi) - netif_receive_skb(skb); - else - netif_rx_ni(skb); + netif_receive_skb(skb); /* update netdevice statistics */ card->netdev_stats.rx_packets++; card->netdev_stats.rx_bytes += skb->len; - - return 1; } +#ifdef DEBUG +static void show_rx_chain(struct spider_net_card *card) +{ + struct spider_net_descr_chain *chain = &card->rx_chain; + struct spider_net_descr *start= chain->tail; + struct spider_net_descr *descr= start; + int status; + + int cnt = 0; + int cstat = spider_net_get_descr_status(descr); + printk(KERN_INFO "RX chain tail at descr=%ld\n", + (start - card->descr) - card->tx_chain.num_desc); + status = cstat; + do + { + status = spider_net_get_descr_status(descr); + if (cstat != status) { + printk(KERN_INFO "Have %d descrs with stat=x%08x\n", cnt, cstat); + cstat = status; + cnt = 0; + } + cnt ++; + descr = descr->next; + } while (descr != start); + printk(KERN_INFO "Last %d descrs with stat=x%08x\n", cnt, cstat); +} +#endif + /** * spider_net_decode_one_descr - processes an rx descriptor * @card: card structure - * @napi: whether caller is in NAPI context * - * returns 1 if a packet has been sent to the stack, otherwise 0 + * Returns 1 if a packet has been sent to the stack, otherwise 0 * - * processes an rx descriptor by iommu-unmapping the data buffer and passing + * Processes an rx descriptor by iommu-unmapping the data buffer and passing * the packet up to the stack. This function is called in softirq * context, e.g. either bottom half from interrupt or NAPI polling context */ static int -spider_net_decode_one_descr(struct spider_net_card *card, int napi) +spider_net_decode_one_descr(struct spider_net_card *card) { struct spider_net_descr_chain *chain = &card->rx_chain; struct spider_net_descr *descr = chain->tail; int status; - int result; status = spider_net_get_descr_status(descr); - if (status == SPIDER_NET_DESCR_CARDOWNED) { - /* nothing in the descriptor yet */ - result=0; - goto out; - } - - if (status == SPIDER_NET_DESCR_NOT_IN_USE) { - /* not initialized yet, the ring must be empty */ - spider_net_refill_rx_chain(card); - spider_net_enable_rxdmac(card); - result=0; - goto out; - } + /* Nothing in the descriptor, or ring must be empty */ + if ((status == SPIDER_NET_DESCR_CARDOWNED) || + (status == SPIDER_NET_DESCR_NOT_IN_USE)) + return 0; /* descriptor definitively used -- move on tail */ chain->tail = descr->next; - result = 0; + /* unmap descriptor */ + pci_unmap_single(card->pdev, descr->buf_addr, + SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); + if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) || (status == SPIDER_NET_DESCR_PROTECTION_ERROR) || (status == SPIDER_NET_DESCR_FORCE_END) ) { @@ -1035,31 +1031,55 @@ spider_net_decode_one_descr(struct spider_net_card *card, int napi) pr_err("%s: dropping RX descriptor with state %d\n", card->netdev->name, status); card->netdev_stats.rx_dropped++; - pci_unmap_single(card->pdev, descr->buf_addr, - SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); - dev_kfree_skb_irq(descr->skb); - goto refill; + goto bad_desc; } if ( (status != SPIDER_NET_DESCR_COMPLETE) && (status != SPIDER_NET_DESCR_FRAME_END) ) { - if (netif_msg_rx_err(card)) { - pr_err("%s: RX descriptor with state %d\n", + if (netif_msg_rx_err(card)) + pr_err("%s: RX descriptor with unkown state %d\n", card->netdev->name, status); - card->spider_stats.rx_desc_unk_state++; - } - goto refill; + card->spider_stats.rx_desc_unk_state++; + goto bad_desc; } - /* ok, we've got a packet in descr */ - result = spider_net_pass_skb_up(descr, card, napi); -refill: + /* The cases we'll throw away the packet immediately */ + if (descr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) { + if (netif_msg_rx_err(card)) + pr_err("%s: error in received descriptor found, " + "data_status=x%08x, data_error=x%08x\n", + card->netdev->name, + descr->data_status, descr->data_error); + goto bad_desc; + } + + if (descr->dmac_cmd_status & 0xfefe) { + pr_err("%s: bad status, cmd_status=x%08x\n", + card->netdev->name, + descr->dmac_cmd_status); + pr_err("buf_addr=x%08x\n", descr->buf_addr); + pr_err("buf_size=x%08x\n", descr->buf_size); + pr_err("next_descr_addr=x%08x\n", descr->next_descr_addr); + pr_err("result_size=x%08x\n", descr->result_size); + pr_err("valid_size=x%08x\n", descr->valid_size); + pr_err("data_status=x%08x\n", descr->data_status); + pr_err("data_error=x%08x\n", descr->data_error); + pr_err("bus_addr=x%08x\n", descr->bus_addr); + pr_err("which=%ld\n", descr - card->rx_chain.ring); + + card->spider_stats.rx_desc_error++; + goto bad_desc; + } + + /* Ok, we've got a packet in descr */ + spider_net_pass_skb_up(descr, card); descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; - /* change the descriptor state: */ - if (!napi) - spider_net_refill_rx_chain(card); -out: - return result; + return 1; + +bad_desc: + dev_kfree_skb_irq(descr->skb); + descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; + return 0; } /** @@ -1085,7 +1105,7 @@ spider_net_poll(struct net_device *netdev, int *budget) packets_to_do = min(*budget, netdev->quota); while (packets_to_do) { - if (spider_net_decode_one_descr(card, 1)) { + if (spider_net_decode_one_descr(card)) { packets_done++; packets_to_do--; } else { @@ -1098,6 +1118,7 @@ spider_net_poll(struct net_device *netdev, int *budget) netdev->quota -= packets_done; *budget -= packets_done; spider_net_refill_rx_chain(card); + spider_net_enable_rxdmac(card); /* if all packets are in the stack, enable interrupts and return 0 */ /* if not, return 1 */ @@ -1226,24 +1247,6 @@ spider_net_set_mac(struct net_device *netdev, void *p) return 0; } -/** - * spider_net_handle_rxram_full - cleans up RX ring upon RX RAM full interrupt - * @card: card structure - * - * spider_net_handle_rxram_full empties the RX ring so that spider can put - * more packets in it and empty its RX RAM. This is called in bottom half - * context - */ -static void -spider_net_handle_rxram_full(struct spider_net_card *card) -{ - while (spider_net_decode_one_descr(card, 0)) - ; - spider_net_enable_rxchtails(card); - spider_net_enable_rxdmac(card); - netif_rx_schedule(card->netdev); -} - /** * spider_net_handle_error_irq - handles errors raised by an interrupt * @card: card structure @@ -1366,10 +1369,10 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) case SPIDER_NET_GRFAFLLINT: /* fallthrough */ case SPIDER_NET_GRMFLLINT: if (netif_msg_intr(card) && net_ratelimit()) - pr_debug("Spider RX RAM full, incoming packets " + pr_err("Spider RX RAM full, incoming packets " "might be discarded!\n"); spider_net_rx_irq_off(card); - tasklet_schedule(&card->rxram_full_tl); + netif_rx_schedule(card->netdev); show_error = 0; break; @@ -1384,7 +1387,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) case SPIDER_NET_GDCDCEINT: /* fallthrough */ case SPIDER_NET_GDBDCEINT: /* fallthrough */ case SPIDER_NET_GDADCEINT: - if (netif_msg_intr(card)) + if (netif_msg_intr(card) && net_ratelimit()) pr_err("got descriptor chain end interrupt, " "restarting DMAC %c.\n", 'D'-(i-SPIDER_NET_GDDDCEINT)/3); @@ -1455,7 +1458,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) break; } - if ((show_error) && (netif_msg_intr(card))) + if ((show_error) && (netif_msg_intr(card)) && net_ratelimit()) pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, " "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n", card->netdev->name, @@ -1651,27 +1654,18 @@ int spider_net_open(struct net_device *netdev) { struct spider_net_card *card = netdev_priv(netdev); - struct spider_net_descr *descr; - int i, result; + int result; - result = -ENOMEM; - if (spider_net_init_chain(card, &card->tx_chain, card->descr, - card->num_tx_desc)) + result = spider_net_init_chain(card, &card->tx_chain); + if (result) goto alloc_tx_failed; - card->low_watermark = NULL; - /* rx_chain is after tx_chain, so offset is descr + tx_count */ - if (spider_net_init_chain(card, &card->rx_chain, - card->descr + card->num_tx_desc, - card->num_rx_desc)) + result = spider_net_init_chain(card, &card->rx_chain); + if (result) goto alloc_rx_failed; - descr = card->rx_chain.head; - for (i=0; i < card->num_rx_desc; i++, descr++) - descr->next_descr_addr = descr->next->bus_addr; - - /* allocate rx skbs */ + /* Allocate rx skbs */ if (spider_net_alloc_rx_skbs(card)) goto alloc_skbs_failed; @@ -1902,7 +1896,6 @@ spider_net_stop(struct net_device *netdev) { struct spider_net_card *card = netdev_priv(netdev); - tasklet_kill(&card->rxram_full_tl); netif_poll_disable(netdev); netif_carrier_off(netdev); netif_stop_queue(netdev); @@ -1924,6 +1917,7 @@ spider_net_stop(struct net_device *netdev) /* release chains */ spider_net_release_tx_chain(card, 1); + spider_net_free_rx_chain_contents(card); spider_net_free_rx_chain_contents(card); @@ -2046,9 +2040,6 @@ spider_net_setup_netdev(struct spider_net_card *card) pci_set_drvdata(card->pdev, netdev); - card->rxram_full_tl.data = (unsigned long) card; - card->rxram_full_tl.func = - (void (*)(unsigned long)) spider_net_handle_rxram_full; init_timer(&card->tx_timer); card->tx_timer.function = (void (*)(unsigned long)) spider_net_cleanup_tx_ring; @@ -2057,8 +2048,8 @@ spider_net_setup_netdev(struct spider_net_card *card) card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; - card->num_tx_desc = tx_descriptors; - card->num_rx_desc = rx_descriptors; + card->tx_chain.num_desc = tx_descriptors; + card->rx_chain.num_desc = rx_descriptors; spider_net_setup_netdev_ops(netdev); @@ -2107,12 +2098,8 @@ spider_net_alloc_card(void) { struct net_device *netdev; struct spider_net_card *card; - size_t alloc_size; - alloc_size = sizeof (*card) + - sizeof (struct spider_net_descr) * rx_descriptors + - sizeof (struct spider_net_descr) * tx_descriptors; - netdev = alloc_etherdev(alloc_size); + netdev = alloc_etherdev(sizeof(struct spider_net_card)); if (!netdev) return NULL; diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 3e196df29790..2fec5cf76926 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -24,7 +24,7 @@ #ifndef _SPIDER_NET_H #define _SPIDER_NET_H -#define VERSION "1.6 A" +#define VERSION "1.6 B" #include "sungem_phy.h" @@ -378,6 +378,9 @@ struct spider_net_descr_chain { spinlock_t lock; struct spider_net_descr *head; struct spider_net_descr *tail; + struct spider_net_descr *ring; + int num_desc; + dma_addr_t dma_addr; }; /* descriptor data_status bits */ @@ -397,8 +400,6 @@ struct spider_net_descr_chain { * 701b8000 would be correct, but every packets gets that flag */ #define SPIDER_NET_DESTROY_RX_FLAGS 0x700b8000 -#define SPIDER_NET_DESCR_SIZE 32 - /* this will be bigger some time */ struct spider_net_options { int rx_csum; /* for rx: if 0 ip_summed=NONE, @@ -441,25 +442,16 @@ struct spider_net_card { struct spider_net_descr_chain rx_chain; struct spider_net_descr *low_watermark; - struct net_device_stats netdev_stats; - - struct spider_net_options options; - - spinlock_t intmask_lock; - struct tasklet_struct rxram_full_tl; struct timer_list tx_timer; - struct work_struct tx_timeout_task; atomic_t tx_timeout_task_counter; wait_queue_head_t waitq; /* for ethtool */ int msg_enable; - int num_rx_desc; - int num_tx_desc; + struct net_device_stats netdev_stats; struct spider_net_extra_stats spider_stats; - - struct spider_net_descr descr[0]; + struct spider_net_options options; }; #define pr_err(fmt,arg...) \ diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 91b995102915..6bcf03fc89be 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -158,9 +158,9 @@ spider_net_ethtool_get_ringparam(struct net_device *netdev, struct spider_net_card *card = netdev->priv; ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX; - ering->tx_pending = card->num_tx_desc; + ering->tx_pending = card->tx_chain.num_desc; ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX; - ering->rx_pending = card->num_rx_desc; + ering->rx_pending = card->rx_chain.num_desc; } static int spider_net_get_stats_count(struct net_device *netdev) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f4bf62c2a7a5..135c0987deae 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -58,11 +58,7 @@ #define TG3_VLAN_TAG_USED 0 #endif -#ifdef NETIF_F_TSO #define TG3_TSO_SUPPORT 1 -#else -#define TG3_TSO_SUPPORT 0 -#endif #include "tg3.h" @@ -3873,7 +3869,6 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) entry = tp->tx_prod; base_flags = 0; -#if TG3_TSO_SUPPORT != 0 mss = 0; if (skb->len > (tp->dev->mtu + ETH_HLEN) && (mss = skb_shinfo(skb)->gso_size) != 0) { @@ -3906,11 +3901,6 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) } else if (skb->ip_summed == CHECKSUM_PARTIAL) base_flags |= TXD_FLAG_TCPUDP_CSUM; -#else - mss = 0; - if (skb->ip_summed == CHECKSUM_PARTIAL) - base_flags |= TXD_FLAG_TCPUDP_CSUM; -#endif #if TG3_VLAN_TAG_USED if (tp->vlgrp != NULL && vlan_tx_tag_present(skb)) base_flags |= (TXD_FLAG_VLAN | @@ -3970,7 +3960,6 @@ out_unlock: return NETDEV_TX_OK; } -#if TG3_TSO_SUPPORT != 0 static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *); /* Use GSO to workaround a rare TSO bug that may be triggered when the @@ -4002,7 +3991,6 @@ tg3_tso_bug_end: return NETDEV_TX_OK; } -#endif /* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and * support TG3_FLG2_HW_TSO_1 or firmware TSO only. @@ -4036,7 +4024,6 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) base_flags = 0; if (skb->ip_summed == CHECKSUM_PARTIAL) base_flags |= TXD_FLAG_TCPUDP_CSUM; -#if TG3_TSO_SUPPORT != 0 mss = 0; if (skb->len > (tp->dev->mtu + ETH_HLEN) && (mss = skb_shinfo(skb)->gso_size) != 0) { @@ -4091,9 +4078,6 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) } } } -#else - mss = 0; -#endif #if TG3_VLAN_TAG_USED if (tp->vlgrp != NULL && vlan_tx_tag_present(skb)) base_flags |= (TXD_FLAG_VLAN | @@ -5329,7 +5313,6 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp) return 0; } -#if TG3_TSO_SUPPORT != 0 #define TG3_TSO_FW_RELEASE_MAJOR 0x1 #define TG3_TSO_FW_RELASE_MINOR 0x6 @@ -5906,7 +5889,6 @@ static int tg3_load_tso_firmware(struct tg3 *tp) return 0; } -#endif /* TG3_TSO_SUPPORT != 0 */ /* tp->lock is held. */ static void __tg3_set_mac_addr(struct tg3 *tp) @@ -6120,7 +6102,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE); tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE); } -#if TG3_TSO_SUPPORT != 0 else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) { int fw_len; @@ -6135,7 +6116,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE5705 - fw_len - 0xa00); } -#endif if (tp->dev->mtu <= ETH_DATA_LEN) { tw32(BUFMGR_MB_RDMA_LOW_WATER, @@ -6337,10 +6317,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST; -#if TG3_TSO_SUPPORT != 0 if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) rdmac_mode |= (1 << 27); -#endif /* Receive/send statistics. */ if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { @@ -6511,10 +6489,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB); tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ); tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE); -#if TG3_TSO_SUPPORT != 0 if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8); -#endif tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE); tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE); @@ -6524,13 +6500,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) return err; } -#if TG3_TSO_SUPPORT != 0 if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) { err = tg3_load_tso_firmware(tp); if (err) return err; } -#endif tp->tx_mode = TX_MODE_ENABLE; tw32_f(MAC_TX_MODE, tp->tx_mode); @@ -8062,7 +8036,6 @@ static void tg3_set_msglevel(struct net_device *dev, u32 value) tp->msg_enable = value; } -#if TG3_TSO_SUPPORT != 0 static int tg3_set_tso(struct net_device *dev, u32 value) { struct tg3 *tp = netdev_priv(dev); @@ -8081,7 +8054,6 @@ static int tg3_set_tso(struct net_device *dev, u32 value) } return ethtool_op_set_tso(dev, value); } -#endif static int tg3_nway_reset(struct net_device *dev) { @@ -9212,10 +9184,8 @@ static const struct ethtool_ops tg3_ethtool_ops = { .set_tx_csum = tg3_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, -#if TG3_TSO_SUPPORT != 0 .get_tso = ethtool_op_get_tso, .set_tso = tg3_set_tso, -#endif .self_test_count = tg3_get_test_count, .self_test = tg3_self_test, .get_strings = tg3_get_strings, @@ -11856,7 +11826,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tg3_init_bufmgr_config(tp); -#if TG3_TSO_SUPPORT != 0 if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) { tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; } @@ -11881,7 +11850,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, dev->features |= NETIF_F_TSO6; } -#endif if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 && !(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 7e4b23c7c1ba..abb8611c5a91 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -2865,8 +2865,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4) align = UCC_GETH_TX_BD_RING_ALIGNMENT; ugeth->tx_bd_ring_offset[j] = - (u32) (kmalloc((u32) (length + align), - GFP_KERNEL)); + kmalloc((u32) (length + align), GFP_KERNEL); + if (ugeth->tx_bd_ring_offset[j] != 0) ugeth->p_tx_bd_ring[j] = (void*)((ugeth->tx_bd_ring_offset[j] + @@ -2901,7 +2901,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4) align = UCC_GETH_RX_BD_RING_ALIGNMENT; ugeth->rx_bd_ring_offset[j] = - (u32) (kmalloc((u32) (length + align), GFP_KERNEL)); + kmalloc((u32) (length + align), GFP_KERNEL); if (ugeth->rx_bd_ring_offset[j] != 0) ugeth->p_rx_bd_ring[j] = (void*)((ugeth->rx_bd_ring_offset[j] + @@ -2927,10 +2927,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) /* Init Tx bds */ for (j = 0; j < ug_info->numQueuesTx; j++) { /* Setup the skbuff rings */ - ugeth->tx_skbuff[j] = - (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) * - ugeth->ug_info->bdRingLenTx[j], - GFP_KERNEL); + ugeth->tx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) * + ugeth->ug_info->bdRingLenTx[j], + GFP_KERNEL); if (ugeth->tx_skbuff[j] == NULL) { ugeth_err("%s: Could not allocate tx_skbuff", @@ -2959,10 +2958,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) /* Init Rx bds */ for (j = 0; j < ug_info->numQueuesRx; j++) { /* Setup the skbuff rings */ - ugeth->rx_skbuff[j] = - (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) * - ugeth->ug_info->bdRingLenRx[j], - GFP_KERNEL); + ugeth->rx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) * + ugeth->ug_info->bdRingLenRx[j], + GFP_KERNEL); if (ugeth->rx_skbuff[j] == NULL) { ugeth_err("%s: Could not allocate rx_skbuff", @@ -3453,8 +3451,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) * allocated resources can be released when the channel is freed. */ if (!(ugeth->p_init_enet_param_shadow = - (struct ucc_geth_init_pram *) kmalloc(sizeof(struct ucc_geth_init_pram), - GFP_KERNEL))) { + kmalloc(sizeof(struct ucc_geth_init_pram), GFP_KERNEL))) { ugeth_err ("%s: Can not allocate memory for" " p_UccInitEnetParamShadows.", __FUNCTION__); diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 21f76f51c95e..61708cf4c85d 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -235,6 +235,19 @@ comment "Cyclades-PC300 MLPPP support is disabled." comment "Refer to the file README.mlppp, provided by PC300 package." depends on WAN && HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP) +config PC300TOO + tristate "Cyclades PC300 RSV/X21 alternative support" + depends on HDLC && PCI + help + Alternative driver for PC300 RSV/X21 PCI cards made by + Cyclades, Inc. If you have such a card, say Y here and see + . + + To compile this as a module, choose M here: the module + will be called pc300too. + + If unsure, say N here. + config N2 tristate "SDL RISCom/N2 support" depends on HDLC && ISA @@ -344,17 +357,6 @@ config DLCI To compile this driver as a module, choose M here: the module will be called dlci. -config DLCI_COUNT - int "Max open DLCI" - depends on DLCI - default "24" - help - Maximal number of logical point-to-point frame relay connections - (the identifiers of which are called DCLIs) that the driver can - handle. - - The default is probably fine. - config DLCI_MAX int "Max DLCI per device" depends on DLCI diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 83ec2c87ba3f..d61fef36afc9 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_N2) += n2.o obj-$(CONFIG_C101) += c101.o obj-$(CONFIG_WANXL) += wanxl.o obj-$(CONFIG_PCI200SYN) += pci200syn.o +obj-$(CONFIG_PC300TOO) += pc300too.o clean-files := wanxlfw.inc $(obj)/wanxl.o: $(obj)/wanxlfw.inc diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index db354e0edbe5..9040d7cf651e 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -222,7 +222,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EINVAL; } -void hdlc_setup(struct net_device *dev) +static void hdlc_setup(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); @@ -325,7 +325,6 @@ MODULE_LICENSE("GPL v2"); EXPORT_SYMBOL(hdlc_open); EXPORT_SYMBOL(hdlc_close); EXPORT_SYMBOL(hdlc_ioctl); -EXPORT_SYMBOL(hdlc_setup); EXPORT_SYMBOL(alloc_hdlcdev); EXPORT_SYMBOL(unregister_hdlc_device); EXPORT_SYMBOL(register_hdlc_protocol); diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c new file mode 100644 index 000000000000..79b2d5454d6b --- /dev/null +++ b/drivers/net/wan/pc300too.c @@ -0,0 +1,565 @@ +/* + * Cyclades PC300 synchronous serial card driver for Linux + * + * Copyright (C) 2000-2007 Krzysztof Halasa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * For information see . + * + * Sources of information: + * Hitachi HD64572 SCA-II User's Manual + * Cyclades PC300 Linux driver + * + * This driver currently supports only PC300/RSV (V.24/V.35) and + * PC300/X21 cards. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hd64572.h" + +static const char* version = "Cyclades PC300 driver version: 1.17"; +static const char* devname = "PC300"; + +#undef DEBUG_PKT +#define DEBUG_RINGS + +#define PC300_PLX_SIZE 0x80 /* PLX control window size (128 B) */ +#define PC300_SCA_SIZE 0x400 /* SCA window size (1 KB) */ +#define ALL_PAGES_ALWAYS_MAPPED +#define NEED_DETECT_RAM +#define NEED_SCA_MSCI_INTR +#define MAX_TX_BUFFERS 10 + +static int pci_clock_freq = 33000000; +static int use_crystal_clock = 0; +static unsigned int CLOCK_BASE; + +/* Masks to access the init_ctrl PLX register */ +#define PC300_CLKSEL_MASK (0x00000004UL) +#define PC300_CHMEDIA_MASK(port) (0x00000020UL << ((port) * 3)) +#define PC300_CTYPE_MASK (0x00000800UL) + + +enum { PC300_RSV = 1, PC300_X21, PC300_TE }; /* card types */ + +/* + * PLX PCI9050-1 local configuration and shared runtime registers. + * This structure can be used to access 9050 registers (memory mapped). + */ +typedef struct { + u32 loc_addr_range[4]; /* 00-0Ch : Local Address Ranges */ + u32 loc_rom_range; /* 10h : Local ROM Range */ + u32 loc_addr_base[4]; /* 14-20h : Local Address Base Addrs */ + u32 loc_rom_base; /* 24h : Local ROM Base */ + u32 loc_bus_descr[4]; /* 28-34h : Local Bus Descriptors */ + u32 rom_bus_descr; /* 38h : ROM Bus Descriptor */ + u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */ + u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */ + u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */ +}plx9050; + + + +typedef struct port_s { + struct net_device *dev; + struct card_s *card; + spinlock_t lock; /* TX lock */ + sync_serial_settings settings; + int rxpart; /* partial frame received, next frame invalid*/ + unsigned short encoding; + unsigned short parity; + unsigned int iface; + u16 rxin; /* rx ring buffer 'in' pointer */ + u16 txin; /* tx ring buffer 'in' and 'last' pointers */ + u16 txlast; + u8 rxs, txs, tmc; /* SCA registers */ + u8 phy_node; /* physical port # - 0 or 1 */ +}port_t; + + + +typedef struct card_s { + int type; /* RSV, X21, etc. */ + int n_ports; /* 1 or 2 ports */ + u8* __iomem rambase; /* buffer memory base (virtual) */ + u8* __iomem scabase; /* SCA memory base (virtual) */ + plx9050 __iomem *plxbase; /* PLX registers memory base (virtual) */ + u32 init_ctrl_value; /* Saved value - 9050 bug workaround */ + u16 rx_ring_buffers; /* number of buffers in a ring */ + u16 tx_ring_buffers; + u16 buff_offset; /* offset of first buffer of first channel */ + u8 irq; /* interrupt request level */ + + port_t ports[2]; +}card_t; + + +#define sca_in(reg, card) readb(card->scabase + (reg)) +#define sca_out(value, reg, card) writeb(value, card->scabase + (reg)) +#define sca_inw(reg, card) readw(card->scabase + (reg)) +#define sca_outw(value, reg, card) writew(value, card->scabase + (reg)) +#define sca_inl(reg, card) readl(card->scabase + (reg)) +#define sca_outl(value, reg, card) writel(value, card->scabase + (reg)) + +#define port_to_card(port) (port->card) +#define log_node(port) (port->phy_node) +#define phy_node(port) (port->phy_node) +#define winbase(card) (card->rambase) +#define get_port(card, port) ((port) < (card)->n_ports ? \ + (&(card)->ports[port]) : (NULL)) + +#include "hd6457x.c" + + +static void pc300_set_iface(port_t *port) +{ + card_t *card = port->card; + u32* init_ctrl = &card->plxbase->init_ctrl; + u16 msci = get_msci(port); + u8 rxs = port->rxs & CLK_BRG_MASK; + u8 txs = port->txs & CLK_BRG_MASK; + + sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, + port_to_card(port)); + switch(port->settings.clock_type) { + case CLOCK_INT: + rxs |= CLK_BRG; /* BRG output */ + txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ + break; + + case CLOCK_TXINT: + rxs |= CLK_LINE; /* RXC input */ + txs |= CLK_PIN_OUT | CLK_BRG; /* BRG output */ + break; + + case CLOCK_TXFROMRX: + rxs |= CLK_LINE; /* RXC input */ + txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */ + break; + + default: /* EXTernal clock */ + rxs |= CLK_LINE; /* RXC input */ + txs |= CLK_PIN_OUT | CLK_LINE; /* TXC input */ + break; + } + + port->rxs = rxs; + port->txs = txs; + sca_out(rxs, msci + RXS, card); + sca_out(txs, msci + TXS, card); + sca_set_port(port); + + if (port->card->type == PC300_RSV) { + if (port->iface == IF_IFACE_V35) + writel(card->init_ctrl_value | + PC300_CHMEDIA_MASK(port->phy_node), init_ctrl); + else + writel(card->init_ctrl_value & + ~PC300_CHMEDIA_MASK(port->phy_node), init_ctrl); + } +} + + + +static int pc300_open(struct net_device *dev) +{ + port_t *port = dev_to_port(dev); + + int result = hdlc_open(dev); + if (result) + return result; + + sca_open(dev); + pc300_set_iface(port); + return 0; +} + + + +static int pc300_close(struct net_device *dev) +{ + sca_close(dev); + hdlc_close(dev); + return 0; +} + + + +static int pc300_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line; + sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; + int new_type; + port_t *port = dev_to_port(dev); + +#ifdef DEBUG_RINGS + if (cmd == SIOCDEVPRIVATE) { + sca_dump_rings(dev); + return 0; + } +#endif + if (cmd != SIOCWANDEV) + return hdlc_ioctl(dev, ifr, cmd); + + if (ifr->ifr_settings.type == IF_GET_IFACE) { + ifr->ifr_settings.type = port->iface; + if (ifr->ifr_settings.size < size) { + ifr->ifr_settings.size = size; /* data size wanted */ + return -ENOBUFS; + } + if (copy_to_user(line, &port->settings, size)) + return -EFAULT; + return 0; + + } + + if (port->card->type == PC300_X21 && + (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL || + ifr->ifr_settings.type == IF_IFACE_X21)) + new_type = IF_IFACE_X21; + + else if (port->card->type == PC300_RSV && + (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL || + ifr->ifr_settings.type == IF_IFACE_V35)) + new_type = IF_IFACE_V35; + + else if (port->card->type == PC300_RSV && + ifr->ifr_settings.type == IF_IFACE_V24) + new_type = IF_IFACE_V24; + + else + return hdlc_ioctl(dev, ifr, cmd); + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (copy_from_user(&new_line, line, size)) + return -EFAULT; + + if (new_line.clock_type != CLOCK_EXT && + new_line.clock_type != CLOCK_TXFROMRX && + new_line.clock_type != CLOCK_INT && + new_line.clock_type != CLOCK_TXINT) + return -EINVAL; /* No such clock setting */ + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + memcpy(&port->settings, &new_line, size); /* Update settings */ + port->iface = new_type; + pc300_set_iface(port); + return 0; +} + + + +static void pc300_pci_remove_one(struct pci_dev *pdev) +{ + int i; + card_t *card = pci_get_drvdata(pdev); + + for (i = 0; i < 2; i++) + if (card->ports[i].card) { + struct net_device *dev = port_to_dev(&card->ports[i]); + unregister_hdlc_device(dev); + } + + if (card->irq) + free_irq(card->irq, card); + + if (card->rambase) + iounmap(card->rambase); + if (card->scabase) + iounmap(card->scabase); + if (card->plxbase) + iounmap(card->plxbase); + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + if (card->ports[0].dev) + free_netdev(card->ports[0].dev); + if (card->ports[1].dev) + free_netdev(card->ports[1].dev); + kfree(card); +} + + + +static int __devinit pc300_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + card_t *card; + u8 rev_id; + u32 __iomem *p; + int i; + u32 ramsize; + u32 ramphys; /* buffer memory base */ + u32 scaphys; /* SCA memory base */ + u32 plxphys; /* PLX registers memory base */ + +#ifndef MODULE + static int printed_version; + if (!printed_version++) + printk(KERN_INFO "%s\n", version); +#endif + + i = pci_enable_device(pdev); + if (i) + return i; + + i = pci_request_regions(pdev, "PC300"); + if (i) { + pci_disable_device(pdev); + return i; + } + + card = kmalloc(sizeof(card_t), GFP_KERNEL); + if (card == NULL) { + printk(KERN_ERR "pc300: unable to allocate memory\n"); + pci_release_regions(pdev); + pci_disable_device(pdev); + return -ENOBUFS; + } + memset(card, 0, sizeof(card_t)); + pci_set_drvdata(pdev, card); + + if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 || + pdev->device == PCI_DEVICE_ID_PC300_TE_2) + card->type = PC300_TE; /* not fully supported */ + else if (card->init_ctrl_value & PC300_CTYPE_MASK) + card->type = PC300_X21; + else + card->type = PC300_RSV; + + if (pdev->device == PCI_DEVICE_ID_PC300_RX_1 || + pdev->device == PCI_DEVICE_ID_PC300_TE_1) + card->n_ports = 1; + else + card->n_ports = 2; + + for (i = 0; i < card->n_ports; i++) + if (!(card->ports[i].dev = alloc_hdlcdev(&card->ports[i]))) { + printk(KERN_ERR "pc300: unable to allocate memory\n"); + pc300_pci_remove_one(pdev); + return -ENOMEM; + } + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); + if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE || + pci_resource_len(pdev, 2) != PC300_SCA_SIZE || + pci_resource_len(pdev, 3) < 16384) { + printk(KERN_ERR "pc300: invalid card EEPROM parameters\n"); + pc300_pci_remove_one(pdev); + return -EFAULT; + } + + plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK; + card->plxbase = ioremap(plxphys, PC300_PLX_SIZE); + + scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK; + card->scabase = ioremap(scaphys, PC300_SCA_SIZE); + + ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK; + card->rambase = ioremap(ramphys, pci_resource_len(pdev,3)); + + if (card->plxbase == NULL || + card->scabase == NULL || + card->rambase == NULL) { + printk(KERN_ERR "pc300: ioremap() failed\n"); + pc300_pci_remove_one(pdev); + } + + /* PLX PCI 9050 workaround for local configuration register read bug */ + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, scaphys); + card->init_ctrl_value = readl(&((plx9050*)card->scabase)->init_ctrl); + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys); + + /* Reset PLX */ + p = &card->plxbase->init_ctrl; + writel(card->init_ctrl_value | 0x40000000, p); + readl(p); /* Flush the write - do not use sca_flush */ + udelay(1); + + writel(card->init_ctrl_value, p); + readl(p); /* Flush the write - do not use sca_flush */ + udelay(1); + + /* Reload Config. Registers from EEPROM */ + writel(card->init_ctrl_value | 0x20000000, p); + readl(p); /* Flush the write - do not use sca_flush */ + udelay(1); + + writel(card->init_ctrl_value, p); + readl(p); /* Flush the write - do not use sca_flush */ + udelay(1); + + ramsize = sca_detect_ram(card, card->rambase, + pci_resource_len(pdev, 3)); + + if (use_crystal_clock) + card->init_ctrl_value &= ~PC300_CLKSEL_MASK; + else + card->init_ctrl_value |= PC300_CLKSEL_MASK; + + writel(card->init_ctrl_value, &card->plxbase->init_ctrl); + /* number of TX + RX buffers for one port */ + i = ramsize / (card->n_ports * (sizeof(pkt_desc) + HDLC_MAX_MRU)); + card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS); + card->rx_ring_buffers = i - card->tx_ring_buffers; + + card->buff_offset = card->n_ports * sizeof(pkt_desc) * + (card->tx_ring_buffers + card->rx_ring_buffers); + + printk(KERN_INFO "pc300: PC300/%s, %u KB RAM at 0x%x, IRQ%u, " + "using %u TX + %u RX packets rings\n", + card->type == PC300_X21 ? "X21" : + card->type == PC300_TE ? "TE" : "RSV", + ramsize / 1024, ramphys, pdev->irq, + card->tx_ring_buffers, card->rx_ring_buffers); + + if (card->tx_ring_buffers < 1) { + printk(KERN_ERR "pc300: RAM test failed\n"); + pc300_pci_remove_one(pdev); + return -EFAULT; + } + + /* Enable interrupts on the PCI bridge, LINTi1 active low */ + writew(0x0041, &card->plxbase->intr_ctrl_stat); + + /* Allocate IRQ */ + if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) { + printk(KERN_WARNING "pc300: could not allocate IRQ%d.\n", + pdev->irq); + pc300_pci_remove_one(pdev); + return -EBUSY; + } + card->irq = pdev->irq; + + sca_init(card, 0); + + // COTE not set - allows better TX DMA settings + // sca_out(sca_in(PCR, card) | PCR_COTE, PCR, card); + + sca_out(0x10, BTCR, card); + + for (i = 0; i < card->n_ports; i++) { + port_t *port = &card->ports[i]; + struct net_device *dev = port_to_dev(port); + hdlc_device *hdlc = dev_to_hdlc(dev); + port->phy_node = i; + + spin_lock_init(&port->lock); + SET_MODULE_OWNER(dev); + dev->irq = card->irq; + dev->mem_start = ramphys; + dev->mem_end = ramphys + ramsize - 1; + dev->tx_queue_len = 50; + dev->do_ioctl = pc300_ioctl; + dev->open = pc300_open; + dev->stop = pc300_close; + hdlc->attach = sca_attach; + hdlc->xmit = sca_xmit; + port->settings.clock_type = CLOCK_EXT; + port->card = card; + if (card->type == PC300_X21) + port->iface = IF_IFACE_X21; + else + port->iface = IF_IFACE_V35; + + if (register_hdlc_device(dev)) { + printk(KERN_ERR "pc300: unable to register hdlc " + "device\n"); + port->card = NULL; + pc300_pci_remove_one(pdev); + return -ENOBUFS; + } + sca_init_sync_port(port); /* Set up SCA memory */ + + printk(KERN_INFO "%s: PC300 node %d\n", + dev->name, port->phy_node); + } + return 0; +} + + + +static struct pci_device_id pc300_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_1, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_2, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_1, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_2, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + + +static struct pci_driver pc300_pci_driver = { + name: "PC300", + id_table: pc300_pci_tbl, + probe: pc300_pci_init_one, + remove: pc300_pci_remove_one, +}; + + +static int __init pc300_init_module(void) +{ +#ifdef MODULE + printk(KERN_INFO "%s\n", version); +#endif + if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) { + printk(KERN_ERR "pc300: Invalid PCI clock frequency\n"); + return -EINVAL; + } + if (use_crystal_clock != 0 && use_crystal_clock != 1) { + printk(KERN_ERR "pc300: Invalid 'use_crystal_clock' value\n"); + return -EINVAL; + } + + CLOCK_BASE = use_crystal_clock ? 24576000 : pci_clock_freq; + + return pci_module_init(&pc300_pci_driver); +} + + + +static void __exit pc300_cleanup_module(void) +{ + pci_unregister_driver(&pc300_pci_driver); +} + +MODULE_AUTHOR("Krzysztof Halasa "); +MODULE_DESCRIPTION("Cyclades PC300 serial port driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(pci, pc300_pci_tbl); +module_param(pci_clock_freq, int, 0444); +MODULE_PARM_DESC(pci_clock_freq, "System PCI clock frequency in Hz"); +module_param(use_crystal_clock, int, 0444); +MODULE_PARM_DESC(use_crystal_clock, + "Use 24.576 MHz clock instead of PCI clock"); +module_init(pc300_init_module); +module_exit(pc300_cleanup_module); diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index 59ddd21c3958..8dbcf83bb5f3 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -331,8 +331,7 @@ static void z8530_rtsdtr(struct z8530_channel *c, int set) static void z8530_rx(struct z8530_channel *c) { u8 ch,stat; - spin_lock(c->lock); - + while(1) { /* FIFO empty ? */ @@ -390,7 +389,6 @@ static void z8530_rx(struct z8530_channel *c) */ write_zsctrl(c, ERR_RES); write_zsctrl(c, RES_H_IUS); - spin_unlock(c->lock); } @@ -406,7 +404,6 @@ static void z8530_rx(struct z8530_channel *c) static void z8530_tx(struct z8530_channel *c) { - spin_lock(c->lock); while(c->txcount) { /* FIFO full ? */ if(!(read_zsreg(c, R0)&4)) @@ -434,7 +431,6 @@ static void z8530_tx(struct z8530_channel *c) z8530_tx_done(c); write_zsctrl(c, RES_H_IUS); - spin_unlock(c->lock); } /** @@ -452,7 +448,6 @@ static void z8530_status(struct z8530_channel *chan) { u8 status, altered; - spin_lock(chan->lock); status=read_zsreg(chan, R0); altered=chan->status^status; @@ -487,7 +482,6 @@ static void z8530_status(struct z8530_channel *chan) } write_zsctrl(chan, RES_EXT_INT); write_zsctrl(chan, RES_H_IUS); - spin_unlock(chan->lock); } struct z8530_irqhandler z8530_sync= @@ -511,7 +505,6 @@ EXPORT_SYMBOL(z8530_sync); static void z8530_dma_rx(struct z8530_channel *chan) { - spin_lock(chan->lock); if(chan->rxdma_on) { /* Special condition check only */ @@ -534,7 +527,6 @@ static void z8530_dma_rx(struct z8530_channel *chan) /* DMA is off right now, drain the slow way */ z8530_rx(chan); } - spin_unlock(chan->lock); } /** @@ -547,7 +539,6 @@ static void z8530_dma_rx(struct z8530_channel *chan) static void z8530_dma_tx(struct z8530_channel *chan) { - spin_lock(chan->lock); if(!chan->dma_tx) { printk(KERN_WARNING "Hey who turned the DMA off?\n"); @@ -557,7 +548,6 @@ static void z8530_dma_tx(struct z8530_channel *chan) /* This shouldnt occur in DMA mode */ printk(KERN_ERR "DMA tx - bogus event!\n"); z8530_tx(chan); - spin_unlock(chan->lock); } /** @@ -596,7 +586,6 @@ static void z8530_dma_status(struct z8530_channel *chan) } } - spin_lock(chan->lock); if(altered&chan->dcdcheck) { if(status&chan->dcdcheck) @@ -618,7 +607,6 @@ static void z8530_dma_status(struct z8530_channel *chan) write_zsctrl(chan, RES_EXT_INT); write_zsctrl(chan, RES_H_IUS); - spin_unlock(chan->lock); } struct z8530_irqhandler z8530_dma_sync= diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 8286678513b9..3a064def162e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -352,6 +352,10 @@ #define BCM43xx_UCODEFLAG_UNKPACTRL 0x0040 #define BCM43xx_UCODEFLAG_JAPAN 0x0080 +/* Hardware Radio Enable masks */ +#define BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16) +#define BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4) + /* Generic-Interrupt reasons. */ #define BCM43xx_IRQ_READY (1 << 0) #define BCM43xx_IRQ_BEACON (1 << 1) @@ -758,7 +762,8 @@ struct bcm43xx_private { bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ short_preamble:1, /* TRUE, if short preamble is enabled. */ - firmware_norelease:1; /* Do not release the firmware. Used on suspend. */ + firmware_norelease:1, /* Do not release the firmware. Used on suspend. */ + radio_hw_enable:1; /* TRUE if radio is hardware enabled */ struct bcm43xx_stats stats; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index 7d383a27b927..8f198befba39 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -26,6 +26,7 @@ */ #include "bcm43xx_leds.h" +#include "bcm43xx_radio.h" #include "bcm43xx.h" #include @@ -108,6 +109,7 @@ static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm, switch (led_index) { case 0: led->behaviour = BCM43xx_LED_ACTIVITY; + led->activelow = 1; if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ) led->behaviour = BCM43xx_LED_RADIO_ALL; break; @@ -199,20 +201,21 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) turn_on = activity; break; case BCM43xx_LED_RADIO_ALL: - turn_on = radio->enabled; + turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm); break; case BCM43xx_LED_RADIO_A: case BCM43xx_LED_BCM4303_2: - turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A); + turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) && + phy->type == BCM43xx_PHYTYPE_A); break; case BCM43xx_LED_RADIO_B: case BCM43xx_LED_BCM4303_1: - turn_on = (radio->enabled && + turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) && (phy->type == BCM43xx_PHYTYPE_B || phy->type == BCM43xx_PHYTYPE_G)); break; case BCM43xx_LED_MODE_BG: - if (phy->type == BCM43xx_PHYTYPE_G && + if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) && 1/*FIXME: using G rates.*/) turn_on = 1; break; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 91b752e3d07e..23aaf1ed8541 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2441,6 +2441,9 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) if (err) goto err_gpio_cleanup; bcm43xx_radio_turn_on(bcm); + bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm); + dprintk(KERN_INFO PFX "Radio %s by hardware\n", + (bcm->radio_hw_enable == 0) ? "disabled" : "enabled"); bcm43xx_write16(bcm, 0x03E6, 0x0000); err = bcm43xx_phy_init(bcm); @@ -3174,10 +3177,25 @@ static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm) } static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm) +{ + bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning? + //TODO for APHY (temperature?) +} + +static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm) { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + int radio_hw_enable; + /* check if radio hardware enabled status changed */ + radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm); + if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) { + bcm->radio_hw_enable = radio_hw_enable; + dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n", + (radio_hw_enable == 0) ? "disabled" : "enabled"); + bcm43xx_leds_update(bcm, 0); + } if (phy->type == BCM43xx_PHYTYPE_G) { //TODO: update_aci_moving_average if (radio->aci_enable && radio->aci_wlan_automatic) { @@ -3201,21 +3219,21 @@ static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm) //TODO: implement rev1 workaround } } - bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning? - //TODO for APHY (temperature?) } static void do_periodic_work(struct bcm43xx_private *bcm) { - if (bcm->periodic_state % 8 == 0) + if (bcm->periodic_state % 120 == 0) bcm43xx_periodic_every120sec(bcm); - if (bcm->periodic_state % 4 == 0) + if (bcm->periodic_state % 60 == 0) bcm43xx_periodic_every60sec(bcm); - if (bcm->periodic_state % 2 == 0) + if (bcm->periodic_state % 30 == 0) bcm43xx_periodic_every30sec(bcm); - bcm43xx_periodic_every15sec(bcm); + if (bcm->periodic_state % 15 == 0) + bcm43xx_periodic_every15sec(bcm); + bcm43xx_periodic_every1sec(bcm); - schedule_delayed_work(&bcm->periodic_work, HZ * 15); + schedule_delayed_work(&bcm->periodic_work, HZ); } static void bcm43xx_periodic_work_handler(struct work_struct *work) @@ -3228,7 +3246,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work) unsigned long orig_trans_start = 0; mutex_lock(&bcm->mutex); - if (unlikely(bcm->periodic_state % 4 == 0)) { + if (unlikely(bcm->periodic_state % 60 == 0)) { /* Periodic work will take a long time, so we want it to * be preemtible. */ @@ -3260,7 +3278,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work) do_periodic_work(bcm); - if (unlikely(bcm->periodic_state % 4 == 0)) { + if (unlikely(bcm->periodic_state % 60 == 0)) { spin_lock_irqsave(&bcm->irq_lock, flags); tasklet_enable(&bcm->isr_tasklet); bcm43xx_interrupt_enable(bcm, savedirqs); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index bb9c484d7e19..af19a07032a3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -1981,6 +1981,7 @@ void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm) } radio->enabled = 1; dprintk(KERN_INFO PFX "Radio turned on\n"); + bcm43xx_leds_update(bcm, 0); } void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) @@ -2001,6 +2002,7 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0015, 0xAA00); radio->enabled = 0; dprintk(KERN_INFO PFX "Radio turned off\n"); + bcm43xx_leds_update(bcm, 0); } void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h index 9ed18039fa3e..77a98a53a2e2 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h @@ -65,6 +65,22 @@ void bcm43xx_radio_init2060(struct bcm43xx_private *bcm); void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm); void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm); +static inline +int bcm43xx_is_hw_radio_enabled(struct bcm43xx_private *bcm) +{ + /* function to return state of hardware enable of radio + * returns 0 if radio disabled, 1 if radio enabled + */ + if (bcm->current_core->rev >= 3) + return ((bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) + & BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK) + == 0) ? 1 : 0; + else + return ((bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) + & BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK) + == 0) ? 0 : 1; +} + int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel, int synthetic_pu_workaround); 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/ipw2200.c b/drivers/net/wireless/ipw2200.c index 22cb3fb7502e..c878a2f3239c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -9166,7 +9166,7 @@ static int ipw_wx_set_rts(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); mutex_lock(&priv->mutex); - if (wrqu->rts.disabled) + if (wrqu->rts.disabled || !wrqu->rts.fixed) priv->rts_threshold = DEFAULT_RTS_THRESHOLD; else { if (wrqu->rts.value < MIN_RTS_THRESHOLD || @@ -9255,7 +9255,7 @@ static int ipw_wx_set_frag(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); mutex_lock(&priv->mutex); - if (wrqu->frag.disabled) + if (wrqu->frag.disabled || !wrqu->frag.fixed) priv->ieee->fts = DEFAULT_FTS; else { if (wrqu->frag.value < MIN_FRAG_THRESHOLD || diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 936c888e03e1..4e7f6cf51436 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -2059,7 +2059,7 @@ static int determine_firmware(struct net_device *dev) int err; struct comp_id nic_id, sta_id; unsigned int firmver; - char tmp[SYMBOL_MAX_VER_LEN+1]; + char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2))); /* Get the hardware version */ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id); @@ -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/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index f057fd9fcd79..a037b11dac9d 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -787,6 +788,17 @@ islpci_set_multicast_list(struct net_device *dev) } #endif +static void islpci_ethtool_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); +} + +static struct ethtool_ops islpci_ethtool_ops = { + .get_drvinfo = islpci_ethtool_get_drvinfo, +}; + struct net_device * islpci_setup(struct pci_dev *pdev) { @@ -813,6 +825,7 @@ islpci_setup(struct pci_dev *pdev) ndev->do_ioctl = &prism54_ioctl; ndev->wireless_handlers = (struct iw_handler_def *) &prism54_handler_def; + ndev->ethtool_ops = &islpci_ethtool_ops; ndev->hard_start_xmit = &islpci_eth_transmit; /* ndev->set_multicast_list = &islpci_set_multicast_list; */ diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h index a9aa1662eaa4..736666da6c24 100644 --- a/drivers/net/wireless/prism54/islpci_dev.h +++ b/drivers/net/wireless/prism54/islpci_dev.h @@ -211,4 +211,8 @@ islpci_trigger(islpci_private *priv) int islpci_free_memory(islpci_private *); struct net_device *islpci_setup(struct pci_dev *); + +#define DRV_NAME "prism54" +#define DRV_VERSION "1.2" + #endif /* _ISLPCI_DEV_H */ diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index 58257b40c043..3dcb13bb7d57 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -28,9 +28,6 @@ #include "islpci_mgt.h" /* for pc_debug */ #include "isl_oid.h" -#define DRV_NAME "prism54" -#define DRV_VERSION "1.2" - MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team "); MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter"); MODULE_LICENSE("GPL"); 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/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 78ea72fb8f0c..12dfc0b6efe6 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -84,6 +84,18 @@ static void print_id(struct zd_chip *chip) dev_info(zd_chip_dev(chip), "%s\n", buffer); } +static zd_addr_t inc_addr(zd_addr_t addr) +{ + u16 a = (u16)addr; + /* Control registers use byte addressing, but everything else uses word + * addressing. */ + if ((a & 0xf000) == CR_START) + a += 2; + else + a += 1; + return (zd_addr_t)a; +} + /* Read a variable number of 32-bit values. Parameter count is not allowed to * exceed USB_MAX_IOREAD32_COUNT. */ @@ -114,7 +126,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr for (i = 0; i < count; i++) { int j = 2*i; /* We read the high word always first. */ - a16[j] = zd_inc_word(addr[i]); + a16[j] = inc_addr(addr[i]); a16[j+1] = addr[i]; } @@ -163,7 +175,7 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs, j = 2*i; /* We write the high word always first. */ ioreqs16[j].value = ioreqs[i].value >> 16; - ioreqs16[j].addr = zd_inc_word(ioreqs[i].addr); + ioreqs16[j].addr = inc_addr(ioreqs[i].addr); ioreqs16[j+1].value = ioreqs[i].value; ioreqs16[j+1].addr = ioreqs[i].addr; } @@ -466,7 +478,8 @@ static int read_values(struct zd_chip *chip, u8 *values, size_t count, ZD_ASSERT(mutex_is_locked(&chip->mutex)); for (i = 0;;) { - r = zd_ioread32_locked(chip, &v, e2p_addr+i/2); + r = zd_ioread32_locked(chip, &v, + (zd_addr_t)((u16)e2p_addr+i/2)); if (r) return r; v -= guard; @@ -798,47 +811,18 @@ static int hw_reset_phy(struct zd_chip *chip) static int zd1211_hw_init_hmac(struct zd_chip *chip) { static const struct zd_ioreq32 ioreqs[] = { - { CR_ACK_TIMEOUT_EXT, 0x20 }, - { CR_ADDA_MBIAS_WARMTIME, 0x30000808 }, { CR_ZD1211_RETRY_MAX, 0x2 }, - { CR_SNIFFER_ON, 0 }, - { CR_RX_FILTER, STA_RX_FILTER }, - { CR_GROUP_HASH_P1, 0x00 }, - { CR_GROUP_HASH_P2, 0x80000000 }, - { CR_REG1, 0xa4 }, - { CR_ADDA_PWR_DWN, 0x7f }, - { CR_BCN_PLCP_CFG, 0x00f00401 }, - { CR_PHY_DELAY, 0x00 }, - { CR_ACK_TIMEOUT_EXT, 0x80 }, - { CR_ADDA_PWR_DWN, 0x00 }, - { CR_ACK_TIME_80211, 0x100 }, - { CR_RX_PE_DELAY, 0x70 }, - { CR_PS_CTRL, 0x10000000 }, - { CR_RTS_CTS_RATE, 0x02030203 }, { CR_RX_THRESHOLD, 0x000c0640 }, - { CR_AFTER_PNP, 0x1 }, - { CR_WEP_PROTECT, 0x114 }, }; - int r; - dev_dbg_f(zd_chip_dev(chip), "\n"); ZD_ASSERT(mutex_is_locked(&chip->mutex)); - r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); -#ifdef DEBUG - if (r) { - dev_err(zd_chip_dev(chip), - "error in zd_iowrite32a_locked. Error number %d\n", r); - } -#endif /* DEBUG */ - return r; + return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); } static int zd1211b_hw_init_hmac(struct zd_chip *chip) { static const struct zd_ioreq32 ioreqs[] = { - { CR_ACK_TIMEOUT_EXT, 0x20 }, - { CR_ADDA_MBIAS_WARMTIME, 0x30000808 }, { CR_ZD1211B_RETRY_MAX, 0x02020202 }, { CR_ZD1211B_TX_PWR_CTL4, 0x007f003f }, { CR_ZD1211B_TX_PWR_CTL3, 0x007f003f }, @@ -847,6 +831,20 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip) { CR_ZD1211B_AIFS_CTL1, 0x00280028 }, { CR_ZD1211B_AIFS_CTL2, 0x008C003C }, { CR_ZD1211B_TXOP, 0x01800824 }, + { CR_RX_THRESHOLD, 0x000c0eff, }, + }; + + dev_dbg_f(zd_chip_dev(chip), "\n"); + ZD_ASSERT(mutex_is_locked(&chip->mutex)); + return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); +} + +static int hw_init_hmac(struct zd_chip *chip) +{ + int r; + static const struct zd_ioreq32 ioreqs[] = { + { CR_ACK_TIMEOUT_EXT, 0x20 }, + { CR_ADDA_MBIAS_WARMTIME, 0x30000808 }, { CR_SNIFFER_ON, 0 }, { CR_RX_FILTER, STA_RX_FILTER }, { CR_GROUP_HASH_P1, 0x00 }, @@ -861,25 +859,16 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip) { CR_RX_PE_DELAY, 0x70 }, { CR_PS_CTRL, 0x10000000 }, { CR_RTS_CTS_RATE, 0x02030203 }, - { CR_RX_THRESHOLD, 0x000c0eff, }, { CR_AFTER_PNP, 0x1 }, { CR_WEP_PROTECT, 0x114 }, + { CR_IFS_VALUE, IFS_VALUE_DEFAULT }, }; - int r; - - dev_dbg_f(zd_chip_dev(chip), "\n"); ZD_ASSERT(mutex_is_locked(&chip->mutex)); r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); - if (r) { - dev_dbg_f(zd_chip_dev(chip), - "error in zd_iowrite32a_locked. Error number %d\n", r); - } - return r; -} + if (r) + return r; -static int hw_init_hmac(struct zd_chip *chip) -{ return chip->is_zd1211b ? zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip); } @@ -974,16 +963,14 @@ static int hw_init(struct zd_chip *chip) if (r) return r; - /* Although the vendor driver defaults to a different value during - * init, it overwrites the IFS value with the following every time - * the channel changes. We should aim to be more intelligent... */ - r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE); - if (r) - return r; - return set_beacon_interval(chip, 100); } +static zd_addr_t fw_reg_addr(struct zd_chip *chip, u16 offset) +{ + return (zd_addr_t)((u16)chip->fw_regs_base + offset); +} + #ifdef DEBUG static int dump_cr(struct zd_chip *chip, const zd_addr_t addr, const char *addr_string) @@ -1018,9 +1005,11 @@ static int test_init(struct zd_chip *chip) static void dump_fw_registers(struct zd_chip *chip) { - static const zd_addr_t addr[4] = { - FW_FIRMWARE_VER, FW_USB_SPEED, FW_FIX_TX_RATE, - FW_LINK_STATUS + const zd_addr_t addr[4] = { + fw_reg_addr(chip, FW_REG_FIRMWARE_VER), + fw_reg_addr(chip, FW_REG_USB_SPEED), + fw_reg_addr(chip, FW_REG_FIX_TX_RATE), + fw_reg_addr(chip, FW_REG_LED_LINK_STATUS), }; int r; @@ -1046,7 +1035,8 @@ static int print_fw_version(struct zd_chip *chip) int r; u16 version; - r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER); + r = zd_ioread16_locked(chip, &version, + fw_reg_addr(chip, FW_REG_FIRMWARE_VER)); if (r) return r; @@ -1126,6 +1116,22 @@ int zd_chip_disable_hwint(struct zd_chip *chip) return r; } +static int read_fw_regs_offset(struct zd_chip *chip) +{ + int r; + + ZD_ASSERT(mutex_is_locked(&chip->mutex)); + r = zd_ioread16_locked(chip, (u16*)&chip->fw_regs_base, + FWRAW_REGS_ADDR); + if (r) + return r; + dev_dbg_f(zd_chip_dev(chip), "fw_regs_base: %#06hx\n", + (u16)chip->fw_regs_base); + + return 0; +} + + int zd_chip_init_hw(struct zd_chip *chip, u8 device_type) { int r; @@ -1145,7 +1151,7 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type) if (r) goto out; - r = zd_usb_init_hw(&chip->usb); + r = read_fw_regs_offset(chip); if (r) goto out; @@ -1325,15 +1331,15 @@ u8 zd_chip_get_channel(struct zd_chip *chip) int zd_chip_control_leds(struct zd_chip *chip, enum led_status status) { - static const zd_addr_t a[] = { - FW_LINK_STATUS, + const zd_addr_t a[] = { + fw_reg_addr(chip, FW_REG_LED_LINK_STATUS), CR_LED, }; int r; u16 v[ARRAY_SIZE(a)]; struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = { - [0] = { FW_LINK_STATUS }, + [0] = { fw_reg_addr(chip, FW_REG_LED_LINK_STATUS) }, [1] = { CR_LED }, }; u16 other_led; diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index a4e3cee9b59d..b07569e391ee 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -18,7 +18,6 @@ #ifndef _ZD_CHIP_H #define _ZD_CHIP_H -#include "zd_types.h" #include "zd_rf.h" #include "zd_usb.h" @@ -27,6 +26,37 @@ * adds a processor for handling the USB protocol. */ +/* Address space */ +enum { + /* CONTROL REGISTERS */ + CR_START = 0x9000, + + + /* FIRMWARE */ + FW_START = 0xee00, + + + /* EEPROM */ + E2P_START = 0xf800, + E2P_LEN = 0x800, + + /* EEPROM layout */ + E2P_LOAD_CODE_LEN = 0xe, /* base 0xf800 */ + E2P_LOAD_VECT_LEN = 0x9, /* base 0xf80e */ + /* E2P_DATA indexes into this */ + E2P_DATA_LEN = 0x7e, /* base 0xf817 */ + E2P_BOOT_CODE_LEN = 0x760, /* base 0xf895 */ + E2P_INTR_VECT_LEN = 0xb, /* base 0xfff5 */ + + /* Some precomputed offsets into the EEPROM */ + E2P_DATA_OFFSET = E2P_LOAD_CODE_LEN + E2P_LOAD_VECT_LEN, + E2P_BOOT_CODE_OFFSET = E2P_DATA_OFFSET + E2P_DATA_LEN, +}; + +#define CTL_REG(offset) ((zd_addr_t)(CR_START + (offset))) +#define E2P_DATA(offset) ((zd_addr_t)(E2P_START + E2P_DATA_OFFSET + (offset))) +#define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset))) + /* 8-bit hardware registers */ #define CR0 CTL_REG(0x0000) #define CR1 CTL_REG(0x0004) @@ -302,7 +332,7 @@ #define CR_MAX_PHY_REG 255 -/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211 +/* Taken from the ZYDAS driver, not all of them are relevant for the ZD1211 * driver. */ @@ -594,80 +624,70 @@ /* * Upper 16 bit contains the regulatory domain. */ -#define E2P_SUBID E2P_REG(0x00) -#define E2P_POD E2P_REG(0x02) -#define E2P_MAC_ADDR_P1 E2P_REG(0x04) -#define E2P_MAC_ADDR_P2 E2P_REG(0x06) -#define E2P_PWR_CAL_VALUE1 E2P_REG(0x08) -#define E2P_PWR_CAL_VALUE2 E2P_REG(0x0a) -#define E2P_PWR_CAL_VALUE3 E2P_REG(0x0c) -#define E2P_PWR_CAL_VALUE4 E2P_REG(0x0e) -#define E2P_PWR_INT_VALUE1 E2P_REG(0x10) -#define E2P_PWR_INT_VALUE2 E2P_REG(0x12) -#define E2P_PWR_INT_VALUE3 E2P_REG(0x14) -#define E2P_PWR_INT_VALUE4 E2P_REG(0x16) +#define E2P_SUBID E2P_DATA(0x00) +#define E2P_POD E2P_DATA(0x02) +#define E2P_MAC_ADDR_P1 E2P_DATA(0x04) +#define E2P_MAC_ADDR_P2 E2P_DATA(0x06) +#define E2P_PWR_CAL_VALUE1 E2P_DATA(0x08) +#define E2P_PWR_CAL_VALUE2 E2P_DATA(0x0a) +#define E2P_PWR_CAL_VALUE3 E2P_DATA(0x0c) +#define E2P_PWR_CAL_VALUE4 E2P_DATA(0x0e) +#define E2P_PWR_INT_VALUE1 E2P_DATA(0x10) +#define E2P_PWR_INT_VALUE2 E2P_DATA(0x12) +#define E2P_PWR_INT_VALUE3 E2P_DATA(0x14) +#define E2P_PWR_INT_VALUE4 E2P_DATA(0x16) /* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30) * also only 11 channels. */ -#define E2P_ALLOWED_CHANNEL E2P_REG(0x18) +#define E2P_ALLOWED_CHANNEL E2P_DATA(0x18) -#define E2P_PHY_REG E2P_REG(0x1a) -#define E2P_DEVICE_VER E2P_REG(0x20) -#define E2P_36M_CAL_VALUE1 E2P_REG(0x28) -#define E2P_36M_CAL_VALUE2 E2P_REG(0x2a) -#define E2P_36M_CAL_VALUE3 E2P_REG(0x2c) -#define E2P_36M_CAL_VALUE4 E2P_REG(0x2e) -#define E2P_11A_INT_VALUE1 E2P_REG(0x30) -#define E2P_11A_INT_VALUE2 E2P_REG(0x32) -#define E2P_11A_INT_VALUE3 E2P_REG(0x34) -#define E2P_11A_INT_VALUE4 E2P_REG(0x36) -#define E2P_48M_CAL_VALUE1 E2P_REG(0x38) -#define E2P_48M_CAL_VALUE2 E2P_REG(0x3a) -#define E2P_48M_CAL_VALUE3 E2P_REG(0x3c) -#define E2P_48M_CAL_VALUE4 E2P_REG(0x3e) -#define E2P_48M_INT_VALUE1 E2P_REG(0x40) -#define E2P_48M_INT_VALUE2 E2P_REG(0x42) -#define E2P_48M_INT_VALUE3 E2P_REG(0x44) -#define E2P_48M_INT_VALUE4 E2P_REG(0x46) -#define E2P_54M_CAL_VALUE1 E2P_REG(0x48) /* ??? */ -#define E2P_54M_CAL_VALUE2 E2P_REG(0x4a) -#define E2P_54M_CAL_VALUE3 E2P_REG(0x4c) -#define E2P_54M_CAL_VALUE4 E2P_REG(0x4e) -#define E2P_54M_INT_VALUE1 E2P_REG(0x50) -#define E2P_54M_INT_VALUE2 E2P_REG(0x52) -#define E2P_54M_INT_VALUE3 E2P_REG(0x54) -#define E2P_54M_INT_VALUE4 E2P_REG(0x56) +#define E2P_PHY_REG E2P_DATA(0x1a) +#define E2P_DEVICE_VER E2P_DATA(0x20) +#define E2P_36M_CAL_VALUE1 E2P_DATA(0x28) +#define E2P_36M_CAL_VALUE2 E2P_DATA(0x2a) +#define E2P_36M_CAL_VALUE3 E2P_DATA(0x2c) +#define E2P_36M_CAL_VALUE4 E2P_DATA(0x2e) +#define E2P_11A_INT_VALUE1 E2P_DATA(0x30) +#define E2P_11A_INT_VALUE2 E2P_DATA(0x32) +#define E2P_11A_INT_VALUE3 E2P_DATA(0x34) +#define E2P_11A_INT_VALUE4 E2P_DATA(0x36) +#define E2P_48M_CAL_VALUE1 E2P_DATA(0x38) +#define E2P_48M_CAL_VALUE2 E2P_DATA(0x3a) +#define E2P_48M_CAL_VALUE3 E2P_DATA(0x3c) +#define E2P_48M_CAL_VALUE4 E2P_DATA(0x3e) +#define E2P_48M_INT_VALUE1 E2P_DATA(0x40) +#define E2P_48M_INT_VALUE2 E2P_DATA(0x42) +#define E2P_48M_INT_VALUE3 E2P_DATA(0x44) +#define E2P_48M_INT_VALUE4 E2P_DATA(0x46) +#define E2P_54M_CAL_VALUE1 E2P_DATA(0x48) /* ??? */ +#define E2P_54M_CAL_VALUE2 E2P_DATA(0x4a) +#define E2P_54M_CAL_VALUE3 E2P_DATA(0x4c) +#define E2P_54M_CAL_VALUE4 E2P_DATA(0x4e) +#define E2P_54M_INT_VALUE1 E2P_DATA(0x50) +#define E2P_54M_INT_VALUE2 E2P_DATA(0x52) +#define E2P_54M_INT_VALUE3 E2P_DATA(0x54) +#define E2P_54M_INT_VALUE4 E2P_DATA(0x56) -/* All 16 bit values */ -#define FW_FIRMWARE_VER FW_REG(0) -/* non-zero if USB high speed connection */ -#define FW_USB_SPEED FW_REG(1) -#define FW_FIX_TX_RATE FW_REG(2) -/* Seems to be able to control LEDs over the firmware */ -#define FW_LINK_STATUS FW_REG(3) -#define FW_SOFT_RESET FW_REG(4) -#define FW_FLASH_CHK FW_REG(5) +/* This word contains the base address of the FW_REG_ registers below */ +#define FWRAW_REGS_ADDR FWRAW_DATA(0x1d) +/* All 16 bit values, offset from the address in FWRAW_REGS_ADDR */ +enum { + FW_REG_FIRMWARE_VER = 0, + /* non-zero if USB high speed connection */ + FW_REG_USB_SPEED = 1, + FW_REG_FIX_TX_RATE = 2, + /* Seems to be able to control LEDs over the firmware */ + FW_REG_LED_LINK_STATUS = 3, + FW_REG_SOFT_RESET = 4, + FW_REG_FLASH_CHK = 5, +}; + +/* Values for FW_LINK_STATUS */ #define FW_LINK_OFF 0x0 #define FW_LINK_TX 0x1 /* 0x2 - link led on? */ -enum { - CR_BASE_OFFSET = 0x9000, - FW_START_OFFSET = 0xee00, - FW_BASE_ADDR_OFFSET = FW_START_OFFSET + 0x1d, - EEPROM_START_OFFSET = 0xf800, - EEPROM_SIZE = 0x800, /* words */ - LOAD_CODE_SIZE = 0xe, /* words */ - LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */ - EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE, - EEPROM_REGS_SIZE = 0x7e, /* words */ - E2P_BASE_OFFSET = EEPROM_START_OFFSET + - EEPROM_REGS_OFFSET, -}; - -#define FW_REG_TABLE_ADDR USB_ADDR(FW_START_OFFSET + 0x1d) - enum { /* indices for ofdm_cal_values */ OFDM_36M_INDEX = 0, @@ -679,6 +699,8 @@ struct zd_chip { struct zd_usb usb; struct zd_rf rf; struct mutex mutex; + /* Base address of FW_REG_ registers */ + zd_addr_t fw_regs_base; u8 e2p_mac[ETH_ALEN]; /* EepSetPoint in the vendor driver */ u8 pwr_cal_values[E2P_CHANNEL_COUNT]; diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h index fb22f62cf1f3..deb99d1eaa77 100644 --- a/drivers/net/wireless/zd1211rw/zd_def.h +++ b/drivers/net/wireless/zd1211rw/zd_def.h @@ -23,6 +23,8 @@ #include #include +typedef u16 __nocast zd_addr_t; + #define dev_printk_f(level, dev, fmt, args...) \ dev_printk(level, dev, "%s() " fmt, __func__, ##args) diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h index 26b8298dff8c..c4f36d39642b 100644 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h +++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h @@ -2,7 +2,6 @@ #define _ZD_IEEE80211_H #include -#include "zd_types.h" /* Additional definitions from the standards. */ diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h index 676b3734f1ed..a57732eb69e1 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.h +++ b/drivers/net/wireless/zd1211rw/zd_rf.h @@ -18,8 +18,6 @@ #ifndef _ZD_RF_H #define _ZD_RF_H -#include "zd_types.h" - #define UW2451_RF 0x2 #define UCHIP_RF 0x3 #define AL2230_RF 0x4 diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h deleted file mode 100644 index 0155a1584ed3..000000000000 --- a/drivers/net/wireless/zd1211rw/zd_types.h +++ /dev/null @@ -1,71 +0,0 @@ -/* zd_types.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ZD_TYPES_H -#define _ZD_TYPES_H - -#include - -/* We have three register spaces mapped into the overall USB address space of - * 64K words (16-bit values). There is the control register space of - * double-word registers, the eeprom register space and the firmware register - * space. The control register space is byte mapped, the others are word - * mapped. - * - * For that reason, we are using byte offsets for control registers and word - * offsets for everything else. - */ - -typedef u32 __nocast zd_addr_t; - -enum { - ADDR_BASE_MASK = 0xff000000, - ADDR_OFFSET_MASK = 0x0000ffff, - ADDR_ZERO_MASK = 0x00ff0000, - NULL_BASE = 0x00000000, - USB_BASE = 0x01000000, - CR_BASE = 0x02000000, - CR_MAX_OFFSET = 0x0b30, - E2P_BASE = 0x03000000, - E2P_MAX_OFFSET = 0x007e, - FW_BASE = 0x04000000, - FW_MAX_OFFSET = 0x0005, -}; - -#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK) -#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK) - -#define ZD_ADDR(base, offset) \ - ((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK))) - -#define ZD_NULL_ADDR ((zd_addr_t)0) -#define USB_REG(offset) ZD_ADDR(USB_BASE, offset) /* word addressing */ -#define CTL_REG(offset) ZD_ADDR(CR_BASE, offset) /* byte addressing */ -#define E2P_REG(offset) ZD_ADDR(E2P_BASE, offset) /* word addressing */ -#define FW_REG(offset) ZD_ADDR(FW_BASE, offset) /* word addressing */ - -static inline zd_addr_t zd_inc_word(zd_addr_t addr) -{ - u32 base = ZD_ADDR_BASE(addr); - u32 offset = ZD_OFFSET(addr); - - offset += base == CR_BASE ? 2 : 1; - - return base | offset; -} - -#endif /* _ZD_TYPES_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 605e96e74057..75ef55624d7f 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -58,6 +58,10 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, {} @@ -73,96 +77,6 @@ MODULE_DEVICE_TABLE(usb, usb_ids); #define FW_ZD1211_PREFIX "zd1211/zd1211_" #define FW_ZD1211B_PREFIX "zd1211/zd1211b_" -/* register address handling */ - -#ifdef DEBUG -static int check_addr(struct zd_usb *usb, zd_addr_t addr) -{ - u32 base = ZD_ADDR_BASE(addr); - u32 offset = ZD_OFFSET(addr); - - if ((u32)addr & ADDR_ZERO_MASK) - goto invalid_address; - switch (base) { - case USB_BASE: - break; - case CR_BASE: - if (offset > CR_MAX_OFFSET) { - dev_dbg(zd_usb_dev(usb), - "CR offset %#010x larger than" - " CR_MAX_OFFSET %#10x\n", - offset, CR_MAX_OFFSET); - goto invalid_address; - } - if (offset & 1) { - dev_dbg(zd_usb_dev(usb), - "CR offset %#010x is not a multiple of 2\n", - offset); - goto invalid_address; - } - break; - case E2P_BASE: - if (offset > E2P_MAX_OFFSET) { - dev_dbg(zd_usb_dev(usb), - "E2P offset %#010x larger than" - " E2P_MAX_OFFSET %#010x\n", - offset, E2P_MAX_OFFSET); - goto invalid_address; - } - break; - case FW_BASE: - if (!usb->fw_base_offset) { - dev_dbg(zd_usb_dev(usb), - "ERROR: fw base offset has not been set\n"); - return -EAGAIN; - } - if (offset > FW_MAX_OFFSET) { - dev_dbg(zd_usb_dev(usb), - "FW offset %#10x is larger than" - " FW_MAX_OFFSET %#010x\n", - offset, FW_MAX_OFFSET); - goto invalid_address; - } - break; - default: - dev_dbg(zd_usb_dev(usb), - "address has unsupported base %#010x\n", addr); - goto invalid_address; - } - - return 0; -invalid_address: - dev_dbg(zd_usb_dev(usb), - "ERROR: invalid address: %#010x\n", addr); - return -EINVAL; -} -#endif /* DEBUG */ - -static u16 usb_addr(struct zd_usb *usb, zd_addr_t addr) -{ - u32 base; - u16 offset; - - base = ZD_ADDR_BASE(addr); - offset = ZD_OFFSET(addr); - - ZD_ASSERT(check_addr(usb, addr) == 0); - - switch (base) { - case CR_BASE: - offset += CR_BASE_OFFSET; - break; - case E2P_BASE: - offset += E2P_BASE_OFFSET; - break; - case FW_BASE: - offset += usb->fw_base_offset; - break; - } - - return offset; -} - /* USB device initialization */ static int request_fw_file( @@ -295,14 +209,13 @@ static int handle_version_mismatch(struct usb_device *udev, u8 device_type, if (r) goto error; - r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET, - REBOOT); + r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START, REBOOT); if (r) goto error; - offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16)); + offset = (E2P_BOOT_CODE_OFFSET * sizeof(u16)); r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset, - E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT); + E2P_START + E2P_BOOT_CODE_OFFSET, REBOOT); /* At this point, the vendor driver downloads the whole firmware * image, hacks around with version IDs, and uploads it again, @@ -331,7 +244,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type) if (r) goto error; - fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET); + fw_bcdDevice = get_word(ub_fw->data, E2P_DATA_OFFSET); if (fw_bcdDevice != bcdDevice) { dev_info(&udev->dev, @@ -357,8 +270,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type) if (r) goto error; - r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET, - REBOOT); + r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START, REBOOT); if (r) { dev_err(&udev->dev, "Could not upload firmware code uph. Error number %d\n", @@ -858,7 +770,7 @@ static inline void init_usb_interrupt(struct zd_usb *usb) spin_lock_init(&intr->lock); intr->interval = int_urb_interval(zd_usb_to_usbdev(usb)); init_completion(&intr->read_regs.completion); - intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT)); + intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT); } static inline void init_usb_rx(struct zd_usb *usb) @@ -890,22 +802,6 @@ void zd_usb_init(struct zd_usb *usb, struct net_device *netdev, init_usb_rx(usb); } -int zd_usb_init_hw(struct zd_usb *usb) -{ - int r; - struct zd_chip *chip = zd_usb_to_chip(usb); - - ZD_ASSERT(mutex_is_locked(&chip->mutex)); - r = zd_ioread16_locked(chip, &usb->fw_base_offset, - USB_REG((u16)FW_BASE_ADDR_OFFSET)); - if (r) - return r; - dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n", - usb->fw_base_offset); - - return 0; -} - void zd_usb_clear(struct zd_usb *usb) { usb_set_intfdata(usb->intf, NULL); @@ -1253,7 +1149,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, return -ENOMEM; req->id = cpu_to_le16(USB_REQ_READ_REGS); for (i = 0; i < count; i++) - req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i])); + req->addr[i] = cpu_to_le16((u16)addresses[i]); udev = zd_usb_to_usbdev(usb); prepare_read_regs_int(usb); @@ -1318,7 +1214,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, req->id = cpu_to_le16(USB_REQ_WRITE_REGS); for (i = 0; i < count; i++) { struct reg_data *rw = &req->reg_writes[i]; - rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr)); + rw->addr = cpu_to_le16((u16)ioreqs[i].addr); rw->value = cpu_to_le16(ioreqs[i].value); } diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index 317d37c36679..506ea6a74393 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -25,7 +25,6 @@ #include #include "zd_def.h" -#include "zd_types.h" enum devicetype { DEVICE_ZD1211 = 0, @@ -181,15 +180,14 @@ struct zd_usb_tx { spinlock_t lock; }; -/* Contains the usb parts. The structure doesn't require a lock, because intf - * and fw_base_offset, will not be changed after initialization. +/* Contains the usb parts. The structure doesn't require a lock because intf + * will not be changed after initialization. */ struct zd_usb { struct zd_usb_interrupt intr; struct zd_usb_rx rx; struct zd_usb_tx tx; struct usb_interface *intf; - u16 fw_base_offset; }; #define zd_usb_dev(usb) (&usb->intf->dev) diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index adce4204d87d..be92695a7833 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -145,15 +145,6 @@ config HOTPLUG_PCI_SHPC When in doubt, say N. -config HOTPLUG_PCI_SHPC_POLL_EVENT_MODE - bool "Use polling mechanism for hot-plug events (for testing purpose)" - depends on HOTPLUG_PCI_SHPC - help - Say Y here if you want to use the polling mechanism for hot-plug - events for early platform testing. - - When in doubt, say N. - config HOTPLUG_PCI_RPA tristate "RPA PCI Hotplug driver" depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE 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/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 4fb12fcda563..d19fcae8a7c0 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -44,15 +44,20 @@ extern int pciehp_poll_time; extern int pciehp_debug; extern int pciehp_force; -/*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/ -#define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) - +#define dbg(format, arg...) \ + do { \ + if (pciehp_debug) \ + printk("%s: " format, MY_NAME , ## arg); \ + } while (0) +#define err(format, arg...) \ + printk(KERN_ERR "%s: " format, MY_NAME , ## arg) +#define info(format, arg...) \ + printk(KERN_INFO "%s: " format, MY_NAME , ## arg) +#define warn(format, arg...) \ + printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) +#define SLOT_NAME_SIZE 10 struct slot { - struct slot *next; u8 bus; u8 device; u32 number; @@ -63,6 +68,8 @@ struct slot { struct hpc_ops *hpc_ops; struct hotplug_slot *hotplug_slot; struct list_head slot_list; + char name[SLOT_NAME_SIZE]; + unsigned long last_emi_toggle; }; struct event_info { @@ -70,34 +77,15 @@ struct event_info { u8 hp_slot; }; -typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id); - -struct php_ctlr_state_s { - struct php_ctlr_state_s *pnext; - struct pci_dev *pci_dev; - unsigned int irq; - unsigned long flags; /* spinlock's */ - u32 slot_device_offset; - u32 num_slots; - struct timer_list int_poll_timer; /* Added for poll event */ - php_intr_callback_t attention_button_callback; - php_intr_callback_t switch_change_callback; - php_intr_callback_t presence_change_callback; - php_intr_callback_t power_fault_callback; - void *callback_instance_id; - struct ctrl_reg *creg; /* Ptr to controller register space */ -}; - #define MAX_EVENTS 10 struct controller { struct controller *next; struct mutex crit_sect; /* critical section mutex */ struct mutex ctrl_lock; /* controller lock */ - struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */ int num_slots; /* Number of slots on ctlr */ int slot_num_inc; /* 1 or -1 */ struct pci_dev *pci_dev; - struct pci_bus *pci_bus; + struct list_head slot_list; struct event_info event_queue[MAX_EVENTS]; struct slot *slot; struct hpc_ops *hpc_ops; @@ -112,6 +100,8 @@ struct controller { u8 ctrlcap; u16 vendor_id; u8 cap_base; + struct timer_list poll_timer; + volatile int cmd_busy; }; #define INT_BUTTON_IGNORE 0 @@ -131,8 +121,6 @@ struct controller { #define POWERON_STATE 3 #define POWEROFF_STATE 4 -#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 - /* Error messages */ #define INTERLOCK_OPEN 0x00000002 #define ADD_NOT_SUPPORTED 0x00000003 @@ -144,10 +132,6 @@ struct controller { #define WRONG_BUS_FREQUENCY 0x0000000D #define POWER_FAILURE 0x0000000E -#define REMOVE_NOT_SUPPORTED 0x00000003 - -#define DISABLE_CARD 1 - /* Field definitions in Slot Capabilities Register */ #define ATTN_BUTTN_PRSN 0x00000001 #define PWR_CTRL_PRSN 0x00000002 @@ -155,6 +139,7 @@ struct controller { #define ATTN_LED_PRSN 0x00000008 #define PWR_LED_PRSN 0x00000010 #define HP_SUPR_RM_SUP 0x00000020 +#define EMI_PRSN 0x00020000 #define ATTN_BUTTN(cap) (cap & ATTN_BUTTN_PRSN) #define POWER_CTRL(cap) (cap & PWR_CTRL_PRSN) @@ -162,130 +147,65 @@ struct controller { #define ATTN_LED(cap) (cap & ATTN_LED_PRSN) #define PWR_LED(cap) (cap & PWR_LED_PRSN) #define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP) +#define EMI(cap) (cap & EMI_PRSN) -/* - * error Messages - */ -#define msg_initialization_err "Initialization failure, error=%d\n" -#define msg_button_on "PCI slot #%s - powering on due to button press.\n" -#define msg_button_off "PCI slot #%s - powering off due to button press.\n" -#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n" -#define msg_button_ignore "PCI slot #%s - button press ignored. (action in progress...)\n" - -/* controller functions */ -extern int pciehp_event_start_thread (void); -extern void pciehp_event_stop_thread (void); -extern int pciehp_enable_slot (struct slot *slot); -extern int pciehp_disable_slot (struct slot *slot); - -extern u8 pciehp_handle_attention_button (u8 hp_slot, void *inst_id); -extern u8 pciehp_handle_switch_change (u8 hp_slot, void *inst_id); -extern u8 pciehp_handle_presence_change (u8 hp_slot, void *inst_id); -extern u8 pciehp_handle_power_fault (u8 hp_slot, void *inst_id); -/* extern void long_delay (int delay); */ - -/* pci functions */ -extern int pciehp_configure_device (struct slot *p_slot); -extern int pciehp_unconfigure_device (struct slot *p_slot); - - +extern int pciehp_event_start_thread(void); +extern void pciehp_event_stop_thread(void); +extern int pciehp_enable_slot(struct slot *slot); +extern int pciehp_disable_slot(struct slot *slot); +extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl); +extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl); +extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl); +extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl); +extern int pciehp_configure_device(struct slot *p_slot); +extern int pciehp_unconfigure_device(struct slot *p_slot); +int pcie_init(struct controller *ctrl, struct pcie_device *dev); /* Global variables */ extern struct controller *pciehp_ctrl_list; -/* Inline functions */ - static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) { - struct slot *p_slot, *tmp_slot = NULL; + struct slot *slot; - p_slot = ctrl->slot; - - while (p_slot && (p_slot->device != device)) { - tmp_slot = p_slot; - p_slot = p_slot->next; - } - if (p_slot == NULL) { - err("ERROR: pciehp_find_slot device=0x%x\n", device); - p_slot = tmp_slot; + list_for_each_entry(slot, &ctrl->slot_list, slot_list) { + if (slot->device == device) + return slot; } - return p_slot; + err("%s: slot (device=0x%x) not found\n", __FUNCTION__, device); + return NULL; } -static inline int wait_for_ctrl_irq(struct controller *ctrl) -{ - int retval = 0; - - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&ctrl->queue, &wait); - if (!pciehp_poll_mode) - /* Sleep for up to 1 second */ - msleep_interruptible(1000); - else - msleep_interruptible(2500); - - remove_wait_queue(&ctrl->queue, &wait); - if (signal_pending(current)) - retval = -EINTR; - - return retval; -} - -#define SLOT_NAME_SIZE 10 - -static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot) -{ - snprintf(buffer, buffer_size, "%04d_%04d", slot->bus, slot->number); -} - -enum php_ctlr_type { - PCI, - ISA, - ACPI -}; - -int pcie_init(struct controller *ctrl, struct pcie_device *dev); - -/* This has no meaning for PCI Express, as there is only 1 slot per port */ -int pcie_get_ctlr_slot_config(struct controller *ctrl, - int *num_ctlr_slots, - int *first_device_num, - int *physical_slot_num, - u8 *ctrlcap); - struct hpc_ops { - int (*power_on_slot) (struct slot *slot); - int (*power_off_slot) (struct slot *slot); - int (*get_power_status) (struct slot *slot, u8 *status); - int (*get_attention_status) (struct slot *slot, u8 *status); - int (*set_attention_status) (struct slot *slot, u8 status); - int (*get_latch_status) (struct slot *slot, u8 *status); - int (*get_adapter_status) (struct slot *slot, u8 *status); - - int (*get_max_bus_speed) (struct slot *slot, enum pci_bus_speed *speed); - int (*get_cur_bus_speed) (struct slot *slot, enum pci_bus_speed *speed); - - int (*get_max_lnk_width) (struct slot *slot, enum pcie_link_width *value); - int (*get_cur_lnk_width) (struct slot *slot, enum pcie_link_width *value); - - int (*query_power_fault) (struct slot *slot); - void (*green_led_on) (struct slot *slot); - void (*green_led_off) (struct slot *slot); - void (*green_led_blink) (struct slot *slot); - void (*release_ctlr) (struct controller *ctrl); - int (*check_lnk_status) (struct controller *ctrl); + int (*power_on_slot)(struct slot *slot); + int (*power_off_slot)(struct slot *slot); + int (*get_power_status)(struct slot *slot, u8 *status); + int (*get_attention_status)(struct slot *slot, u8 *status); + int (*set_attention_status)(struct slot *slot, u8 status); + int (*get_latch_status)(struct slot *slot, u8 *status); + int (*get_adapter_status)(struct slot *slot, u8 *status); + int (*get_emi_status)(struct slot *slot, u8 *status); + int (*toggle_emi)(struct slot *slot); + int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); + int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed); + int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val); + int (*get_cur_lnk_width)(struct slot *slot, enum pcie_link_width *val); + int (*query_power_fault)(struct slot *slot); + void (*green_led_on)(struct slot *slot); + void (*green_led_off)(struct slot *slot); + void (*green_led_blink)(struct slot *slot); + void (*release_ctlr)(struct controller *ctrl); + int (*check_lnk_status)(struct controller *ctrl); }; - #ifdef CONFIG_ACPI #include #include #include #include -#define pciehp_get_hp_hw_control_from_firmware(dev) \ +#define pciehp_get_hp_hw_control_from_firmware(dev) \ pciehp_acpi_get_hp_hw_control_from_firmware(dev) static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, struct hotplug_params *hpp) diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index f13f31323e85..a92eda6e02f6 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -34,6 +34,7 @@ #include #include "pciehp.h" #include +#include /* Global variables */ int pciehp_debug; @@ -87,6 +88,95 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { .get_cur_bus_speed = get_cur_bus_speed, }; +/* + * Check the status of the Electro Mechanical Interlock (EMI) + */ +static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = hotplug_slot->private; + return (slot->hpc_ops->get_emi_status(slot, value)); +} + +/* + * sysfs interface for the Electro Mechanical Interlock (EMI) + * 1 == locked, 0 == unlocked + */ +static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf) +{ + int retval; + u8 value; + + retval = get_lock_status(slot, &value); + if (retval) + goto lock_read_exit; + retval = sprintf (buf, "%d\n", value); + +lock_read_exit: + return retval; +} + +/* + * Change the status of the Electro Mechanical Interlock (EMI) + * This is a toggle - in addition there must be at least 1 second + * in between toggles. + */ +static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status) +{ + struct slot *slot = hotplug_slot->private; + int retval; + u8 value; + + mutex_lock(&slot->ctrl->crit_sect); + + /* has it been >1 sec since our last toggle? */ + if ((get_seconds() - slot->last_emi_toggle) < 1) + return -EINVAL; + + /* see what our current state is */ + retval = get_lock_status(hotplug_slot, &value); + if (retval || (value == status)) + goto set_lock_exit; + + slot->hpc_ops->toggle_emi(slot); +set_lock_exit: + mutex_unlock(&slot->ctrl->crit_sect); + return 0; +} + +/* + * sysfs interface which allows the user to toggle the Electro Mechanical + * Interlock. Valid values are either 0 or 1. 0 == unlock, 1 == lock + */ +static ssize_t lock_write_file(struct hotplug_slot *slot, const char *buf, + size_t count) +{ + unsigned long llock; + u8 lock; + int retval = 0; + + llock = simple_strtoul(buf, NULL, 10); + lock = (u8)(llock & 0xff); + + switch (lock) { + case 0: + case 1: + retval = set_lock_status(slot, lock); + break; + default: + err ("%d is an invalid lock value\n", lock); + retval = -EINVAL; + } + if (retval) + return retval; + return count; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_lock = { + .attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = lock_read_file, + .store = lock_write_file +}; + /** * release_slot - free up the memory used by a slot * @hotplug_slot: slot to free @@ -98,148 +188,108 @@ static void release_slot(struct hotplug_slot *hotplug_slot) dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); kfree(slot); } +static void make_slot_name(struct slot *slot) +{ + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", + slot->bus, slot->number); +} + static int init_slots(struct controller *ctrl) { struct slot *slot; - struct hpc_ops *hpc_ops; struct hotplug_slot *hotplug_slot; - struct hotplug_slot_info *hotplug_slot_info; - u8 number_of_slots; - u8 slot_device; - u32 slot_number; - int result = -ENOMEM; + struct hotplug_slot_info *info; + int retval = -ENOMEM; + int i; - number_of_slots = ctrl->num_slots; - slot_device = ctrl->slot_device_offset; - slot_number = ctrl->first_slot; - - while (number_of_slots) { + for (i = 0; i < ctrl->num_slots; i++) { slot = kzalloc(sizeof(*slot), GFP_KERNEL); if (!slot) goto error; - slot->hotplug_slot = - kzalloc(sizeof(*(slot->hotplug_slot)), - GFP_KERNEL); - if (!slot->hotplug_slot) + hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL); + if (!hotplug_slot) goto error_slot; - hotplug_slot = slot->hotplug_slot; + slot->hotplug_slot = hotplug_slot; - hotplug_slot->info = - kzalloc(sizeof(*(hotplug_slot->info)), - GFP_KERNEL); - if (!hotplug_slot->info) + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) goto error_hpslot; - hotplug_slot_info = hotplug_slot->info; - hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if (!hotplug_slot->name) - goto error_info; + hotplug_slot->info = info; + hotplug_slot->name = slot->name; + + slot->hp_slot = i; slot->ctrl = ctrl; - slot->bus = ctrl->slot_bus; - slot->device = slot_device; - slot->hpc_ops = hpc_ops = ctrl->hpc_ops; - + slot->bus = ctrl->pci_dev->subordinate->number; + slot->device = ctrl->slot_device_offset + i; + slot->hpc_ops = ctrl->hpc_ops; slot->number = ctrl->first_slot; - slot->hp_slot = slot_device - ctrl->slot_device_offset; /* register this slot with the hotplug pci core */ hotplug_slot->private = slot; hotplug_slot->release = &release_slot; - make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot); + make_slot_name(slot); hotplug_slot->ops = &pciehp_hotplug_slot_ops; - hpc_ops->get_power_status(slot, - &(hotplug_slot_info->power_status)); - hpc_ops->get_attention_status(slot, - &(hotplug_slot_info->attention_status)); - hpc_ops->get_latch_status(slot, - &(hotplug_slot_info->latch_status)); - hpc_ops->get_adapter_status(slot, - &(hotplug_slot_info->adapter_status)); + get_power_status(hotplug_slot, &info->power_status); + get_attention_status(hotplug_slot, &info->attention_status); + get_latch_status(hotplug_slot, &info->latch_status); + get_adapter_status(hotplug_slot, &info->adapter_status); dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x " - "slot_device_offset=%x\n", - slot->bus, slot->device, slot->hp_slot, slot->number, - ctrl->slot_device_offset); - result = pci_hp_register(hotplug_slot); - if (result) { - err ("pci_hp_register failed with error %d\n", result); - goto error_name; + "slot_device_offset=%x\n", slot->bus, slot->device, + slot->hp_slot, slot->number, ctrl->slot_device_offset); + retval = pci_hp_register(hotplug_slot); + if (retval) { + err ("pci_hp_register failed with error %d\n", retval); + goto error_info; + } + /* create additional sysfs entries */ + if (EMI(ctrl->ctrlcap)) { + retval = sysfs_create_file(&hotplug_slot->kobj, + &hotplug_slot_attr_lock.attr); + if (retval) { + pci_hp_deregister(hotplug_slot); + err("cannot create additional sysfs entries\n"); + goto error_info; + } } - slot->next = ctrl->slot; - ctrl->slot = slot; - - number_of_slots--; - slot_device++; - slot_number += ctrl->slot_num_inc; + list_add(&slot->slot_list, &ctrl->slot_list); } return 0; - -error_name: - kfree(hotplug_slot->name); error_info: - kfree(hotplug_slot_info); + kfree(info); error_hpslot: kfree(hotplug_slot); error_slot: kfree(slot); error: - return result; + return retval; } - -static int cleanup_slots (struct controller * ctrl) +static void cleanup_slots(struct controller *ctrl) { - struct slot *old_slot, *next_slot; + struct list_head *tmp; + struct list_head *next; + struct slot *slot; - old_slot = ctrl->slot; - ctrl->slot = NULL; - - while (old_slot) { - next_slot = old_slot->next; - pci_hp_deregister (old_slot->hotplug_slot); - old_slot = next_slot; + list_for_each_safe(tmp, next, &ctrl->slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + list_del(&slot->slot_list); + if (EMI(ctrl->ctrlcap)) + sysfs_remove_file(&slot->hotplug_slot->kobj, + &hotplug_slot_attr_lock.attr); + pci_hp_deregister(slot->hotplug_slot); } - - - return(0); } -static int get_ctlr_slot_config(struct controller *ctrl) -{ - int num_ctlr_slots; /* Not needed; PCI Express has 1 slot per port*/ - int first_device_num; /* Not needed */ - int physical_slot_num; - u8 ctrlcap; - int rc; - - rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &ctrlcap); - if (rc) { - err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device); - return (-1); - } - - ctrl->num_slots = num_ctlr_slots; /* PCI Express has 1 slot per port */ - ctrl->slot_device_offset = first_device_num; - ctrl->first_slot = physical_slot_num; - ctrl->ctrlcap = ctrlcap; - - dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) ctrlcap(%x) for b:d (%x:%x)\n", - __FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, ctrlcap, - ctrl->bus, ctrl->device); - - return (0); -} - - /* * set_attention_status - Turns the Amber LED for a slot on, off or blink */ @@ -378,8 +428,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ int rc; struct controller *ctrl; struct slot *t_slot; - int first_device_num = 0 ; /* first PCI device number supported by this PCIE */ - int num_ctlr_slots; /* number of slots supported by this HPC */ u8 value; struct pci_dev *pdev; @@ -388,6 +436,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ err("%s : out of memory\n", __FUNCTION__); goto err_out_none; } + INIT_LIST_HEAD(&ctrl->slot_list); pdev = dev->port; ctrl->pci_dev = pdev; @@ -400,13 +449,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ pci_set_drvdata(pdev, ctrl); - ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL); - if (!ctrl->pci_bus) { - err("%s: out of memory\n", __FUNCTION__); - rc = -ENOMEM; - goto err_out_unmap_mmio_region; - } - memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus)); ctrl->bus = pdev->bus->number; /* ctrl bus */ ctrl->slot_bus = pdev->subordinate->number; /* bus controlled by this HPC */ @@ -415,26 +457,14 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__, ctrl->bus, ctrl->device, ctrl->function, pdev->irq); - /* - * Save configuration headers for this and subordinate PCI buses - */ - - rc = get_ctlr_slot_config(ctrl); - if (rc) { - err(msg_initialization_err, rc); - goto err_out_free_ctrl_bus; - } - first_device_num = ctrl->slot_device_offset; - num_ctlr_slots = ctrl->num_slots; - /* Setup the slot information structures */ rc = init_slots(ctrl); if (rc) { - err(msg_initialization_err, 6); - goto err_out_free_ctrl_slot; + err("%s: slot initialization failed\n", PCIE_MODULE_NAME); + goto err_out_release_ctlr; } - t_slot = pciehp_find_slot(ctrl, first_device_num); + t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset); /* Finish setting up the hot plug ctrl device */ ctrl->next_event = 0; @@ -447,32 +477,18 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ pciehp_ctrl_list = ctrl; } - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ - if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ - if (rc) { - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); + if (rc) goto err_out_free_ctrl_slot; - } else - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); } - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); - return 0; err_out_free_ctrl_slot: cleanup_slots(ctrl); -err_out_free_ctrl_bus: - kfree(ctrl->pci_bus); -err_out_unmap_mmio_region: +err_out_release_ctlr: ctrl->hpc_ops->release_ctlr(ctrl); err_out_free_ctrl: kfree(ctrl); @@ -506,8 +522,6 @@ static void __exit unload_pciehpd(void) while (ctrl) { cleanup_slots(ctrl); - kfree (ctrl->pci_bus); - ctrl->hpc_ops->release_ctlr(ctrl); tctrl = ctrl; diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 372c63e35aa9..4283ef56dbd9 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -48,9 +48,8 @@ static inline char *slot_name(struct slot *p_slot) return p_slot->hotplug_slot->name; } -u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) +u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u8 rc = 0; u8 getstatus; @@ -101,9 +100,8 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) } -u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id) +u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u8 rc = 0; u8 getstatus; @@ -143,9 +141,8 @@ u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id) return rc; } -u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id) +u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u8 presence_save, rc = 0; struct event_info *taskInfo; @@ -187,9 +184,8 @@ u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id) return rc; } -u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) +u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) { - struct controller *ctrl = (struct controller *) inst_id; struct slot *p_slot; u8 rc = 0; struct event_info *taskInfo; @@ -233,35 +229,25 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) static void set_slot_off(struct controller *ctrl, struct slot * pslot) { - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ if (POWER_CTRL(ctrl->ctrlcap)) { if (pslot->hpc_ops->power_off_slot(pslot)) { - err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->ctrl_lock); + err("%s: Issue of Slot Power Off command failed\n", + __FUNCTION__); return; } - wait_for_ctrl_irq (ctrl); } - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) pslot->hpc_ops->green_led_off(pslot); - wait_for_ctrl_irq (ctrl); - } - if (ATTN_LED(ctrl->ctrlcap)) { - if (pslot->hpc_ops->set_attention_status(pslot, 1)) { - err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->ctrl_lock); + if (ATTN_LED(ctrl->ctrlcap)) { + if (pslot->hpc_ops->set_attention_status(pslot, 1)) { + err("%s: Issue of Set Attention Led command failed\n", + __FUNCTION__); return; } - wait_for_ctrl_irq (ctrl); } - - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); } /** @@ -274,7 +260,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) static int board_added(struct slot *p_slot) { u8 hp_slot; - int rc = 0; + int retval = 0; struct controller *ctrl = p_slot->ctrl; hp_slot = p_slot->device - ctrl->slot_device_offset; @@ -283,53 +269,38 @@ static int board_added(struct slot *p_slot) __FUNCTION__, p_slot->device, ctrl->slot_device_offset, hp_slot); - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - if (POWER_CTRL(ctrl->ctrlcap)) { /* Power on slot */ - rc = p_slot->hpc_ops->power_on_slot(p_slot); - if (rc) { - mutex_unlock(&ctrl->ctrl_lock); - return -1; - } - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); + retval = p_slot->hpc_ops->power_on_slot(p_slot); + if (retval) + return retval; } - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_blink(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); /* Wait for ~1 second */ - wait_for_ctrl_irq (ctrl); + msleep(1000); - /* Check link training status */ - rc = p_slot->hpc_ops->check_lnk_status(ctrl); - if (rc) { + /* Check link training status */ + retval = p_slot->hpc_ops->check_lnk_status(ctrl); + if (retval) { err("%s: Failed to check link status\n", __FUNCTION__); set_slot_off(ctrl, p_slot); - return rc; + return retval; } /* Check for a power fault */ if (p_slot->hpc_ops->query_power_fault(p_slot)) { dbg("%s: power fault detected\n", __FUNCTION__); - rc = POWER_FAILURE; + retval = POWER_FAILURE; goto err_exit; } - rc = pciehp_configure_device(p_slot); - if (rc) { + retval = pciehp_configure_device(p_slot); + if (retval) { err("Cannot add device 0x%x:%x\n", p_slot->bus, - p_slot->device); + p_slot->device); goto err_exit; } @@ -338,26 +309,16 @@ static int board_added(struct slot *p_slot) */ if (pcie_mch_quirk) pci_fixup_device(pci_fixup_final, ctrl->pci_dev); - if (PWR_LED(ctrl->ctrlcap)) { - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_on(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); - } + return 0; err_exit: set_slot_off(ctrl, p_slot); - return -1; + return retval; } - /** * remove_board - Turns off slot and LED's * @@ -366,44 +327,32 @@ static int remove_board(struct slot *p_slot) { u8 device; u8 hp_slot; - int rc; + int retval = 0; struct controller *ctrl = p_slot->ctrl; - if (pciehp_unconfigure_device(p_slot)) - return 1; + retval = pciehp_unconfigure_device(p_slot); + if (retval) + return retval; device = p_slot->device; - hp_slot = p_slot->device - ctrl->slot_device_offset; p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - if (POWER_CTRL(ctrl->ctrlcap)) { /* power off slot */ - rc = p_slot->hpc_ops->power_off_slot(p_slot); - if (rc) { - err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->ctrl_lock); - return rc; + retval = p_slot->hpc_ops->power_off_slot(p_slot); + if (retval) { + err("%s: Issue of Slot Disable command failed\n", + __FUNCTION__); + return retval; } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); } - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) /* turn off Green LED */ p_slot->hpc_ops->green_led_off(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); return 0; } @@ -448,18 +397,10 @@ static void pciehp_pushbutton_thread(unsigned long slot) dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__, p_slot->bus, p_slot->device); - if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { - /* Wait for exclusive access to hardware */ - mutex_lock(&p_slot->ctrl->ctrl_lock); - + if (pciehp_enable_slot(p_slot) && + PWR_LED(p_slot->ctrl->ctrlcap)) p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (p_slot->ctrl); - - /* Done with exclusive hardware access */ - mutex_unlock(&p_slot->ctrl->ctrl_lock); - } p_slot->state = STATIC_STATE; } @@ -498,18 +439,10 @@ static void pciehp_surprise_rm_thread(unsigned long slot) dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__, p_slot->bus, p_slot->device); - if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { - /* Wait for exclusive access to hardware */ - mutex_lock(&p_slot->ctrl->ctrl_lock); - + if (pciehp_enable_slot(p_slot) && + PWR_LED(p_slot->ctrl->ctrlcap)) p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (p_slot->ctrl); - - /* Done with exclusive hardware access */ - mutex_unlock(&p_slot->ctrl->ctrl_lock); - } p_slot->state = STATIC_STATE; } @@ -620,46 +553,24 @@ static void interrupt_event_handler(struct controller *ctrl) switch (p_slot->state) { case BLINKINGOFF_STATE: - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_on(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - if (ATTN_LED(ctrl->ctrlcap)) { - p_slot->hpc_ops->set_attention_status(p_slot, 0); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); + if (ATTN_LED(ctrl->ctrlcap)) + p_slot->hpc_ops->set_attention_status(p_slot, 0); break; case BLINKINGON_STATE: - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - if (ATTN_LED(ctrl->ctrlcap)){ - p_slot->hpc_ops->set_attention_status(p_slot, 0); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); + if (ATTN_LED(ctrl->ctrlcap)) + p_slot->hpc_ops->set_attention_status(p_slot, 0); break; default: warn("Not a valid state\n"); return; } - info(msg_button_cancel, slot_name(p_slot)); + info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot)); p_slot->state = STATIC_STATE; } /* ***********Button Pressed (No action on 1st press...) */ @@ -672,34 +583,21 @@ static void interrupt_event_handler(struct controller *ctrl) /* slot is on */ dbg("slot is on\n"); p_slot->state = BLINKINGOFF_STATE; - info(msg_button_off, slot_name(p_slot)); + info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot)); } else { /* slot is off */ dbg("slot is off\n"); p_slot->state = BLINKINGON_STATE; - info(msg_button_on, slot_name(p_slot)); + info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot)); } - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - /* blink green LED and turn off amber */ - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_blink(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - if (ATTN_LED(ctrl->ctrlcap)) { + if (ATTN_LED(ctrl->ctrlcap)) p_slot->hpc_ops->set_attention_status(p_slot, 0); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - } - - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); - init_timer(&p_slot->task_event); p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; @@ -712,21 +610,11 @@ static void interrupt_event_handler(struct controller *ctrl) else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { if (POWER_CTRL(ctrl->ctrlcap)) { dbg("power fault\n"); - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->ctrl_lock); - - if (ATTN_LED(ctrl->ctrlcap)) { + if (ATTN_LED(ctrl->ctrlcap)) p_slot->hpc_ops->set_attention_status(p_slot, 1); - wait_for_ctrl_irq (ctrl); - } - if (PWR_LED(ctrl->ctrlcap)) { + if (PWR_LED(ctrl->ctrlcap)) p_slot->hpc_ops->green_led_off(p_slot); - wait_for_ctrl_irq (ctrl); - } - - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->ctrl_lock); } } /***********SURPRISE REMOVAL********************/ @@ -754,7 +642,6 @@ static void interrupt_event_handler(struct controller *ctrl) } } - int pciehp_enable_slot(struct slot *p_slot) { u8 getstatus = 0; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 25d3aadfddbf..fbc64aa2dd68 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "../pci.h" #include "pciehp.h" @@ -105,34 +106,30 @@ enum ctrl_offsets { ROOTCTRL = offsetof(struct ctrl_reg, root_ctrl), ROOTSTATUS = offsetof(struct ctrl_reg, root_status), }; -static int pcie_cap_base = 0; /* Base of the PCI Express capability item structure */ -#define PCIE_CAP_ID(cb) ( cb + PCIECAPID ) -#define NXT_CAP_PTR(cb) ( cb + NXTCAPPTR ) -#define CAP_REG(cb) ( cb + CAPREG ) -#define DEV_CAP(cb) ( cb + DEVCAP ) -#define DEV_CTRL(cb) ( cb + DEVCTRL ) -#define DEV_STATUS(cb) ( cb + DEVSTATUS ) -#define LNK_CAP(cb) ( cb + LNKCAP ) -#define LNK_CTRL(cb) ( cb + LNKCTRL ) -#define LNK_STATUS(cb) ( cb + LNKSTATUS ) -#define SLOT_CAP(cb) ( cb + SLOTCAP ) -#define SLOT_CTRL(cb) ( cb + SLOTCTRL ) -#define SLOT_STATUS(cb) ( cb + SLOTSTATUS ) -#define ROOT_CTRL(cb) ( cb + ROOTCTRL ) -#define ROOT_STATUS(cb) ( cb + ROOTSTATUS ) +static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value) +{ + struct pci_dev *dev = ctrl->pci_dev; + return pci_read_config_word(dev, ctrl->cap_base + reg, value); +} -#define hp_register_read_word(pdev, reg , value) \ - pci_read_config_word(pdev, reg, &value) +static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value) +{ + struct pci_dev *dev = ctrl->pci_dev; + return pci_read_config_dword(dev, ctrl->cap_base + reg, value); +} -#define hp_register_read_dword(pdev, reg , value) \ - pci_read_config_dword(pdev, reg, &value) - -#define hp_register_write_word(pdev, reg , value) \ - pci_write_config_word(pdev, reg, value) +static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value) +{ + struct pci_dev *dev = ctrl->pci_dev; + return pci_write_config_word(dev, ctrl->cap_base + reg, value); +} -#define hp_register_dwrite_word(pdev, reg , value) \ - pci_write_config_dword(pdev, reg, value) +static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) +{ + struct pci_dev *dev = ctrl->pci_dev; + return pci_write_config_dword(dev, ctrl->cap_base + reg, value); +} /* Field definitions in PCI Express Capabilities Register */ #define CAP_VER 0x000F @@ -196,6 +193,7 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct #define ATTN_LED_CTRL 0x00C0 #define PWR_LED_CTRL 0x0300 #define PWR_CTRL 0x0400 +#define EMI_CTRL 0x0800 /* Attention indicator and Power indicator states */ #define LED_ON 0x01 @@ -206,6 +204,10 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct #define POWER_ON 0 #define POWER_OFF 0x0400 +/* EMI Status defines */ +#define EMI_DISENGAGED 0 +#define EMI_ENGAGED 1 + /* Field definitions in Slot Status Register */ #define ATTN_BUTTN_PRESSED 0x0001 #define PWR_FAULT_DETECTED 0x0002 @@ -214,114 +216,117 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct #define CMD_COMPLETED 0x0010 #define MRL_STATE 0x0020 #define PRSN_STATE 0x0040 +#define EMI_STATE 0x0080 +#define EMI_STATUS_BIT 7 static spinlock_t hpc_event_lock; DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ -static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ static int ctlr_seq_num = 0; /* Controller sequence # */ -static spinlock_t list_lock; -static irqreturn_t pcie_isr(int IRQ, void *dev_id); - -static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); +static irqreturn_t pcie_isr(int irq, void *dev_id); +static void start_int_poll_timer(struct controller *ctrl, int sec); /* This is the interrupt polling timeout function. */ -static void int_poll_timeout(unsigned long lphp_ctlr) +static void int_poll_timeout(unsigned long data) { - struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr; + struct controller *ctrl = (struct controller *)data; DBG_ENTER_ROUTINE - if ( !php_ctlr ) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return; - } - /* Poll for interrupt events. regs == NULL => polling */ - pcie_isr( 0, (void *)php_ctlr ); - - init_timer(&php_ctlr->int_poll_timer); + pcie_isr(0, ctrl); + init_timer(&ctrl->poll_timer); if (!pciehp_poll_time) pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ - start_int_poll_timer(php_ctlr, pciehp_poll_time); - - return; + start_int_poll_timer(ctrl, pciehp_poll_time); } /* This function starts the interrupt polling timer. */ -static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) +static void start_int_poll_timer(struct controller *ctrl, int sec) { - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return; + /* Clamp to sane value */ + if ((sec <= 0) || (sec > 60)) + sec = 2; + + ctrl->poll_timer.function = &int_poll_timeout; + ctrl->poll_timer.data = (unsigned long)ctrl; + ctrl->poll_timer.expires = jiffies + sec * HZ; + add_timer(&ctrl->poll_timer); +} + +static inline int pcie_wait_cmd(struct controller *ctrl) +{ + int retval = 0; + unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; + unsigned long timeout = msecs_to_jiffies(msecs); + int rc; + + rc = wait_event_interruptible_timeout(ctrl->queue, + !ctrl->cmd_busy, timeout); + if (!rc) + dbg("Command not completed in 1000 msec\n"); + else if (rc < 0) { + retval = -EINTR; + info("Command was interrupted by a signal\n"); } - if ( ( seconds <= 0 ) || ( seconds > 60 ) ) - seconds = 2; /* Clamp to sane value */ - - php_ctlr->int_poll_timer.function = &int_poll_timeout; - php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */ - php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ; - add_timer(&php_ctlr->int_poll_timer); - - return; + return retval; } static int pcie_write_cmd(struct slot *slot, u16 cmd) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; int retval = 0; u16 slot_status; DBG_ENTER_ROUTINE - - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; + + mutex_lock(&ctrl->ctrl_lock); + + retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); + if (retval) { + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); + goto out; } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); - if (retval) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); - return retval; - } - if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { - /* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue - the next command according to spec. Just print out the error message */ - dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__); + /* After 1 sec and CMD_COMPLETED still not set, just + proceed forward to issue the next command according + to spec. Just print out the error message */ + dbg("%s: CMD_COMPLETED not clear after 1 sec.\n", + __FUNCTION__); } - retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE); + ctrl->cmd_busy = 1; + retval = pciehp_writew(ctrl, SLOTCTRL, (cmd | CMD_CMPL_INTR_ENABLE)); if (retval) { - err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); - return retval; + err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); + goto out; } + /* + * Wait for command completion. + */ + retval = pcie_wait_cmd(ctrl); + out: + mutex_unlock(&ctrl->ctrl_lock); DBG_LEAVE_ROUTINE return retval; } static int hpc_check_lnk_status(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; u16 lnk_status; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(ctrl->cap_base), lnk_status); - + retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { - err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); return retval; } @@ -340,26 +345,21 @@ static int hpc_check_lnk_status(struct controller *ctrl) static int hpc_get_attention_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_ctrl; u8 atten_led_state; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - + retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return retval; } - dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + dbg("%s: SLOTCTRL %x, value read %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6; @@ -385,27 +385,22 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) return 0; } -static int hpc_get_power_status(struct slot * slot, u8 *status) +static int hpc_get_power_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_ctrl; u8 pwr_state; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - + retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return retval; } - dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + dbg("%s: SLOTCTRL %x value read %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); pwr_state = (slot_ctrl & PWR_CTRL) >> 10; @@ -428,21 +423,15 @@ static int hpc_get_power_status(struct slot * slot, u8 *status) static int hpc_get_latch_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_status; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); - + retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); return retval; } @@ -454,22 +443,16 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) static int hpc_get_adapter_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_status; u8 card_state; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); - + retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); return retval; } card_state = (u8)((slot_status & PRSN_STATE) >> 6); @@ -479,24 +462,18 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) return 0; } -static int hpc_query_power_fault(struct slot * slot) +static int hpc_query_power_fault(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_status; u8 pwr_fault; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status); - + retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { - err("%s : Cannot check for power fault\n", __FUNCTION__); + err("%s: Cannot check for power fault\n", __FUNCTION__); return retval; } pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1); @@ -505,28 +482,63 @@ static int hpc_query_power_fault(struct slot * slot) return pwr_fault; } -static int hpc_set_attention_status(struct slot *slot, u8 value) +static int hpc_get_emi_status(struct slot *slot, u8 *status) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; + u16 slot_status; + int retval = 0; + + DBG_ENTER_ROUTINE + + retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); + if (retval) { + err("%s : Cannot check EMI status\n", __FUNCTION__); + return retval; + } + *status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT; + + DBG_LEAVE_ROUTINE + return retval; +} + +static int hpc_toggle_emi(struct slot *slot) +{ + struct controller *ctrl = slot->ctrl; u16 slot_cmd = 0; u16 slot_ctrl; int rc = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - + rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s : hp_register_read_word SLOT_CTRL failed\n", + __FUNCTION__); + return rc; + } + + slot_cmd = (slot_ctrl | EMI_CTRL); + if (!pciehp_poll_mode) + slot_cmd = slot_cmd | HP_INTR_ENABLE; + + pcie_write_cmd(slot, slot_cmd); + slot->last_emi_toggle = get_seconds(); + DBG_LEAVE_ROUTINE + return rc; +} + +static int hpc_set_attention_status(struct slot *slot, u8 value) +{ + struct controller *ctrl = slot->ctrl; + u16 slot_cmd = 0; + u16 slot_ctrl; + int rc = 0; + + DBG_ENTER_ROUTINE + + rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); + if (rc) { + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return rc; } @@ -547,7 +559,8 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) slot_cmd = slot_cmd | HP_INTR_ENABLE; pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); + dbg("%s: SLOTCTRL %x write cmd %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); DBG_LEAVE_ROUTINE return rc; @@ -556,27 +569,16 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) static void hpc_set_green_led_on(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 slot_ctrl; int rc = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return ; - } - - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - + rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return; } slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100; @@ -585,34 +587,24 @@ static void hpc_set_green_led_on(struct slot *slot) pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); + dbg("%s: SLOTCTRL %x write cmd %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); DBG_LEAVE_ROUTINE return; } static void hpc_set_green_led_off(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 slot_ctrl; int rc = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return ; - } - - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - + rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return; } @@ -621,7 +613,8 @@ static void hpc_set_green_led_off(struct slot *slot) if (!pciehp_poll_mode) slot_cmd = slot_cmd | HP_INTR_ENABLE; pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); + dbg("%s: SLOTCTRL %x write cmd %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); DBG_LEAVE_ROUTINE return; @@ -629,27 +622,16 @@ static void hpc_set_green_led_off(struct slot *slot) static void hpc_set_green_led_blink(struct slot *slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 slot_ctrl; int rc = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return ; - } - - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - + rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return; } @@ -659,126 +641,54 @@ static void hpc_set_green_led_blink(struct slot *slot) slot_cmd = slot_cmd | HP_INTR_ENABLE; pcie_write_cmd(slot, slot_cmd); - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); + dbg("%s: SLOTCTRL %x write cmd %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); DBG_LEAVE_ROUTINE return; } -int pcie_get_ctlr_slot_config(struct controller *ctrl, - int *num_ctlr_slots, /* number of slots in this HPC; only 1 in PCIE */ - int *first_device_num, /* PCI dev num of the first slot in this PCIE */ - int *physical_slot_num, /* phy slot num of the first slot in this PCIE */ - u8 *ctrlcap) -{ - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; - u32 slot_cap; - int rc = 0; - - DBG_ENTER_ROUTINE - - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - *first_device_num = 0; - *num_ctlr_slots = 1; - - rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap); - - if (rc) { - err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__); - return -1; - } - - *physical_slot_num = slot_cap >> 19; - dbg("%s: PSN %d \n", __FUNCTION__, *physical_slot_num); - - *ctrlcap = slot_cap & 0x0000007f; - - DBG_LEAVE_ROUTINE - return 0; -} - static void hpc_release_ctlr(struct controller *ctrl) { - struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; - struct php_ctlr_state_s *p, *p_prev; - DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return ; - } - - if (pciehp_poll_mode) { - del_timer(&php_ctlr->int_poll_timer); - } else { - if (php_ctlr->irq) { - free_irq(php_ctlr->irq, ctrl); - php_ctlr->irq = 0; - } - } - if (php_ctlr->pci_dev) - php_ctlr->pci_dev = NULL; - - spin_lock(&list_lock); - p = php_ctlr_list_head; - p_prev = NULL; - while (p) { - if (p == php_ctlr) { - if (p_prev) - p_prev->pnext = p->pnext; - else - php_ctlr_list_head = p->pnext; - break; - } else { - p_prev = p; - p = p->pnext; - } - } - spin_unlock(&list_lock); - - kfree(php_ctlr); + if (pciehp_poll_mode) + del_timer(&ctrl->poll_timer); + else + free_irq(ctrl->pci_dev->irq, ctrl); DBG_LEAVE_ROUTINE - } static int hpc_power_on_slot(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 slot_ctrl, slot_status; - int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } /* Clear sticky power-fault bit from previous power failures */ - hp_register_read_word(php_ctlr->pci_dev, - SLOT_STATUS(slot->ctrl->cap_base), slot_status); - slot_status &= PWR_FAULT_DETECTED; - if (slot_status) - hp_register_write_word(php_ctlr->pci_dev, - SLOT_STATUS(slot->ctrl->cap_base), slot_status); - - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); - + retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (retval) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); + return retval; + } + slot_status &= PWR_FAULT_DETECTED; + if (slot_status) { + retval = pciehp_writew(ctrl, SLOTSTATUS, slot_status); + if (retval) { + err("%s: Cannot write to SLOTSTATUS register\n", + __FUNCTION__); + return retval; + } + } + + retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); + if (retval) { + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return retval; } @@ -798,7 +708,8 @@ static int hpc_power_on_slot(struct slot * slot) err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd); return -1; } - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); + dbg("%s: SLOTCTRL %x write cmd %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); DBG_LEAVE_ROUTINE @@ -807,29 +718,18 @@ static int hpc_power_on_slot(struct slot * slot) static int hpc_power_off_slot(struct slot * slot) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; u16 slot_cmd; u16 slot_ctrl; - int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); - slot->hp_slot = 0; - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl); + retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); return retval; } @@ -854,47 +754,25 @@ static int hpc_power_off_slot(struct slot * slot) err("%s: Write command failed!\n", __FUNCTION__); return -1; } - dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd); + dbg("%s: SLOTCTRL %x write cmd %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd); DBG_LEAVE_ROUTINE return retval; } -static irqreturn_t pcie_isr(int IRQ, void *dev_id) +static irqreturn_t pcie_isr(int irq, void *dev_id) { - struct controller *ctrl = NULL; - struct php_ctlr_state_s *php_ctlr; - u8 schedule_flag = 0; + struct controller *ctrl = (struct controller *)dev_id; u16 slot_status, intr_detect, intr_loc; u16 temp_word; int hp_slot = 0; /* only 1 slot per PCI Express port */ int rc = 0; - if (!dev_id) - return IRQ_NONE; - - if (!pciehp_poll_mode) { - ctrl = dev_id; - php_ctlr = ctrl->hpc_ctlr_handle; - } else { - php_ctlr = dev_id; - ctrl = (struct controller *)php_ctlr->callback_instance_id; - } - - if (!ctrl) { - dbg("%s: dev_id %p ctlr == NULL\n", __FUNCTION__, (void*) dev_id); - return IRQ_NONE; - } - - if (!php_ctlr) { - dbg("%s: php_ctlr == NULL\n", __FUNCTION__); - return IRQ_NONE; - } - - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); return IRQ_NONE; } @@ -910,33 +788,38 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id) dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc); /* Mask Hot-plug Interrupt Enable */ if (!pciehp_poll_mode) { - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOT_CTRL register\n", + __FUNCTION__); return IRQ_NONE; } - dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); + dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n", + __FUNCTION__, temp_word); temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); + if (rc) { + err("%s: Cannot write to SLOTCTRL register\n", + __FUNCTION__); + return IRQ_NONE; + } - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { - err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOT_STATUS register\n", + __FUNCTION__); return IRQ_NONE; } - - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); - if (rc) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); - return IRQ_NONE; - } - dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); + dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n", + __FUNCTION__, slot_status); /* Clear command complete interrupt caused by this write */ temp_word = 0x1f; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTSTATUS register\n", + __FUNCTION__); return IRQ_NONE; } } @@ -945,60 +828,65 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id) /* * Command Complete Interrupt Pending */ + ctrl->cmd_busy = 0; wake_up_interruptible(&ctrl->queue); } - if ((php_ctlr->switch_change_callback) && (intr_loc & MRL_SENS_CHANGED)) - schedule_flag += php_ctlr->switch_change_callback( - hp_slot, php_ctlr->callback_instance_id); - if ((php_ctlr->attention_button_callback) && (intr_loc & ATTN_BUTTN_PRESSED)) - schedule_flag += php_ctlr->attention_button_callback( - hp_slot, php_ctlr->callback_instance_id); - if ((php_ctlr->presence_change_callback) && (intr_loc & PRSN_DETECT_CHANGED)) - schedule_flag += php_ctlr->presence_change_callback( - hp_slot , php_ctlr->callback_instance_id); - if ((php_ctlr->power_fault_callback) && (intr_loc & PWR_FAULT_DETECTED)) - schedule_flag += php_ctlr->power_fault_callback( - hp_slot, php_ctlr->callback_instance_id); + if (intr_loc & MRL_SENS_CHANGED) + pciehp_handle_switch_change(hp_slot, ctrl); + + if (intr_loc & ATTN_BUTTN_PRESSED) + pciehp_handle_attention_button(hp_slot, ctrl); + + if (intr_loc & PRSN_DETECT_CHANGED) + pciehp_handle_presence_change(hp_slot, ctrl); + + if (intr_loc & PWR_FAULT_DETECTED) + pciehp_handle_power_fault(hp_slot, ctrl); /* Clear all events after serving them */ temp_word = 0x1F; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); return IRQ_NONE; } /* Unmask Hot-plug Interrupt Enable */ if (!pciehp_poll_mode) { - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", + __FUNCTION__); return IRQ_NONE; } dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__); temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTCTRL register\n", + __FUNCTION__); return IRQ_NONE; } - - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); + + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOT_STATUS register\n", + __FUNCTION__); return IRQ_NONE; } /* Clear command complete interrupt caused by this write */ temp_word = 0x1F; - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTSTATUS failed\n", + __FUNCTION__); return IRQ_NONE; } - dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word); + dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n", + __FUNCTION__, temp_word); } return IRQ_HANDLED; @@ -1006,27 +894,16 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id) static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; enum pcie_link_speed lnk_speed; u32 lnk_cap; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap); - + retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap); if (retval) { - err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__); + err("%s: Cannot read LNKCAP register\n", __FUNCTION__); return retval; } @@ -1047,27 +924,16 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value) static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; enum pcie_link_width lnk_wdth; u32 lnk_cap; int retval = 0; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap); - + retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap); if (retval) { - err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__); + err("%s: Cannot read LNKCAP register\n", __FUNCTION__); return retval; } @@ -1109,27 +975,16 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN; int retval = 0; u16 lnk_status; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status); - + retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { - err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); return retval; } @@ -1150,27 +1005,16 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value) static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value) { - struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; + struct controller *ctrl = slot->ctrl; enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; int retval = 0; u16 lnk_status; DBG_ENTER_ROUTINE - if (!php_ctlr) { - err("%s: Invalid HPC controller handle!\n", __FUNCTION__); - return -1; - } - - if (slot->hp_slot >= php_ctlr->num_slots) { - err("%s: Invalid HPC slot number!\n", __FUNCTION__); - return -1; - } - - retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status); - + retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { - err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__); return retval; } @@ -1218,6 +1062,8 @@ static struct hpc_ops pciehp_hpc_ops = { .get_attention_status = hpc_get_attention_status, .get_latch_status = hpc_get_latch_status, .get_adapter_status = hpc_get_adapter_status, + .get_emi_status = hpc_get_emi_status, + .toggle_emi = hpc_toggle_emi, .get_max_bus_speed = hpc_get_max_lnk_speed, .get_cur_bus_speed = hpc_get_cur_lnk_speed, @@ -1305,38 +1151,24 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) int pcie_init(struct controller * ctrl, struct pcie_device *dev) { - struct php_ctlr_state_s *php_ctlr, *p; - void *instance_id = ctrl; int rc; static int first = 1; u16 temp_word; u16 cap_reg; u16 intr_enable = 0; u32 slot_cap; - int cap_base, saved_cap_base; + int cap_base; u16 slot_status, slot_ctrl; struct pci_dev *pdev; DBG_ENTER_ROUTINE - spin_lock_init(&list_lock); - php_ctlr = kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL); - - if (!php_ctlr) { /* allocate controller state data */ - err("%s: HPC controller memory allocation error!\n", __FUNCTION__); - goto abort; - } - - memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s)); - pdev = dev->port; - php_ctlr->pci_dev = pdev; /* save pci_dev in context */ + ctrl->pci_dev = pdev; /* save pci_dev in context */ dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", __FUNCTION__, pdev->vendor, pdev->device); - saved_cap_base = pcie_cap_base; - if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) { dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__); goto abort_free_ctlr; @@ -1344,14 +1176,15 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ctrl->cap_base = cap_base; - dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base); + dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base); - rc = hp_register_read_word(pdev, CAP_REG(ctrl->cap_base), cap_reg); + rc = pciehp_readw(ctrl, CAPREG, &cap_reg); if (rc) { - err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__); + err("%s: Cannot read CAPREG register\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG(ctrl->cap_base), cap_reg); + dbg("%s: CAPREG offset %x cap_reg %x\n", + __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg); if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040) && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { @@ -1359,31 +1192,34 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) goto abort_free_ctlr; } - rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap); + rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); if (rc) { - err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCAP register\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP(ctrl->cap_base), slot_cap); + dbg("%s: SLOTCAP offset %x slot_cap %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap); if (!(slot_cap & HP_CAP)) { dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); goto abort_free_ctlr; } /* For debugging purpose */ - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), slot_status); + dbg("%s: SLOTSTATUS offset %x slot_status %x\n", + __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status); - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), slot_ctrl); + rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), slot_ctrl); + dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl); if (first) { spin_lock_init(&hpc_event_lock); @@ -1405,69 +1241,64 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) /* setup wait queue */ init_waitqueue_head(&ctrl->queue); - /* find the IRQ */ - php_ctlr->irq = dev->irq; - - /* Save interrupt callback info */ - php_ctlr->attention_button_callback = pciehp_handle_attention_button; - php_ctlr->switch_change_callback = pciehp_handle_switch_change; - php_ctlr->presence_change_callback = pciehp_handle_presence_change; - php_ctlr->power_fault_callback = pciehp_handle_power_fault; - php_ctlr->callback_instance_id = instance_id; - /* return PCI Controller Info */ - php_ctlr->slot_device_offset = 0; - php_ctlr->num_slots = 1; + ctrl->slot_device_offset = 0; + ctrl->num_slots = 1; + ctrl->first_slot = slot_cap >> 19; + ctrl->ctrlcap = slot_cap & 0x0000007f; /* Mask Hot-plug Interrupt Enable */ - rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); goto abort_free_ctlr; } - dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word); + dbg("%s: SLOTCTRL %x value read %x\n", + __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word); temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; - rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); goto abort_free_ctlr; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); goto abort_free_ctlr; } temp_word = 0x1F; /* Clear all events */ - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); goto abort_free_ctlr; } - if (pciehp_poll_mode) {/* Install interrupt polling code */ - /* Install and start the interrupt polling timer */ - init_timer(&php_ctlr->int_poll_timer); - start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */ + if (pciehp_poll_mode) { + /* Install interrupt polling timer. Start with 10 sec delay */ + init_timer(&ctrl->poll_timer); + start_int_poll_timer(ctrl, 10); } else { /* Installs the interrupt handler */ - rc = request_irq(php_ctlr->irq, pcie_isr, IRQF_SHARED, MY_NAME, (void *) ctrl); - dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc); + rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED, + MY_NAME, (void *)ctrl); + dbg("%s: request_irq %d for hpc%d (returns %d)\n", + __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc); if (rc) { - err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); + err("Can't get irq %d for the hotplug controller\n", + ctrl->pci_dev->irq); goto abort_free_ctlr; } } - dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); - rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (rc) { - err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__); goto abort_free_irq; } @@ -1491,21 +1322,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) } /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */ - rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__); goto abort_free_irq; } - rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); + rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); if (rc) { - err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__); goto abort_disable_intr; } temp_word = 0x1F; /* Clear all events */ - rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); if (rc) { - err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); goto abort_disable_intr; } @@ -1518,24 +1349,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) goto abort_disable_intr; } - /* Add this HPC instance into the HPC list */ - spin_lock(&list_lock); - if (php_ctlr_list_head == 0) { - php_ctlr_list_head = php_ctlr; - p = php_ctlr_list_head; - p->pnext = NULL; - } else { - p = php_ctlr_list_head; - - while (p->pnext) - p = p->pnext; - - p->pnext = php_ctlr; - } - spin_unlock(&list_lock); - ctlr_seq_num++; - ctrl->hpc_ctlr_handle = php_ctlr; ctrl->hpc_ops = &pciehp_hpc_ops; DBG_LEAVE_ROUTINE @@ -1543,24 +1357,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) /* We end up here for the many possible ways to fail this API. */ abort_disable_intr: - rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); if (!rc) { temp_word &= ~(intr_enable | HP_INTR_ENABLE); - rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); + rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); } if (rc) err("%s : disabling interrupts failed\n", __FUNCTION__); abort_free_irq: if (pciehp_poll_mode) - del_timer_sync(&php_ctlr->int_poll_timer); + del_timer_sync(&ctrl->poll_timer); else - free_irq(php_ctlr->irq, ctrl); + free_irq(ctrl->pci_dev->irq, ctrl); abort_free_ctlr: - pcie_cap_base = saved_cap_base; - kfree(php_ctlr); -abort: DBG_LEAVE_ROUTINE return -1; } diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 5d188c558386..78cf0711d1fa 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include "../pci.h" @@ -35,14 +37,17 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)"); MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver"); -#define PCIIO_ASIC_TYPE_TIOCA 4 + +/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */ #define PCI_SLOT_ALREADY_UP 2 /* slot already up */ #define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */ #define PCI_L1_ERR 7 /* L1 console command error */ #define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */ + + +#define PCIIO_ASIC_TYPE_TIOCA 4 #define PCI_L1_QSIZE 128 /* our L1 message buffer size */ #define SN_MAX_HP_SLOTS 32 /* max hotplug slots */ -#define SGI_HOTPLUG_PROM_REV 0x0430 /* Min. required PROM version */ #define SN_SLOT_NAME_SIZE 33 /* size of name string */ /* internal list head */ @@ -227,7 +232,7 @@ static void sn_bus_free_data(struct pci_dev *dev) } static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, - int device_num) + int device_num, char **ssdt) { struct slot *slot = bss_hotplug_slot->private; struct pcibus_info *pcibus_info; @@ -240,7 +245,8 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot, * Power-on and initialize the slot in the SN * PCI infrastructure. */ - rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp); + rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt); + if (rc == PCI_SLOT_ALREADY_UP) { dev_dbg(slot->pci_bus->self, "is already active\n"); @@ -335,6 +341,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) int func, num_funcs; int new_ppb = 0; int rc; + char *ssdt = NULL; void pcibios_fixup_device_resources(struct pci_dev *); /* Serialize the Linux PCI infrastructure */ @@ -342,14 +349,29 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) /* * Power-on and initialize the slot in the SN - * PCI infrastructure. + * PCI infrastructure. Also, retrieve the ACPI SSDT + * table for the slot (if ACPI capable PROM). */ - rc = sn_slot_enable(bss_hotplug_slot, slot->device_num); + rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt); if (rc) { mutex_unlock(&sn_hotplug_mutex); return rc; } + if (ssdt) + ssdt = __va(ssdt); + /* Add the new SSDT for the slot to the ACPI namespace */ + if (SN_ACPI_BASE_SUPPORT() && ssdt) { + acpi_status ret; + + ret = acpi_load_table((struct acpi_table_header *)ssdt); + if (ACPI_FAILURE(ret)) { + printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n", + __FUNCTION__, ret); + /* try to continue on */ + } + } + num_funcs = pci_scan_slot(slot->pci_bus, PCI_DEVFN(slot->device_num + 1, 0)); if (!num_funcs) { @@ -374,7 +396,10 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) * pdi_host_pcidev_info). */ pcibios_fixup_device_resources(dev); - sn_pci_fixup_slot(dev); + if (SN_ACPI_BASE_SUPPORT()) + sn_acpi_slot_fixup(dev); + else + sn_io_slot_fixup(dev); if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { unsigned char sec_bus; pci_read_config_byte(dev, PCI_SECONDARY_BUS, @@ -388,6 +413,63 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) } } + /* + * Add the slot's devices to the ACPI infrastructure */ + if (SN_ACPI_BASE_SUPPORT() && ssdt) { + unsigned long adr; + struct acpi_device *pdevice; + struct acpi_device *device; + acpi_handle phandle; + acpi_handle chandle = NULL; + acpi_handle rethandle; + acpi_status ret; + + phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle; + + if (acpi_bus_get_device(phandle, &pdevice)) { + dev_dbg(slot->pci_bus->self, + "no parent device, assuming NULL\n"); + pdevice = NULL; + } + + /* + * Walk the rootbus node's immediate children looking for + * the slot's device node(s). There can be more than + * one for multifunction devices. + */ + for (;;) { + rethandle = NULL; + ret = acpi_get_next_object(ACPI_TYPE_DEVICE, + phandle, chandle, + &rethandle); + + if (ret == AE_NOT_FOUND || rethandle == NULL) + break; + + chandle = rethandle; + + ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR, + NULL, &adr); + + if (ACPI_SUCCESS(ret) && + (adr>>16) == (slot->device_num + 1)) { + + ret = acpi_bus_add(&device, pdevice, chandle, + ACPI_BUS_TYPE_DEVICE); + if (ACPI_FAILURE(ret)) { + printk(KERN_ERR "%s: acpi_bus_add " + "failed (0x%x) for slot %d " + "func %d\n", __FUNCTION__, + ret, (int)(adr>>16), + (int)(adr&0xffff)); + /* try to continue on */ + } else { + acpi_bus_start(device); + } + } + } + } + /* Call the driver for the new device */ pci_bus_add_devices(slot->pci_bus); /* Call the drivers for the new devices subordinate to PPB */ @@ -412,6 +494,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) struct pci_dev *dev; int func; int rc; + acpi_owner_id ssdt_id = 0; /* Acquire update access to the bus */ mutex_lock(&sn_hotplug_mutex); @@ -422,6 +505,52 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) if (rc) goto leaving; + /* free the ACPI resources for the slot */ + if (SN_ACPI_BASE_SUPPORT() && + PCI_CONTROLLER(slot->pci_bus)->acpi_handle) { + unsigned long adr; + struct acpi_device *device; + acpi_handle phandle; + acpi_handle chandle = NULL; + acpi_handle rethandle; + acpi_status ret; + + /* Get the rootbus node pointer */ + phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle; + + /* + * Walk the rootbus node's immediate children looking for + * the slot's device node(s). There can be more than + * one for multifunction devices. + */ + for (;;) { + rethandle = NULL; + ret = acpi_get_next_object(ACPI_TYPE_DEVICE, + phandle, chandle, + &rethandle); + + if (ret == AE_NOT_FOUND || rethandle == NULL) + break; + + chandle = rethandle; + + ret = acpi_evaluate_integer(chandle, + METHOD_NAME__ADR, + NULL, &adr); + if (ACPI_SUCCESS(ret) && + (adr>>16) == (slot->device_num + 1)) { + /* retain the owner id */ + acpi_get_id(chandle, &ssdt_id); + + ret = acpi_bus_get_device(chandle, + &device); + if (ACPI_SUCCESS(ret)) + acpi_bus_trim(device, 1); + } + } + + } + /* Free the SN resources assigned to the Linux device.*/ for (func = 0; func < 8; func++) { dev = pci_get_slot(slot->pci_bus, @@ -434,6 +563,18 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) } } + /* Remove the SSDT for the slot from the ACPI namespace */ + if (SN_ACPI_BASE_SUPPORT() && ssdt_id) { + acpi_status ret; + ret = acpi_unload_table_id(ssdt_id); + if (ACPI_FAILURE(ret)) { + printk(KERN_ERR "%s: acpi_unload_table_id " + "failed (0x%x) for id %d\n", + __FUNCTION__, ret, ssdt_id); + /* try to continue on */ + } + } + /* free the collected sysdata pointers */ sn_bus_free_sysdata(); diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 3ca6a4f574b3..01d31a1f697c 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -106,7 +106,7 @@ struct controller { }; /* Define AMD SHPC ID */ -#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 +#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 #define PCI_DEVICE_ID_AMD_POGO_7458 0x7458 /* AMD PCIX bridge registers */ @@ -221,7 +221,7 @@ enum ctrl_offsets { }; static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot) -{ +{ return hotplug_slot->private; } diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 590cd3cbe010..5f4bc08a633a 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -401,10 +401,6 @@ static int __init shpcd_init(void) { int retval = 0; -#ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE - shpchp_poll_mode = 1; -#endif - retval = pci_register_driver(&shpc_driver); dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 6bb84734cd6c..b746bd265bc6 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -64,7 +64,7 @@ u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl) /* Attention Button Change */ dbg("shpchp: Attention button interrupt received.\n"); - + p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); @@ -128,7 +128,7 @@ u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl) p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - /* + /* * Save the presence state */ p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save)); @@ -184,12 +184,12 @@ u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl) return 1; } -/* The following routines constitute the bulk of the +/* The following routines constitute the bulk of the hotplug controller logic */ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, enum pci_bus_speed speed) -{ +{ int rc = 0; dbg("%s: change to speed %d\n", __FUNCTION__, speed); @@ -204,7 +204,7 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot, static int fix_bus_speed(struct controller *ctrl, struct slot *pslot, u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp, enum pci_bus_speed msp) -{ +{ int rc = 0; /* @@ -257,23 +257,23 @@ static int board_added(struct slot *p_slot) err("%s: Failed to power on slot\n", __FUNCTION__); return -1; } - + if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) { if (slots_not_empty) return WRONG_BUS_FREQUENCY; - + if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); return WRONG_BUS_FREQUENCY; } - + /* turn on board, blink green LED, turn off Amber LED */ if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); return rc; } } - + rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp); if (rc) { err("%s: Can't get adapter speed or bus mode mismatch\n", @@ -378,7 +378,7 @@ static int remove_board(struct slot *p_slot) err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); return rc; } - + rc = p_slot->hpc_ops->set_attention_status(p_slot, 0); if (rc) { err("%s: Issue of Set Attention command failed\n", __FUNCTION__); diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index b7bede4b7c27..5183a45d45b5 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -35,38 +35,6 @@ #include "shpchp.h" -#ifdef DEBUG -#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */ -#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */ -#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */ -#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */ -#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT) -#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE) -/* Redefine this flagword to set debug level */ -#define DEBUG_LEVEL DBG_K_STANDARD - -#define DEFINE_DBG_BUFFER char __dbg_str_buf[256]; - -#define DBG_PRINT( dbg_flags, args... ) \ - do { \ - if ( DEBUG_LEVEL & ( dbg_flags ) ) \ - { \ - int len; \ - len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \ - __FILE__, __LINE__, __FUNCTION__ ); \ - sprintf( __dbg_str_buf + len, args ); \ - printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \ - } \ - } while (0) - -#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]"); -#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]"); -#else -#define DEFINE_DBG_BUFFER -#define DBG_ENTER_ROUTINE -#define DBG_LEAVE_ROUTINE -#endif /* DEBUG */ - /* Slot Available Register I field definition */ #define SLOT_33MHZ 0x0000001f #define SLOT_66MHZ_PCIX 0x00001f00 @@ -211,7 +179,6 @@ #define SLOT_EVENT_LATCH 0x2 #define SLOT_SERR_INT_MASK 0x3 -DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ static atomic_t shpchp_num_controllers = ATOMIC_INIT(0); static irqreturn_t shpc_isr(int irq, void *dev_id); @@ -268,8 +235,6 @@ static void int_poll_timeout(unsigned long data) { struct controller *ctrl = (struct controller *)data; - DBG_ENTER_ROUTINE - /* Poll for interrupt events. regs == NULL => polling */ shpc_isr(0, ctrl); @@ -278,8 +243,6 @@ static void int_poll_timeout(unsigned long data) shpchp_poll_time = 2; /* default polling interval is 2 sec */ start_int_poll_timer(ctrl, shpchp_poll_time); - - DBG_LEAVE_ROUTINE } /* @@ -353,8 +316,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) int retval = 0; u16 temp_word; - DBG_ENTER_ROUTINE - mutex_lock(&slot->ctrl->cmd_lock); if (!shpc_poll_ctrl_busy(ctrl)) { @@ -368,9 +329,9 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) ++t_slot; temp_word = (t_slot << 8) | (cmd & 0xFF); dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd); - + /* To make sure the Controller Busy bit is 0 before we send out the - * command. + * command. */ shpc_writew(ctrl, CMD, temp_word); @@ -389,20 +350,14 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) } out: mutex_unlock(&slot->ctrl->cmd_lock); - - DBG_LEAVE_ROUTINE return retval; } static int hpc_check_cmd_status(struct controller *ctrl) { - u16 cmd_status; int retval = 0; + u16 cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F; - DBG_ENTER_ROUTINE - - cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F; - switch (cmd_status >> 1) { case 0: retval = 0; @@ -423,7 +378,6 @@ static int hpc_check_cmd_status(struct controller *ctrl) retval = cmd_status; } - DBG_LEAVE_ROUTINE return retval; } @@ -431,13 +385,8 @@ static int hpc_check_cmd_status(struct controller *ctrl) static int hpc_get_attention_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; - u32 slot_reg; - u8 state; - - DBG_ENTER_ROUTINE - - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT; + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); + u8 state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT; switch (state) { case ATN_LED_STATE_ON: @@ -454,20 +403,14 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) break; } - DBG_LEAVE_ROUTINE return 0; } static int hpc_get_power_status(struct slot * slot, u8 *status) { struct controller *ctrl = slot->ctrl; - u32 slot_reg; - u8 state; - - DBG_ENTER_ROUTINE - - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT; + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); + u8 state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT; switch (state) { case SLOT_STATE_PWRONLY: @@ -484,7 +427,6 @@ static int hpc_get_power_status(struct slot * slot, u8 *status) break; } - DBG_LEAVE_ROUTINE return 0; } @@ -492,30 +434,21 @@ static int hpc_get_power_status(struct slot * slot, u8 *status) static int hpc_get_latch_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; - u32 slot_reg; + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - DBG_ENTER_ROUTINE - - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); *status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */ - DBG_LEAVE_ROUTINE return 0; } static int hpc_get_adapter_status(struct slot *slot, u8 *status) { struct controller *ctrl = slot->ctrl; - u32 slot_reg; - u8 state; + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); + u8 state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT; - DBG_ENTER_ROUTINE - - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT; *status = (state != 0x3) ? 1 : 0; - DBG_LEAVE_ROUTINE return 0; } @@ -523,11 +456,8 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) { struct controller *ctrl = slot->ctrl; - DBG_ENTER_ROUTINE - *prog_int = shpc_readb(ctrl, PROG_INTERFACE); - DBG_LEAVE_ROUTINE return 0; } @@ -539,8 +469,6 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) u8 m66_cap = !!(slot_reg & MHZ66_CAP); u8 pi, pcix_cap; - DBG_ENTER_ROUTINE - if ((retval = hpc_get_prog_int(slot, &pi))) return retval; @@ -582,21 +510,15 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) } dbg("Adapter speed = %d\n", *value); - DBG_LEAVE_ROUTINE return retval; } static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) { - struct controller *ctrl = slot->ctrl; - u16 sec_bus_status; - u8 pi; int retval = 0; - - DBG_ENTER_ROUTINE - - pi = shpc_readb(ctrl, PROG_INTERFACE); - sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG); + struct controller *ctrl = slot->ctrl; + u16 sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG); + u8 pi = shpc_readb(ctrl, PROG_INTERFACE); if (pi == 2) { *mode = (sec_bus_status & 0x0100) >> 8; @@ -605,21 +527,14 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) } dbg("Mode 1 ECC cap = %d\n", *mode); - - DBG_LEAVE_ROUTINE return retval; } static int hpc_query_power_fault(struct slot * slot) { struct controller *ctrl = slot->ctrl; - u32 slot_reg; + u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - DBG_ENTER_ROUTINE - - slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot)); - - DBG_LEAVE_ROUTINE /* Note: Logic 0 => fault */ return !(slot_reg & POWER_FAULT); } @@ -629,7 +544,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) u8 slot_cmd = 0; switch (value) { - case 0 : + case 0 : slot_cmd = SET_ATTN_OFF; /* OFF */ break; case 1: @@ -666,8 +581,6 @@ static void hpc_release_ctlr(struct controller *ctrl) int i; u32 slot_reg, serr_int; - DBG_ENTER_ROUTINE - /* * Mask event interrupts and SERRs of all slots */ @@ -708,61 +621,43 @@ static void hpc_release_ctlr(struct controller *ctrl) */ if (atomic_dec_and_test(&shpchp_num_controllers)) destroy_workqueue(shpchp_wq); - - DBG_LEAVE_ROUTINE } static int hpc_power_on_slot(struct slot * slot) { int retval; - DBG_ENTER_ROUTINE - retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR); - if (retval) { + if (retval) err("%s: Write command failed!\n", __FUNCTION__); - return retval; - } - DBG_LEAVE_ROUTINE - - return 0; + return retval; } static int hpc_slot_enable(struct slot * slot) { int retval; - DBG_ENTER_ROUTINE - /* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */ retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF); - if (retval) { + if (retval) err("%s: Write command failed!\n", __FUNCTION__); - return retval; - } - DBG_LEAVE_ROUTINE - return 0; + return retval; } static int hpc_slot_disable(struct slot * slot) { int retval; - DBG_ENTER_ROUTINE - /* Slot - Disable, Power Indicator - Off, Attention Indicator - On */ retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON); - if (retval) { + if (retval) err("%s: Write command failed!\n", __FUNCTION__); - return retval; - } - DBG_LEAVE_ROUTINE - return 0; + return retval; } static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) @@ -771,8 +666,6 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) struct controller *ctrl = slot->ctrl; u8 pi, cmd; - DBG_ENTER_ROUTINE - pi = shpc_readb(ctrl, PROG_INTERFACE); if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX)) return -EINVAL; @@ -828,7 +721,6 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) if (retval) err("%s: Write command failed!\n", __FUNCTION__); - DBG_LEAVE_ROUTINE return retval; } @@ -843,7 +735,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id) if (!intr_loc) return IRQ_NONE; - dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); + dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); if(!shpchp_poll_mode) { /* @@ -856,12 +748,12 @@ static irqreturn_t shpc_isr(int irq, void *dev_id) shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); intr_loc2 = shpc_readl(ctrl, INTR_LOC); - dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); + dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); } if (intr_loc & CMD_INTR_PENDING) { - /* - * Command Complete Interrupt Pending + /* + * Command Complete Interrupt Pending * RO only - clear by writing 1 to the Command Completion * Detect bit in Controller SERR-INT register */ @@ -875,7 +767,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id) if (!(intr_loc & ~CMD_INTR_PENDING)) goto out; - for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { + for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { /* To find out which slot has interrupt pending */ if (!(intr_loc & SLOT_INTR_PENDING(hp_slot))) continue; @@ -907,7 +799,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id) serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK); shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int); } - + return IRQ_HANDLED; } @@ -920,8 +812,6 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1); u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2); - DBG_ENTER_ROUTINE - if (pi == 2) { if (slot_avail2 & SLOT_133MHZ_PCIX_533) bus_speed = PCI_SPEED_133MHz_PCIX_533; @@ -954,7 +844,7 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) *value = bus_speed; dbg("Max bus speed = %d\n", bus_speed); - DBG_LEAVE_ROUTINE + return retval; } @@ -967,8 +857,6 @@ static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) u8 pi = shpc_readb(ctrl, PROG_INTERFACE); u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7); - DBG_ENTER_ROUTINE - if ((pi == 1) && (speed_mode > 4)) { *value = PCI_SPEED_UNKNOWN; return -ENODEV; @@ -1024,7 +912,6 @@ static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) } dbg("Current bus speed = %d\n", bus_speed); - DBG_LEAVE_ROUTINE return retval; } @@ -1032,7 +919,7 @@ static struct hpc_ops shpchp_hpc_ops = { .power_on_slot = hpc_power_on_slot, .slot_enable = hpc_slot_enable, .slot_disable = hpc_slot_disable, - .set_bus_speed_mode = hpc_set_bus_speed_mode, + .set_bus_speed_mode = hpc_set_bus_speed_mode, .set_attention_status = hpc_set_attention_status, .get_power_status = hpc_get_power_status, .get_attention_status = hpc_get_attention_status, @@ -1049,7 +936,7 @@ static struct hpc_ops shpchp_hpc_ops = { .green_led_on = hpc_set_green_led_on, .green_led_off = hpc_set_green_led_off, .green_led_blink = hpc_set_green_led_blink, - + .release_ctlr = hpc_release_ctlr, }; @@ -1061,8 +948,6 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) u32 tempdword, slot_reg, slot_config; u8 i; - DBG_ENTER_ROUTINE - ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device == @@ -1108,9 +993,9 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) ctrl->mmio_size = 0x24 + 0x4 * num_slots; } - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, + info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device); - + rc = pci_enable_device(pdev); if (rc) { err("%s: pci_enable_device failed\n", __FUNCTION__); @@ -1172,7 +1057,7 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) slot_reg &= ~SLOT_REG_RSVDZ_MASK; shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg); } - + if (shpchp_poll_mode) { /* Install interrupt polling timer. Start with 10 sec delay */ init_timer(&ctrl->poll_timer); @@ -1184,7 +1069,7 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) info("Can't get msi for the hotplug controller\n"); info("Use INTx for the hotplug controller\n"); } - + rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED, MY_NAME, (void *)ctrl); dbg("%s: request_irq %d for hpc%d (returns %d)\n", @@ -1235,13 +1120,11 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); } - DBG_LEAVE_ROUTINE return 0; /* We end up here for the many possible ways to fail this API. */ abort_iounmap: iounmap(ctrl->creg); abort: - DBG_LEAVE_ROUTINE return rc; } diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index ed3f7e1a563c..68555c11f556 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -24,8 +24,6 @@ #include "pci.h" #include "msi.h" -static DEFINE_SPINLOCK(msi_lock); -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; @@ -44,13 +42,13 @@ 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: 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); @@ -74,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: { @@ -113,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: { @@ -162,6 +160,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; @@ -169,13 +168,6 @@ static int msi_init(void) if (!status) return status; - if (pci_msi_quirk) { - pci_msi_enable = 0; - printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n"); - status = -EINVAL; - return status; - } - status = msi_cache_init(); if (status < 0) { pci_msi_enable = 0; @@ -200,46 +192,6 @@ static struct msi_desc* alloc_msi_entry(void) return entry; } -static void attach_msi_entry(struct msi_desc *entry, int irq) -{ - unsigned long flags; - - spin_lock_irqsave(&msi_lock, flags); - msi_desc[irq] = entry; - spin_unlock_irqrestore(&msi_lock, flags); -} - -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_data(irq, entry); - - return irq; -} - -static void destroy_msi_irq(unsigned int irq) -{ - struct msi_desc *entry; - - entry = get_irq_data(irq); - set_irq_chip(irq, NULL); - set_irq_data(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; @@ -278,36 +230,8 @@ 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 exits. Override dev->irq with this irq */ - dev->irq = irq; - return 0; - } - spin_unlock_irqrestore(&msi_lock, flags); - - 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) +static int __pci_save_msi_state(struct pci_dev *dev) { int pos, i = 0; u16 control; @@ -345,7 +269,7 @@ int pci_save_msi_state(struct pci_dev *dev) return 0; } -void pci_restore_msi_state(struct pci_dev *dev) +static void __pci_restore_msi_state(struct pci_dev *dev) { int i = 0, pos; u16 control; @@ -373,14 +297,16 @@ void pci_restore_msi_state(struct pci_dev *dev) kfree(save_state); } -int pci_save_msix_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; @@ -398,38 +324,46 @@ 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; - 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; } - dev->irq = temp; save_state->cap_nr = PCI_CAP_ID_MSIX; pci_add_saved_cap(dev, save_state); return 0; } -void pci_restore_msix_state(struct pci_dev *dev) +int pci_save_msi_state(struct pci_dev *dev) +{ + int rc; + + rc = __pci_save_msi_state(dev); + if (rc) + return rc; + + rc = __pci_save_msix_state(dev); + + return rc; +} + +static void __pci_restore_msix_state(struct pci_dev *dev) { u16 save; 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; @@ -442,23 +376,25 @@ 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]; + entry = get_irq_msi(irq); write_msi_msg(irq, &entry->msg_save); - tail = msi_desc[irq]->link.tail; + tail = entry->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); } -#endif + +void pci_restore_msi_state(struct pci_dev *dev) +{ + __pci_restore_msi_state(dev); + __pci_restore_msix_state(dev); +} +#endif /* CONFIG_PM */ /** * msi_capability_init - configure device's MSI capability structure @@ -471,7 +407,6 @@ void pci_restore_msix_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; @@ -479,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_data(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; @@ -511,13 +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); - attach_msi_entry(entry, irq); /* Set MSI enabled bits */ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); @@ -539,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; @@ -562,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_data(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; @@ -577,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; @@ -589,14 +529,8 @@ 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; - } - attach_msi_entry(entry, irq); + set_irq_msi(irq, entry); } if (i != nvec) { int avail = i - 1; @@ -613,6 +547,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); @@ -660,13 +595,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; @@ -675,15 +608,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); @@ -695,13 +627,15 @@ void pci_disable_msi(struct pci_dev* dev) struct msi_desc *entry; int pos, default_irq; u16 control; - unsigned long flags; if (!pci_msi_enable) return; if (!dev) return; + if (!dev->msi_enabled) + return; + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); if (!pos) return; @@ -710,28 +644,26 @@ 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 = get_irq_msi(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)) { - spin_unlock_irqrestore(&msi_lock, flags); + if (irq_has_action(dev->first_msi_irq)) { 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) @@ -739,27 +671,20 @@ static int msi_free_irq(struct pci_dev* dev, int irq) struct msi_desc *entry; int head, entry_nr, type; void __iomem *base; - unsigned long flags; - arch_teardown_msi_irq(irq); - - spin_lock_irqsave(&msi_lock, flags); - entry = msi_desc[irq]; + entry = get_irq_msi(irq); if (!entry || entry->dev != dev) { - spin_unlock_irqrestore(&msi_lock, flags); return -EINVAL; } type = entry->msi_attrib.type; 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; - entry->dev = NULL; - msi_desc[irq] = NULL; - spin_unlock_irqrestore(&msi_lock, flags); + get_irq_msi(entry->link.head)->link.tail = entry->link.tail; + get_irq_msi(entry->link.tail)->link.head = entry->link.head; - 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 + @@ -790,7 +715,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) @@ -818,16 +743,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); @@ -836,7 +759,8 @@ 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; + int pos; u16 control; if (!pci_msi_enable) @@ -844,6 +768,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; @@ -854,31 +781,23 @@ 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) { + tail = get_irq_msi(irq)->link.tail; + 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; } /** @@ -892,35 +811,26 @@ void pci_disable_msix(struct pci_dev* dev) **/ void msi_remove_pci_irq_vectors(struct pci_dev* dev) { - int pos, temp; - 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 (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 (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; - base = msi_desc[irq]->mask_base; - spin_unlock_irqrestore(&msi_lock, flags); + 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 */ @@ -935,7 +845,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/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 92d5e8db0de7..4438ae1ede4f 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -324,8 +324,7 @@ static int pci_default_resume(struct pci_dev *pci_dev) /* restore the PCI config space */ pci_restore_state(pci_dev); /* if the device was enabled before suspend, reenable */ - if (atomic_read(&pci_dev->enable_cnt)) - retval = __pci_enable_device(pci_dev); + retval = __pci_reenable_device(pci_dev); /* if the device was busmaster before the suspend, make it busmaster again */ if (pci_dev->is_busmaster) pci_set_master(pci_dev); @@ -422,7 +421,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 +430,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/drivers/pci/pci.c b/drivers/pci/pci.c index 206c834d263a..84c757ba0664 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -392,6 +392,14 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) if (state > PCI_D3hot) state = PCI_D3hot; + /* + * If the device or the parent bridge can't support PCI PM, ignore + * the request if we're doing anything besides putting it into D0 + * (which would only happen on boot). + */ + if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev)) + return 0; + /* Validate current state: * Can enter D0 from any state, but if we can only go deeper * to sleep if we're already in a low power state @@ -403,13 +411,6 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) } else if (dev->current_state == state) return 0; /* we're already there */ - /* - * If the device or the parent bridge can't support PCI PM, ignore - * the request if we're doing anything besides putting it into D0 - * (which would only happen on boot). - */ - if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev)) - return 0; /* find PCI PM capability in list */ pm = pci_find_capability(dev, PCI_CAP_ID_PM); @@ -633,8 +634,6 @@ pci_save_state(struct pci_dev *dev) pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]); if ((i = pci_save_msi_state(dev)) != 0) return i; - if ((i = pci_save_msix_state(dev)) != 0) - return i; if ((i = pci_save_pcie_state(dev)) != 0) return i; if ((i = pci_save_pcix_state(dev)) != 0) @@ -672,22 +671,11 @@ pci_restore_state(struct pci_dev *dev) } pci_restore_pcix_state(dev); pci_restore_msi_state(dev); - pci_restore_msix_state(dev); + return 0; } -/** - * pci_enable_device_bars - Initialize some of a device for use - * @dev: PCI device to be initialized - * @bars: bitmask of BAR's that must be configured - * - * Initialize device before it's used by a driver. Ask low-level code - * to enable selected I/O and memory resources. Wake up the device if it - * was suspended. Beware, this function can fail. - */ - -int -pci_enable_device_bars(struct pci_dev *dev, int bars) +static int do_pci_enable_device(struct pci_dev *dev, int bars) { int err; @@ -697,30 +685,47 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) err = pcibios_enable_device(dev, bars); if (err < 0) return err; + pci_fixup_device(pci_fixup_enable, dev); + return 0; } /** - * __pci_enable_device - Initialize device before it's used by a driver. - * @dev: PCI device to be initialized + * __pci_reenable_device - Resume abandoned device + * @dev: PCI device to be resumed * - * Initialize device before it's used by a driver. Ask low-level code - * to enable I/O and memory. Wake up the device if it was suspended. - * Beware, this function can fail. - * - * Note this function is a backend and is not supposed to be called by - * normal code, use pci_enable_device() instead. + * Note this function is a backend of pci_default_resume and is not supposed + * to be called by normal code, write proper resume handler and use it instead. */ int -__pci_enable_device(struct pci_dev *dev) +__pci_reenable_device(struct pci_dev *dev) +{ + if (atomic_read(&dev->enable_cnt)) + return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1); + return 0; +} + +/** + * pci_enable_device_bars - Initialize some of a device for use + * @dev: PCI device to be initialized + * @bars: bitmask of BAR's that must be configured + * + * Initialize device before it's used by a driver. Ask low-level code + * to enable selected I/O and memory resources. Wake up the device if it + * was suspended. Beware, this function can fail. + */ +int +pci_enable_device_bars(struct pci_dev *dev, int bars) { int err; - err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); - if (err) - return err; - pci_fixup_device(pci_fixup_enable, dev); - return 0; + if (atomic_add_return(1, &dev->enable_cnt) > 1) + return 0; /* already enabled */ + + err = do_pci_enable_device(dev, bars); + if (err < 0) + atomic_dec(&dev->enable_cnt); + return err; } /** @@ -736,13 +741,7 @@ __pci_enable_device(struct pci_dev *dev) */ int pci_enable_device(struct pci_dev *dev) { - int result; - if (atomic_add_return(1, &dev->enable_cnt) > 1) - return 0; /* already enabled */ - result = __pci_enable_device(dev); - if (result < 0) - atomic_dec(&dev->enable_cnt); - return result; + return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); } /** @@ -921,6 +920,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 +973,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 +991,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 +1174,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; @@ -1181,12 +1223,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); @@ -1197,6 +1233,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,13 +1243,10 @@ 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); EXPORT_SYMBOL(pci_restore_state); EXPORT_SYMBOL(pci_enable_wake); -/* Quirk info */ - -EXPORT_SYMBOL(isa_dma_bridge_buggy); -EXPORT_SYMBOL(pci_pci_problems); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 398852f526a6..a4f2d580625e 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1,6 +1,6 @@ /* Functions internal to the PCI core code */ -extern int __must_check __pci_enable_device(struct pci_dev *); +extern int __must_check __pci_reenable_device(struct pci_dev *); extern int pci_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); @@ -43,12 +43,8 @@ extern void pci_remove_legacy_files(struct pci_bus *bus); /* Lock for read/write access to pci device and bus lists */ extern struct rw_semaphore pci_bus_sem; -#ifdef CONFIG_PCI_MSI -extern int pci_msi_quirk; -#else -#define pci_msi_quirk 0 -#endif extern unsigned int pci_pm_d3_delay; + #ifdef CONFIG_PCI_MSI void disable_msi_mode(struct pci_dev *dev, int pos, int type); void pci_no_msi(void); @@ -56,17 +52,15 @@ void pci_no_msi(void); static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { } static inline void pci_no_msi(void) { } #endif + #if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) int pci_save_msi_state(struct pci_dev *dev); -int pci_save_msix_state(struct pci_dev *dev); void pci_restore_msi_state(struct pci_dev *dev); -void pci_restore_msix_state(struct pci_dev *dev); #else static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; } -static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; } static inline void pci_restore_msi_state(struct pci_dev *dev) {} -static inline void pci_restore_msix_state(struct pci_dev *dev) {} #endif + static inline int pci_no_d1d2(struct pci_dev *dev) { unsigned int parent_dstates = 0; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 0e0401dd02cb..2fe1d690eb13 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -144,6 +144,32 @@ static u32 pci_size(u32 base, u32 maxbase, u32 mask) return size; } +static u64 pci_size64(u64 base, u64 maxbase, u64 mask) +{ + u64 size = mask & maxbase; /* Find the significant bits */ + if (!size) + return 0; + + /* Get the lowest of them to find the decode size, and + from that the extent. */ + size = (size & ~(size-1)) - 1; + + /* base == maxbase can be valid only if the BAR has + already been programmed with all 1s. */ + if (base == maxbase && ((base | size) & mask) != mask) + return 0; + + return size; +} + +static inline int is_64bit_memory(u32 mask) +{ + if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == + (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) + return 1; + return 0; +} + static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) { unsigned int pos, reg, next; @@ -151,6 +177,10 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) struct resource *res; for(pos=0; posresource[pos]; res->name = pci_name(dev); @@ -163,9 +193,16 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) continue; if (l == 0xffffffff) l = 0; - if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { + raw_sz = sz; + if ((l & PCI_BASE_ADDRESS_SPACE) == + PCI_BASE_ADDRESS_SPACE_MEMORY) { sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK); - if (!sz) + /* + * For 64bit prefetchable memory sz could be 0, if the + * real size is bigger than 4G, so we need to check + * szhi for that. + */ + if (!is_64bit_memory(l) && !sz) continue; res->start = l & PCI_BASE_ADDRESS_MEM_MASK; res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK; @@ -178,30 +215,36 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) } res->end = res->start + (unsigned long) sz; res->flags |= pci_calc_resource_flags(l); - if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) - == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { + if (is_64bit_memory(l)) { u32 szhi, lhi; + pci_read_config_dword(dev, reg+4, &lhi); pci_write_config_dword(dev, reg+4, ~0); pci_read_config_dword(dev, reg+4, &szhi); pci_write_config_dword(dev, reg+4, lhi); - szhi = pci_size(lhi, szhi, 0xffffffff); + sz64 = ((u64)szhi << 32) | raw_sz; + l64 = ((u64)lhi << 32) | l; + sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK); next++; #if BITS_PER_LONG == 64 - res->start |= ((unsigned long) lhi) << 32; - res->end = res->start + sz; - if (szhi) { - /* This BAR needs > 4GB? Wow. */ - res->end |= (unsigned long)szhi<<32; + if (!sz64) { + res->start = 0; + res->end = 0; + res->flags = 0; + continue; } + res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK; + res->end = res->start + sz64; #else - if (szhi) { - printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev)); + if (sz64 > 0x100000000ULL) { + printk(KERN_ERR "PCI: Unable to handle 64-bit " + "BAR for device %s\n", pci_name(dev)); res->start = 0; res->flags = 0; } else if (lhi) { /* 64-bit wide address, treat as disabled */ - pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); + pci_write_config_dword(dev, reg, + l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); pci_write_config_dword(dev, reg+4, 0); res->start = 0; res->end = sz; @@ -902,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/drivers/pci/quirks.c b/drivers/pci/quirks.c index c913ea4e545c..11217bda4b9e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -61,7 +61,8 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_p This appears to be BIOS not version dependent. So presumably there is a chipset level fix */ -int isa_dma_bridge_buggy; /* Exported */ +int isa_dma_bridge_buggy; +EXPORT_SYMBOL(isa_dma_bridge_buggy); static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev) { @@ -83,6 +84,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_d DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs ); int pci_pci_problems; +EXPORT_SYMBOL(pci_pci_problems); /* * Chipsets where PCI->PCI transfers vanish or hang @@ -94,6 +96,8 @@ static void __devinit quirk_nopcipci(struct pci_dev *dev) pci_pci_problems |= PCIPCI_FAIL; } } +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci ); static void __devinit quirk_nopciamd(struct pci_dev *dev) { @@ -105,9 +109,6 @@ static void __devinit quirk_nopciamd(struct pci_dev *dev) pci_pci_problems |= PCIAGP_FAIL; } } - -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci ); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd ); /* @@ -976,52 +977,51 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x1626: /* L3C notebook */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) switch(dev->subsystem_device) { case 0x80b1: /* P4GE-V */ case 0x80b2: /* P4PE */ case 0x8093: /* P4B533-V */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB) switch(dev->subsystem_device) { case 0x8030: /* P4T533 */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_7205_0) + else if (dev->device == PCI_DEVICE_ID_INTEL_7205_0) switch (dev->subsystem_device) { case 0x8070: /* P4G8X Deluxe */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH) + else if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH) switch (dev->subsystem_device) { case 0x80c9: /* PU-DLS */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB) switch (dev->subsystem_device) { case 0x1751: /* M2N notebook */ case 0x1821: /* M5N notebook */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) switch (dev->subsystem_device) { case 0x184b: /* W1N notebook */ case 0x186a: /* M6Ne notebook */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) switch (dev->subsystem_device) { case 0x80f2: /* P4P800-X */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) { + else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) switch (dev->subsystem_device) { case 0x1882: /* M6V notebook */ case 0x1977: /* A6VA notebook */ asus_hides_smbus = 1; } - } } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) { if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) switch(dev->subsystem_device) { @@ -1029,25 +1029,24 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) case 0x0890: /* HP Compaq nc6000 */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB) switch (dev->subsystem_device) { case 0x12bc: /* HP D330L */ case 0x12bd: /* HP D530 */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) { + else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) switch (dev->subsystem_device) { case 0x099c: /* HP Compaq nx6110 */ asus_hides_smbus = 1; } - } } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) { if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB) switch(dev->subsystem_device) { case 0x0001: /* Toshiba Satellite A40 */ asus_hides_smbus = 1; } - if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) + else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB) switch(dev->subsystem_device) { case 0x0001: /* Toshiba Tecra M2 */ asus_hides_smbus = 1; @@ -1136,6 +1135,14 @@ static void quirk_sis_96x_smbus(struct pci_dev *dev) pci_write_config_byte(dev, 0x77, val & ~0x10); } } +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); /* * ... This is further complicated by the fact that some SiS96x south @@ -1145,8 +1152,6 @@ static void quirk_sis_96x_smbus(struct pci_dev *dev) * * We can also enable the sis96x bit in the discovery register.. */ -static int __devinitdata sis_96x_compatible = 0; - #define SIS_DETECT_REGISTER 0x40 static void quirk_sis_503(struct pci_dev *dev) @@ -1162,9 +1167,6 @@ static void quirk_sis_503(struct pci_dev *dev) return; } - /* Make people aware that we changed the config.. */ - printk(KERN_WARNING "Uncovering SIS%x that hid as a SIS503 (compatible=%d)\n", devid, sis_96x_compatible); - /* * Ok, it now shows up as a 96x.. run the 96x quirk by * hand in case it has already been processed. @@ -1173,20 +1175,10 @@ static void quirk_sis_503(struct pci_dev *dev) dev->device = devid; quirk_sis_96x_smbus(dev); } - -static void __init quirk_sis_96x_compatible(struct pci_dev *dev) -{ - sis_96x_compatible = 1; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_645, quirk_sis_96x_compatible ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, quirk_sis_96x_compatible ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_648, quirk_sis_96x_compatible ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, quirk_sis_96x_compatible ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_compatible ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, quirk_sis_96x_compatible ); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 ); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 ); + + /* * On ASUS A8V and A8V Deluxe boards, the onboard AC97 audio controller * and MC97 modem controller are disabled when a second PCI soundcard is @@ -1217,21 +1209,8 @@ static void asus_hides_ac97_lpc(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc ); - - -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); - DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc ); - -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus ); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus ); - #if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE) /* @@ -1276,7 +1255,6 @@ static void quirk_jmicron_dualfn(struct pci_dev *pdev) break; } } - DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn); @@ -1420,6 +1398,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_co int pcie_mch_quirk; +EXPORT_SYMBOL(pcie_mch_quirk); static void __devinit quirk_pcie_mch(struct pci_dev *pdev) { @@ -1481,6 +1460,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; @@ -1646,6 +1643,7 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) } pci_do_fixups(dev, start, end); } +EXPORT_SYMBOL(pci_fixup_device); /* Enable 1k I/O space granularity on the Intel P64H2 */ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) @@ -1673,6 +1671,31 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); +/* Fix the IOBL_ADR for 1k I/O space granularity on the Intel P64H2 + * The IOBL_ADR gets re-written to 4k boundaries in pci_setup_bridge() + * in drivers/pci/setup-bus.c + */ +static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev) +{ + u16 en1k, iobl_adr, iobl_adr_1k; + struct resource *res = dev->resource + PCI_BRIDGE_RESOURCES; + + pci_read_config_word(dev, 0x40, &en1k); + + if (en1k & 0x200) { + pci_read_config_word(dev, PCI_IO_BASE, &iobl_adr); + + iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00); + + if (iobl_adr != iobl_adr_1k) { + printk(KERN_INFO "PCI: Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1 KB Granularity\n", + iobl_adr,iobl_adr_1k); + pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k); + } + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io_fix_iobl); + /* Under some circumstances, AER is not linked with extended capabilities. * Force it to be linked by setting the corresponding control bit in the * config space. @@ -1695,9 +1718,6 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, quirk_nvidia_ck804_pcie_aer_ext_cap); #ifdef CONFIG_PCI_MSI -/* To disable MSI globally */ -int pci_msi_quirk; - /* The Serverworks PCI-X chipset does not support MSI. We cannot easily rely * on setting PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually * some other busses controlled by the chipset even if Linux is not aware of it. @@ -1706,8 +1726,8 @@ int pci_msi_quirk; */ static void __init quirk_svw_msi(struct pci_dev *dev) { - pci_msi_quirk = 1; - printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n"); + pci_no_msi(); + printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n"); } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi); @@ -1788,8 +1808,3 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, quirk_nvidia_ck804_msi_ht_cap); #endif /* CONFIG_PCI_MSI */ - -EXPORT_SYMBOL(pcie_mch_quirk); -#ifdef CONFIG_HOTPLUG -EXPORT_SYMBOL(pci_fixup_device); -#endif 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/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 606a46740338..ac004248324a 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -110,7 +110,7 @@ int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state) down_read(&pcmcia_socket_list_rwsem); list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { - if (socket->dev.dev != dev) + if (socket->dev.parent != dev) continue; mutex_lock(&socket->skt_mutex); socket_suspend(socket); @@ -128,7 +128,7 @@ int pcmcia_socket_dev_resume(struct device *dev) down_read(&pcmcia_socket_list_rwsem); list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { - if (socket->dev.dev != dev) + if (socket->dev.parent != dev) continue; mutex_lock(&socket->skt_mutex); socket_resume(socket); @@ -143,12 +143,12 @@ EXPORT_SYMBOL(pcmcia_socket_dev_resume); struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt) { - struct class_device *cl_dev = class_device_get(&skt->dev); - if (!cl_dev) + struct device *dev = get_device(&skt->dev); + if (!dev) return NULL; - skt = class_get_devdata(cl_dev); + skt = dev_get_drvdata(dev); if (!try_module_get(skt->owner)) { - class_device_put(&skt->dev); + put_device(&skt->dev); return NULL; } return (skt); @@ -159,14 +159,14 @@ EXPORT_SYMBOL(pcmcia_get_socket); void pcmcia_put_socket(struct pcmcia_socket *skt) { module_put(skt->owner); - class_device_put(&skt->dev); + put_device(&skt->dev); } EXPORT_SYMBOL(pcmcia_put_socket); -static void pcmcia_release_socket(struct class_device *class_dev) +static void pcmcia_release_socket(struct device *dev) { - struct pcmcia_socket *socket = class_get_devdata(class_dev); + struct pcmcia_socket *socket = dev_get_drvdata(dev); complete(&socket->socket_released); } @@ -181,7 +181,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) struct task_struct *tsk; int ret; - if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops) + if (!socket || !socket->ops || !socket->dev.parent || !socket->resource_ops) return -EINVAL; cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops); @@ -226,9 +226,9 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) #endif /* set proper values in socket->dev */ - socket->dev.class_data = socket; + dev_set_drvdata(&socket->dev, socket); socket->dev.class = &pcmcia_socket_class; - snprintf(socket->dev.class_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock); + snprintf(socket->dev.bus_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock); /* base address = 0, map = 0 */ socket->cis_mem.flags = 0; @@ -640,7 +640,7 @@ static int pccardd(void *__skt) skt->ops->set_socket(skt, &skt->socket); /* register with the device core */ - ret = class_device_register(&skt->dev); + ret = device_register(&skt->dev); if (ret) { printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n", skt); @@ -689,7 +689,7 @@ static int pccardd(void *__skt) remove_wait_queue(&skt->thread_wait, &wait); /* remove from the device core */ - class_device_unregister(&skt->dev); + device_unregister(&skt->dev); return 0; } @@ -904,7 +904,7 @@ int pcmcia_insert_card(struct pcmcia_socket *skt) EXPORT_SYMBOL(pcmcia_insert_card); -static int pcmcia_socket_uevent(struct class_device *dev, char **envp, +static int pcmcia_socket_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); @@ -930,8 +930,8 @@ static void pcmcia_release_socket_class(struct class *data) struct class pcmcia_socket_class = { .name = "pcmcia_socket", - .uevent = pcmcia_socket_uevent, - .release = pcmcia_release_socket, + .dev_uevent = pcmcia_socket_uevent, + .dev_release = pcmcia_release_socket, .class_release = pcmcia_release_socket_class, }; EXPORT_SYMBOL(pcmcia_socket_class); diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index f573ea04db6f..9fa207e3c7b3 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -142,7 +142,7 @@ struct pcmcia_callback{ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); -#define cs_socket_name(skt) ((skt)->dev.class_id) +#define cs_socket_name(skt) ((skt)->dev.bus_id) #ifdef DEBUG extern int cs_debug_level(int); @@ -158,6 +158,6 @@ extern int cs_debug_level(int); #endif #define cs_err(skt, fmt, arg...) \ - printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.class_id , ## arg) + printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.bus_id , ## arg) #endif /* _LINUX_CS_INTERNAL_H */ diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 7355eb455a88..18e111e12339 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -572,7 +572,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f p_dev->func = function; p_dev->dev.bus = &pcmcia_bus_type; - p_dev->dev.parent = s->dev.dev; + p_dev->dev.parent = s->dev.parent; p_dev->dev.release = pcmcia_release_dev; bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); @@ -1328,10 +1328,10 @@ static struct pcmcia_callback pcmcia_bus_callback = { .resume = pcmcia_bus_resume, }; -static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, +static int __devinit pcmcia_bus_add_socket(struct device *dev, struct class_interface *class_intf) { - struct pcmcia_socket *socket = class_get_devdata(class_dev); + struct pcmcia_socket *socket = dev_get_drvdata(dev); int ret; socket = pcmcia_get_socket(socket); @@ -1364,10 +1364,10 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, return 0; } -static void pcmcia_bus_remove_socket(struct class_device *class_dev, +static void pcmcia_bus_remove_socket(struct device *dev, struct class_interface *class_intf) { - struct pcmcia_socket *socket = class_get_devdata(class_dev); + struct pcmcia_socket *socket = dev_get_drvdata(dev); if (!socket) return; @@ -1389,8 +1389,8 @@ static void pcmcia_bus_remove_socket(struct class_device *class_dev, /* the pcmcia_bus_interface is used to handle pcmcia socket devices */ static struct class_interface pcmcia_bus_interface = { .class = &pcmcia_socket_class, - .add = &pcmcia_bus_add_socket, - .remove = &pcmcia_bus_remove_socket, + .add_dev = &pcmcia_bus_add_socket, + .remove_dev = &pcmcia_bus_remove_socket, }; diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index c2ea07aa7a12..df21e2d16f87 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -161,7 +161,7 @@ static int __devinit i82092aa_pci_probe(struct pci_dev *dev, const struct pci_de pci_set_drvdata(dev, &sockets[i].socket); for (i = 0; idev; + sockets[i].socket.dev.parent = &dev->dev; sockets[i].socket.ops = &i82092aa_operations; sockets[i].socket.resource_ops = &pccard_nonstatic_ops; ret = pcmcia_register_socket(&sockets[i].socket); diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index ea74f98a7350..72ff2f615b33 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -1298,7 +1298,7 @@ static int __init init_i82365(void) /* register sockets with the pcmcia core */ for (i = 0; i < sockets; i++) { - socket[i].socket.dev.dev = &i82365_device->dev; + socket[i].socket.dev.parent = &i82365_device->dev; socket[i].socket.ops = &pcic_operations; socket[i].socket.resource_ops = &pccard_nonstatic_ops; socket[i].socket.owner = THIS_MODULE; diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 327372b7a54e..88494149e910 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -59,7 +59,6 @@ typedef struct user_info_t { #ifdef DEBUG extern int ds_pc_debug; -#define cs_socket_name(skt) ((skt)->dev.class_id) #define ds_dbg(lvl, fmt, arg...) do { \ if (ds_pc_debug >= lvl) \ diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index b9201c2ec38b..0ce39de834c4 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -48,7 +48,6 @@ static u8 pcmcia_used_irq[NR_IRQS]; #ifdef DEBUG extern int ds_pc_debug; -#define cs_socket_name(skt) ((skt)->dev.class_id) #define ds_dbg(skt, lvl, fmt, arg...) do { \ if (ds_pc_debug >= lvl) \ diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index 360c24896548..dd0ddf19ee57 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -682,7 +682,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, socket[i].socket.ops = &pd6729_operations; socket[i].socket.resource_ops = &pccard_nonstatic_ops; - socket[i].socket.dev.dev = &dev->dev; + socket[i].socket.dev.parent = &dev->dev; socket[i].socket.driver_data = &socket[i]; } diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index c3176b16b7be..bfcaad6021cf 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -616,7 +616,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star static struct resource *nonstatic_find_io_region(unsigned long base, int num, unsigned long align, struct pcmcia_socket *s) { - struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id); + struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.bus_id); struct socket_data *s_data = s->resource_data; struct pcmcia_align_data data; unsigned long min = base; @@ -650,7 +650,7 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num, static struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long align, int low, struct pcmcia_socket *s) { - struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id); + struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.bus_id); struct socket_data *s_data = s->resource_data; struct pcmcia_align_data data; unsigned long min, max; @@ -897,9 +897,10 @@ EXPORT_SYMBOL(pccard_nonstatic_ops); /* sysfs interface to the resource database */ -static ssize_t show_io_db(struct class_device *class_dev, char *buf) +static ssize_t show_io_db(struct device *dev, + struct device_attribute *attr, char *buf) { - struct pcmcia_socket *s = class_get_devdata(class_dev); + struct pcmcia_socket *s = dev_get_drvdata(dev); struct socket_data *data; struct resource_map *p; ssize_t ret = 0; @@ -920,9 +921,11 @@ static ssize_t show_io_db(struct class_device *class_dev, char *buf) return (ret); } -static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size_t count) +static ssize_t store_io_db(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct pcmcia_socket *s = class_get_devdata(class_dev); + struct pcmcia_socket *s = dev_get_drvdata(dev); unsigned long start_addr, end_addr; unsigned int add = ADD_MANAGED_RESOURCE; ssize_t ret = 0; @@ -947,11 +950,12 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size return ret ? ret : count; } -static CLASS_DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db); +static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db); -static ssize_t show_mem_db(struct class_device *class_dev, char *buf) +static ssize_t show_mem_db(struct device *dev, + struct device_attribute *attr, char *buf) { - struct pcmcia_socket *s = class_get_devdata(class_dev); + struct pcmcia_socket *s = dev_get_drvdata(dev); struct socket_data *data; struct resource_map *p; ssize_t ret = 0; @@ -972,9 +976,11 @@ static ssize_t show_mem_db(struct class_device *class_dev, char *buf) return (ret); } -static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, size_t count) +static ssize_t store_mem_db(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct pcmcia_socket *s = class_get_devdata(class_dev); + struct pcmcia_socket *s = dev_get_drvdata(dev); unsigned long start_addr, end_addr; unsigned int add = ADD_MANAGED_RESOURCE; ssize_t ret = 0; @@ -999,25 +1005,25 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz return ret ? ret : count; } -static CLASS_DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db); +static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db); -static struct class_device_attribute *pccard_rsrc_attributes[] = { - &class_device_attr_available_resources_io, - &class_device_attr_available_resources_mem, +static struct device_attribute *pccard_rsrc_attributes[] = { + &dev_attr_available_resources_io, + &dev_attr_available_resources_mem, NULL, }; -static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev, +static int __devinit pccard_sysfs_add_rsrc(struct device *dev, struct class_interface *class_intf) { - struct pcmcia_socket *s = class_get_devdata(class_dev); - struct class_device_attribute **attr; + struct pcmcia_socket *s = dev_get_drvdata(dev); + struct device_attribute **attr; int ret = 0; if (s->resource_ops != &pccard_nonstatic_ops) return 0; for (attr = pccard_rsrc_attributes; *attr; attr++) { - ret = class_device_create_file(class_dev, *attr); + ret = device_create_file(dev, *attr); if (ret) break; } @@ -1025,23 +1031,23 @@ static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev, return ret; } -static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev, +static void __devexit pccard_sysfs_remove_rsrc(struct device *dev, struct class_interface *class_intf) { - struct pcmcia_socket *s = class_get_devdata(class_dev); - struct class_device_attribute **attr; + struct pcmcia_socket *s = dev_get_drvdata(dev); + struct device_attribute **attr; if (s->resource_ops != &pccard_nonstatic_ops) return; for (attr = pccard_rsrc_attributes; *attr; attr++) - class_device_remove_file(class_dev, *attr); + device_remove_file(dev, *attr); } static struct class_interface pccard_rsrc_interface = { .class = &pcmcia_socket_class, - .add = &pccard_sysfs_add_rsrc, - .remove = __devexit_p(&pccard_sysfs_remove_rsrc), + .add_dev = &pccard_sysfs_add_rsrc, + .remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc), }; static int __init nonstatic_sysfs_init(void) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index e433704e026a..d2a3bea55de2 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -478,10 +478,10 @@ dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, i * * Returns: the number of characters added to the buffer */ -static ssize_t show_status(struct class_device *class_dev, char *buf) +static ssize_t show_status(struct device *dev, char *buf) { struct soc_pcmcia_socket *skt = - container_of(class_dev, struct soc_pcmcia_socket, socket.dev); + container_of(dev, struct soc_pcmcia_socket, socket.dev); char *p = buf; p+=sprintf(p, "slot : %d\n", skt->nr); @@ -747,7 +747,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops add_timer(&skt->poll_timer); - class_device_create_file(&skt->socket.dev, &class_device_attr_status); + device_create_file(&skt->socket.dev, &device_attr_status); } dev_set_drvdata(dev, sinfo); diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index b005602d6b53..ea5765c3bdc0 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -40,7 +40,8 @@ #define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev) -static ssize_t pccard_show_type(struct class_device *dev, char *buf) +static ssize_t pccard_show_type(struct device *dev, struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); @@ -50,9 +51,10 @@ static ssize_t pccard_show_type(struct class_device *dev, char *buf) return sprintf(buf, "32-bit\n"); return sprintf(buf, "16-bit\n"); } -static CLASS_DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL); +static DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL); -static ssize_t pccard_show_voltage(struct class_device *dev, char *buf) +static ssize_t pccard_show_voltage(struct device *dev, struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); @@ -63,28 +65,31 @@ static ssize_t pccard_show_voltage(struct class_device *dev, char *buf) s->socket.Vcc % 10); return sprintf(buf, "X.XV\n"); } -static CLASS_DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL); +static DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL); -static ssize_t pccard_show_vpp(struct class_device *dev, char *buf) +static ssize_t pccard_show_vpp(struct device *dev, struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); if (!(s->state & SOCKET_PRESENT)) return -ENODEV; return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10); } -static CLASS_DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL); +static DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL); -static ssize_t pccard_show_vcc(struct class_device *dev, char *buf) +static ssize_t pccard_show_vcc(struct device *dev, struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); if (!(s->state & SOCKET_PRESENT)) return -ENODEV; return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10); } -static CLASS_DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL); +static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL); -static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { ssize_t ret; struct pcmcia_socket *s = to_socket(dev); @@ -96,16 +101,20 @@ static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, si return ret ? ret : count; } -static CLASS_DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); +static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); -static ssize_t pccard_show_card_pm_state(struct class_device *dev, char *buf) +static ssize_t pccard_show_card_pm_state(struct device *dev, + struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); return sprintf(buf, "%s\n", s->state & SOCKET_SUSPEND ? "off" : "on"); } -static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_card_pm_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { ssize_t ret = -EINVAL; struct pcmcia_socket *s = to_socket(dev); @@ -120,9 +129,11 @@ static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char * return ret ? -ENODEV : count; } -static CLASS_DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state); +static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state); -static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_eject(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { ssize_t ret; struct pcmcia_socket *s = to_socket(dev); @@ -134,16 +145,20 @@ static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, siz return ret ? ret : count; } -static CLASS_DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); +static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); -static ssize_t pccard_show_irq_mask(struct class_device *dev, char *buf) +static ssize_t pccard_show_irq_mask(struct device *dev, + struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); return sprintf(buf, "0x%04x\n", s->irq_mask); } -static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_irq_mask(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { ssize_t ret; struct pcmcia_socket *s = to_socket(dev); @@ -161,16 +176,19 @@ static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, return ret ? ret : count; } -static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask); +static DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask); -static ssize_t pccard_show_resource(struct class_device *dev, char *buf) +static ssize_t pccard_show_resource(struct device *dev, + struct device_attribute *attr, char *buf) { struct pcmcia_socket *s = to_socket(dev); return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no"); } -static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_resource(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { unsigned long flags; struct pcmcia_socket *s = to_socket(dev); @@ -196,7 +214,7 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, return count; } -static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); +static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count) @@ -279,7 +297,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size if (off + count > size) count = size - off; - s = to_socket(container_of(kobj, struct class_device, kobj)); + s = to_socket(container_of(kobj, struct device, kobj)); if (!(s->state & SOCKET_PRESENT)) return -ENODEV; @@ -296,7 +314,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) { - struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj)); + struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj)); cisdump_t *cis; int error; @@ -335,16 +353,16 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz } -static struct class_device_attribute *pccard_socket_attributes[] = { - &class_device_attr_card_type, - &class_device_attr_card_voltage, - &class_device_attr_card_vpp, - &class_device_attr_card_vcc, - &class_device_attr_card_insert, - &class_device_attr_card_pm_state, - &class_device_attr_card_eject, - &class_device_attr_card_irq_mask, - &class_device_attr_available_resources_setup_done, +static struct device_attribute *pccard_socket_attributes[] = { + &dev_attr_card_type, + &dev_attr_card_voltage, + &dev_attr_card_vpp, + &dev_attr_card_vcc, + &dev_attr_card_insert, + &dev_attr_card_pm_state, + &dev_attr_card_eject, + &dev_attr_card_irq_mask, + &dev_attr_available_resources_setup_done, NULL, }; @@ -355,35 +373,35 @@ static struct bin_attribute pccard_cis_attr = { .write = pccard_store_cis, }; -static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev, +static int __devinit pccard_sysfs_add_socket(struct device *dev, struct class_interface *class_intf) { - struct class_device_attribute **attr; + struct device_attribute **attr; int ret = 0; for (attr = pccard_socket_attributes; *attr; attr++) { - ret = class_device_create_file(class_dev, *attr); + ret = device_create_file(dev, *attr); if (ret) break; } if (!ret) - ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr); + ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr); return ret; } -static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev, +static void __devexit pccard_sysfs_remove_socket(struct device *dev, struct class_interface *class_intf) { - struct class_device_attribute **attr; + struct device_attribute **attr; - sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr); + sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr); for (attr = pccard_socket_attributes; *attr; attr++) - class_device_remove_file(class_dev, *attr); + device_remove_file(dev, *attr); } struct class_interface pccard_sysfs_interface = { .class = &pcmcia_socket_class, - .add = &pccard_sysfs_add_socket, - .remove = __devexit_p(&pccard_sysfs_remove_socket), + .add_dev = &pccard_sysfs_add_socket, + .remove_dev = __devexit_p(&pccard_sysfs_remove_socket), }; diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index 2d2f415f80a8..c158cf38b9dd 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -512,7 +512,7 @@ static int __init init_tcic(void) for (i = 0; i < sockets; i++) { socket_table[i].socket.ops = &tcic_operations; socket_table[i].socket.resource_ops = &pccard_nonstatic_ops; - socket_table[i].socket.dev.dev = &tcic_device.dev; + socket_table[i].socket.dev.parent = &tcic_device.dev; ret = pcmcia_register_socket(&socket_table[i].socket); if (ret && i) pcmcia_unregister_socket(&socket_table[0].socket); diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index da471bddc972..a61d768f6e0e 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1104,7 +1104,7 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i /* prepare pcmcia_socket */ socket->socket.ops = ¥ta_socket_operations; socket->socket.resource_ops = &pccard_nonstatic_ops; - socket->socket.dev.dev = &dev->dev; + socket->socket.dev.parent = &dev->dev; socket->socket.driver_data = socket; socket->socket.owner = THIS_MODULE; socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD; diff --git a/drivers/pnp/pnpacpi/Kconfig b/drivers/pnp/pnpacpi/Kconfig index b1854171b963..ad27e5e0101f 100644 --- a/drivers/pnp/pnpacpi/Kconfig +++ b/drivers/pnp/pnpacpi/Kconfig @@ -2,8 +2,8 @@ # Plug and Play ACPI configuration # config PNPACPI - bool "Plug and Play ACPI support (EXPERIMENTAL)" - depends on PNP && ACPI && EXPERIMENTAL + bool "Plug and Play ACPI support" + depends on PNP && ACPI default y ---help--- Linux uses the PNPACPI to autodetect built-in diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c index d42015c382af..2065e74bb63f 100644 --- a/drivers/pnp/system.c +++ b/drivers/pnp/system.c @@ -3,7 +3,8 @@ * * Some code is based on pnpbios_core.c * Copyright 2002 Adam Belay - * + * (c) Copyright 2007 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas */ #include @@ -21,18 +22,21 @@ static const struct pnp_device_id pnp_dev_table[] = { { "", 0 } }; -static void reserve_ioport_range(char *pnpid, int start, int end) +static void reserve_range(char *pnpid, int start, int end, int port) { struct resource *res; char *regionid; regionid = kmalloc(16, GFP_KERNEL); - if ( regionid == NULL ) + if (regionid == NULL) return; snprintf(regionid, 16, "pnp %s", pnpid); - res = request_region(start,end-start+1,regionid); - if ( res == NULL ) - kfree( regionid ); + if (port) + res = request_region(start,end-start+1,regionid); + else + res = request_mem_region(start,end-start+1,regionid); + if (res == NULL) + kfree(regionid); else res->flags &= ~IORESOURCE_BUSY; /* @@ -41,26 +45,20 @@ static void reserve_ioport_range(char *pnpid, int start, int end) * have double reservations. */ printk(KERN_INFO - "pnp: %s: ioport range 0x%x-0x%x %s reserved\n", - pnpid, start, end, - NULL != res ? "has been" : "could not be" - ); - - return; + "pnp: %s: %s range 0x%x-0x%x %s reserved\n", + pnpid, port ? "ioport" : "iomem", start, end, + NULL != res ? "has been" : "could not be"); } -static void reserve_resources_of_dev( struct pnp_dev *dev ) +static void reserve_resources_of_dev(struct pnp_dev *dev) { int i; - for (i=0;idev.bus_id, pnp_port_start(dev, i), + pnp_port_end(dev, i), 1); + } + + for (i = 0; i < PNP_MAX_MEM; i++) { + if (!pnp_mem_valid(dev, i)) continue; - reserve_ioport_range( - dev->dev.bus_id, - pnp_port_start(dev, i), - pnp_port_end(dev, i) - ); + + reserve_range(dev->dev.bus_id, pnp_mem_start(dev, i), + pnp_mem_end(dev, i), 0); } return; diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig index ae89b9b88743..165af398fdea 100644 --- a/drivers/s390/Kconfig +++ b/drivers/s390/Kconfig @@ -103,14 +103,8 @@ config CCW_CONSOLE depends on TN3215_CONSOLE || TN3270_CONSOLE default y -config SCLP - bool "Support for SCLP" - help - Include support for the SCLP interface to the service element. - config SCLP_TTY bool "Support for SCLP line mode terminal" - depends on SCLP help Include support for IBM SCLP line-mode terminals. @@ -123,7 +117,6 @@ config SCLP_CONSOLE config SCLP_VT220_TTY bool "Support for SCLP VT220-compatible terminal" - depends on SCLP help Include support for an IBM SCLP VT220-compatible terminal. @@ -136,7 +129,6 @@ config SCLP_VT220_CONSOLE config SCLP_CPI tristate "Control-Program Identification" - depends on SCLP help This option enables the hardware console interface for system identification. This is commonly used for workload management and diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile index 9803c9352d78..5a888704a8d0 100644 --- a/drivers/s390/Makefile +++ b/drivers/s390/Makefile @@ -2,6 +2,8 @@ # Makefile for the S/390 specific device drivers # +CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w + obj-y += s390mach.o sysinfo.o s390_rdev.o obj-y += cio/ block/ char/ crypto/ net/ scsi/ diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 492b68bcd7cc..eb5dc62f0d9c 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -37,6 +37,7 @@ */ debug_info_t *dasd_debug_area; struct dasd_discipline *dasd_diag_discipline_pointer; +void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); MODULE_AUTHOR("Holger Smolinski "); MODULE_DESCRIPTION("Linux on S/390 DASD device driver," @@ -51,7 +52,6 @@ static int dasd_alloc_queue(struct dasd_device * device); static void dasd_setup_queue(struct dasd_device * device); static void dasd_free_queue(struct dasd_device * device); static void dasd_flush_request_queue(struct dasd_device *); -static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); static int dasd_flush_ccw_queue(struct dasd_device *, int); static void dasd_tasklet(struct dasd_device *); static void do_kick_device(struct work_struct *); @@ -483,7 +483,7 @@ unsigned int dasd_profile_level = DASD_PROFILE_OFF; /* * Add profiling information for cqr before execution. */ -static inline void +static void dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr, struct request *req) { @@ -505,7 +505,7 @@ dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr, /* * Add profiling information for cqr after execution. */ -static inline void +static void dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr, struct request *req) { @@ -1022,8 +1022,6 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) era = dasd_era_none; - else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) - era = dasd_era_fatal; /* don't recover this request */ else if (irb->esw.esw0.erw.cons) era = device->discipline->examine_error(cqr, irb); else @@ -1104,7 +1102,7 @@ __dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr) /* * Process ccw request queue. */ -static inline void +static void __dasd_process_ccw_queue(struct dasd_device * device, struct list_head *final_queue) { @@ -1127,7 +1125,9 @@ restart: cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock(); } else { - if (cqr->irb.esw.esw0.erw.cons) { + if (cqr->irb.esw.esw0.erw.cons && + test_bit(DASD_CQR_FLAGS_USE_ERP, + &cqr->flags)) { erp_fn = device->discipline-> erp_action(cqr); erp_fn(cqr); @@ -1181,7 +1181,7 @@ dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data) /* * Fetch requests from the block device queue. */ -static inline void +static void __dasd_process_blk_queue(struct dasd_device * device) { request_queue_t *queue; @@ -1232,6 +1232,19 @@ __dasd_process_blk_queue(struct dasd_device * device) if (IS_ERR(cqr)) { if (PTR_ERR(cqr) == -ENOMEM) break; /* terminate request queue loop */ + if (PTR_ERR(cqr) == -EAGAIN) { + /* + * The current request cannot be build right + * now, we have to try later. If this request + * is the head-of-queue we stop the device + * for 1/2 second. + */ + if (!list_empty(&device->ccw_queue)) + break; + device->stopped |= DASD_STOPPED_PENDING; + dasd_set_timer(device, HZ/2); + break; + } DBF_DEV_EVENT(DBF_ERR, device, "CCW creation failed (rc=%ld) " "on request %p", @@ -1254,7 +1267,7 @@ __dasd_process_blk_queue(struct dasd_device * device) * Take a look at the first request on the ccw queue and check * if it reached its expire time. If so, terminate the IO. */ -static inline void +static void __dasd_check_expire(struct dasd_device * device) { struct dasd_ccw_req *cqr; @@ -1285,7 +1298,7 @@ __dasd_check_expire(struct dasd_device * device) * Take a look at the first request on the ccw queue and check * if it needs to be started. */ -static inline void +static void __dasd_start_head(struct dasd_device * device) { struct dasd_ccw_req *cqr; diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 4d01040c2c63..8b9d68f6e016 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -170,7 +170,6 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb) /* log the erp chain if fatal error occurred */ if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) { dasd_log_sense(cqr, irb); - dasd_log_ccw(cqr, 0, irb->scsw.cpa); } return era; @@ -2640,7 +2639,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) struct dasd_ccw_req *erp = NULL; struct dasd_device *device = cqr->device; - __u32 cpa = cqr->irb.scsw.cpa; struct dasd_ccw_req *temp_erp = NULL; if (device->features & DASD_FEATURE_ERPLOG) { @@ -2706,9 +2704,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) } } - if (erp->status == DASD_CQR_FAILED) - dasd_log_ccw(erp, 1, cpa); - /* enqueue added ERP request */ if (erp->status == DASD_CQR_FILLED) { erp->status = DASD_CQR_QUEUED; diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 5943266152f5..ed70852cc915 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -136,7 +136,7 @@ __setup ("dasd=", dasd_call_setup); /* * Read a device busid/devno from a string. */ -static inline int +static int dasd_busid(char **str, int *id0, int *id1, int *devno) { int val, old_style; @@ -182,7 +182,7 @@ dasd_busid(char **str, int *id0, int *id1, int *devno) * only one: "ro" for read-only devices. The default feature set * is empty (value 0). */ -static inline int +static int dasd_feature_list(char *str, char **endp) { int features, len, rc; @@ -341,7 +341,7 @@ dasd_parse_range( char *parsestring ) { return ERR_PTR(-EINVAL); } -static inline char * +static char * dasd_parse_next_element( char *parsestring ) { char * residual_str; residual_str = dasd_parse_keyword(parsestring); diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 53db58a68617..ab782bb46ac1 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -43,7 +43,7 @@ MODULE_LICENSE("GPL"); #define DIAG_MAX_RETRIES 32 #define DIAG_TIMEOUT 50 * HZ -struct dasd_discipline dasd_diag_discipline; +static struct dasd_discipline dasd_diag_discipline; struct dasd_diag_private { struct dasd_diag_characteristics rdc_data; @@ -90,7 +90,7 @@ static inline int dia250(void *iob, int cmd) * block offset. On success, return zero and set end_block to contain the * number of blocks on the device minus the specified offset. Return non-zero * otherwise. */ -static __inline__ int +static inline int mdsk_init_io(struct dasd_device *device, unsigned int blocksize, blocknum_t offset, blocknum_t *end_block) { @@ -117,7 +117,7 @@ mdsk_init_io(struct dasd_device *device, unsigned int blocksize, /* Remove block I/O environment for device. Return zero on success, non-zero * otherwise. */ -static __inline__ int +static inline int mdsk_term_io(struct dasd_device * device) { struct dasd_diag_private *private; @@ -576,7 +576,7 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, "dump sense not available for DIAG data"); } -struct dasd_discipline dasd_diag_discipline = { +static struct dasd_discipline dasd_diag_discipline = { .owner = THIS_MODULE, .name = "DIAG", .ebcname = "DIAG", diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index fdaa471e845f..cecab2274a6e 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -134,44 +134,7 @@ ceil_quot(unsigned int d1, unsigned int d2) return (d1 + (d2 - 1)) / d2; } -static inline int -bytes_per_record(struct dasd_eckd_characteristics *rdc, int kl, int dl) -{ - unsigned int fl1, fl2, int1, int2; - int bpr; - - switch (rdc->formula) { - case 0x01: - fl1 = round_up_multiple(ECKD_F2(rdc) + dl, ECKD_F1(rdc)); - fl2 = round_up_multiple(kl ? ECKD_F2(rdc) + kl : 0, - ECKD_F1(rdc)); - bpr = fl1 + fl2; - break; - case 0x02: - int1 = ceil_quot(dl + ECKD_F6(rdc), ECKD_F5(rdc) << 1); - int2 = ceil_quot(kl + ECKD_F6(rdc), ECKD_F5(rdc) << 1); - fl1 = round_up_multiple(ECKD_F1(rdc) * ECKD_F2(rdc) + dl + - ECKD_F6(rdc) + ECKD_F4(rdc) * int1, - ECKD_F1(rdc)); - fl2 = round_up_multiple(ECKD_F1(rdc) * ECKD_F3(rdc) + kl + - ECKD_F6(rdc) + ECKD_F4(rdc) * int2, - ECKD_F1(rdc)); - bpr = fl1 + fl2; - break; - default: - bpr = 0; - break; - } - return bpr; -} - -static inline unsigned int -bytes_per_track(struct dasd_eckd_characteristics *rdc) -{ - return *(unsigned int *) (rdc->byte_per_track) >> 8; -} - -static inline unsigned int +static unsigned int recs_per_track(struct dasd_eckd_characteristics * rdc, unsigned int kl, unsigned int dl) { @@ -204,37 +167,39 @@ recs_per_track(struct dasd_eckd_characteristics * rdc, return 0; } -static inline void +static int check_XRC (struct ccw1 *de_ccw, struct DE_eckd_data *data, struct dasd_device *device) { struct dasd_eckd_private *private; + int rc; private = (struct dasd_eckd_private *) device->private; + if (!private->rdc_data.facilities.XRC_supported) + return 0; /* switch on System Time Stamp - needed for XRC Support */ - if (private->rdc_data.facilities.XRC_supported) { + data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ + data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ - data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ - data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ + rc = get_sync_clock(&data->ep_sys_time); + /* Ignore return code if sync clock is switched off. */ + if (rc == -ENOSYS || rc == -EACCES) + rc = 0; - data->ep_sys_time = get_clock (); + de_ccw->count = sizeof (struct DE_eckd_data); + de_ccw->flags |= CCW_FLAG_SLI; + return rc; +} - de_ccw->count = sizeof (struct DE_eckd_data); - de_ccw->flags |= CCW_FLAG_SLI; - } - - return; - -} /* end check_XRC */ - -static inline void +static int define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, int totrk, int cmd, struct dasd_device * device) { struct dasd_eckd_private *private; struct ch_t geo, beg, end; + int rc = 0; private = (struct dasd_eckd_private *) device->private; @@ -263,12 +228,12 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, case DASD_ECKD_CCW_WRITE_KD_MT: data->mask.perm = 0x02; data->attributes.operation = private->attrib.operation; - check_XRC (ccw, data, device); + rc = check_XRC (ccw, data, device); break; case DASD_ECKD_CCW_WRITE_CKD: case DASD_ECKD_CCW_WRITE_CKD_MT: data->attributes.operation = DASD_BYPASS_CACHE; - check_XRC (ccw, data, device); + rc = check_XRC (ccw, data, device); break; case DASD_ECKD_CCW_ERASE: case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: @@ -276,7 +241,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, data->mask.perm = 0x3; data->mask.auth = 0x1; data->attributes.operation = DASD_BYPASS_CACHE; - check_XRC (ccw, data, device); + rc = check_XRC (ccw, data, device); break; default: DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd); @@ -312,9 +277,10 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, data->beg_ext.head = beg.head; data->end_ext.cyl = end.cyl; data->end_ext.head = end.head; + return rc; } -static inline void +static void locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, int rec_on_trk, int no_rec, int cmd, struct dasd_device * device, int reclen) @@ -548,7 +514,7 @@ dasd_eckd_read_conf(struct dasd_device *device) /* * Build CP for Perform Subsystem Function - SSC. */ -struct dasd_ccw_req * +static struct dasd_ccw_req * dasd_eckd_build_psf_ssc(struct dasd_device *device) { struct dasd_ccw_req *cqr; @@ -1200,7 +1166,12 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) return cqr; ccw = cqr->cpaddr; /* First ccw is define extent. */ - define_extent(ccw++, cqr->data, first_trk, last_trk, cmd, device); + if (define_extent(ccw++, cqr->data, first_trk, + last_trk, cmd, device) == -EAGAIN) { + /* Clock not in sync and XRC is enabled. Try again later. */ + dasd_sfree_request(cqr, device); + return ERR_PTR(-EAGAIN); + } /* Build locate_record+read/write/ccws. */ idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data)); LO_data = (struct LO_eckd_data *) (idaws + cidaw); @@ -1380,7 +1351,7 @@ dasd_eckd_release(struct dasd_device *device) cqr->device = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); - cqr->retries = 0; + cqr->retries = 2; /* set retry counter to enable basic ERP */ cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1420,7 +1391,7 @@ dasd_eckd_reserve(struct dasd_device *device) cqr->device = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); - cqr->retries = 0; + cqr->retries = 2; /* set retry counter to enable basic ERP */ cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1459,7 +1430,7 @@ dasd_eckd_steal_lock(struct dasd_device *device) cqr->device = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); - cqr->retries = 0; + cqr->retries = 2; /* set retry counter to enable basic ERP */ cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1609,7 +1580,7 @@ dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp) * Dump the range of CCWs into 'page' buffer * and return number of printed chars. */ -static inline int +static int dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page) { int len, count; diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index e0bf30ebb215..6cedc914077e 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -658,18 +658,24 @@ static struct file_operations dasd_eer_fops = { .owner = THIS_MODULE, }; -static struct miscdevice dasd_eer_dev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "dasd_eer", - .fops = &dasd_eer_fops, -}; +static struct miscdevice *dasd_eer_dev = NULL; int __init dasd_eer_init(void) { int rc; - rc = misc_register(&dasd_eer_dev); + dasd_eer_dev = kzalloc(sizeof(*dasd_eer_dev), GFP_KERNEL); + if (!dasd_eer_dev) + return -ENOMEM; + + dasd_eer_dev->minor = MISC_DYNAMIC_MINOR; + dasd_eer_dev->name = "dasd_eer"; + dasd_eer_dev->fops = &dasd_eer_fops; + + rc = misc_register(dasd_eer_dev); if (rc) { + kfree(dasd_eer_dev); + dasd_eer_dev = NULL; MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not " "register misc device"); return rc; @@ -680,5 +686,9 @@ int __init dasd_eer_init(void) void dasd_eer_exit(void) { - WARN_ON(misc_deregister(&dasd_eer_dev) != 0); + if (dasd_eer_dev) { + WARN_ON(misc_deregister(dasd_eer_dev) != 0); + kfree(dasd_eer_dev); + dasd_eer_dev = NULL; + } } diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index 58a65097922b..caa5d91420f8 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -152,25 +152,6 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr) } /* end default_erp_postaction */ -/* - * Print the hex dump of the memory used by a request. This includes - * all error recovery ccws that have been chained in from of the - * real request. - */ -static inline void -hex_dump_memory(struct dasd_device *device, void *data, int len) -{ - int *pint; - - pint = (int *) data; - while (len > 0) { - DEV_MESSAGE(KERN_ERR, device, "%p: %08x %08x %08x %08x", - pint, pint[0], pint[1], pint[2], pint[3]); - pint += 4; - len -= 16; - } -} - void dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb) { @@ -182,69 +163,8 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb) device->discipline->dump_sense(device, cqr, irb); } -void -dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa) -{ - struct dasd_device *device; - struct dasd_ccw_req *lcqr; - struct ccw1 *ccw; - int cplength; - - device = cqr->device; - /* log the channel program */ - for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) { - DEV_MESSAGE(KERN_ERR, device, - "(%s) ERP chain report for req: %p", - caller == 0 ? "EXAMINE" : "ACTION", lcqr); - hex_dump_memory(device, lcqr, sizeof(struct dasd_ccw_req)); - - cplength = 1; - ccw = lcqr->cpaddr; - while (ccw++->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) - cplength++; - - if (cplength > 40) { /* log only parts of the CP */ - DEV_MESSAGE(KERN_ERR, device, "%s", - "Start of channel program:"); - hex_dump_memory(device, lcqr->cpaddr, - 40*sizeof(struct ccw1)); - - DEV_MESSAGE(KERN_ERR, device, "%s", - "End of channel program:"); - hex_dump_memory(device, lcqr->cpaddr + cplength - 10, - 10*sizeof(struct ccw1)); - } else { /* log the whole CP */ - DEV_MESSAGE(KERN_ERR, device, "%s", - "Channel program (complete):"); - hex_dump_memory(device, lcqr->cpaddr, - cplength*sizeof(struct ccw1)); - } - - if (lcqr != cqr) - continue; - - /* - * Log bytes arround failed CCW but only if we did - * not log the whole CP of the CCW is outside the - * logged CP. - */ - if (cplength > 40 || - ((addr_t) cpa < (addr_t) lcqr->cpaddr && - (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) { - - DEV_MESSAGE(KERN_ERR, device, - "Failed CCW (%p) (area):", - (void *) (long) cpa); - hex_dump_memory(device, cqr->cpaddr - 10, - 20*sizeof(struct ccw1)); - } - } - -} /* end log_erp_chain */ - EXPORT_SYMBOL(dasd_default_erp_action); EXPORT_SYMBOL(dasd_default_erp_postaction); EXPORT_SYMBOL(dasd_alloc_erp_request); EXPORT_SYMBOL(dasd_free_erp_request); EXPORT_SYMBOL(dasd_log_sense); -EXPORT_SYMBOL(dasd_log_ccw); diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index b857fd5893fd..be0909e39226 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -75,7 +75,7 @@ static struct ccw_driver dasd_fba_driver = { .notify = dasd_generic_notify, }; -static inline void +static void define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw, int blksize, int beg, int nr) { @@ -95,7 +95,7 @@ define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw, data->ext_end = nr - 1; } -static inline void +static void locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw, int block_nr, int block_ct) { diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index d163632101d2..47ba4462708d 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -147,7 +147,7 @@ dasd_destroy_partitions(struct dasd_device * device) */ memset(&bpart, 0, sizeof(struct blkpg_partition)); memset(&barg, 0, sizeof(struct blkpg_ioctl_arg)); - barg.data = (void __user *) &bpart; + barg.data = (void __force __user *) &bpart; barg.op = BLKPG_DEL_PARTITION; for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--) ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index fb725e3b08fe..a2cc69e11410 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -559,7 +559,6 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int, struct dasd_device *); void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *); void dasd_log_sense(struct dasd_ccw_req *, struct irb *); -void dasd_log_ccw(struct dasd_ccw_req *, int, __u32); /* externals in dasd_3370_erp.c */ dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *); diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index bfa010f6dab2..8b7e11815d70 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -28,7 +28,7 @@ static struct proc_dir_entry *dasd_proc_root_entry = NULL; static struct proc_dir_entry *dasd_devices_entry = NULL; static struct proc_dir_entry *dasd_statistics_entry = NULL; -static inline char * +static char * dasd_get_user_string(const char __user *user_buf, size_t user_len) { char *buffer; @@ -154,7 +154,7 @@ static struct file_operations dasd_devices_file_ops = { .release = seq_release, }; -static inline int +static int dasd_calc_metrics(char *page, char **start, off_t off, int count, int *eof, int len) { @@ -167,8 +167,8 @@ dasd_calc_metrics(char *page, char **start, off_t off, return len; } -static inline char * -dasd_statistics_array(char *str, int *array, int shift) +static char * +dasd_statistics_array(char *str, unsigned int *array, int shift) { int i; diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index be9b05347b4f..1340451ea408 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -102,7 +102,7 @@ dcssblk_release_segment(struct device *dev) * device needs to be enqueued before the semaphore is * freed. */ -static inline int +static int dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info) { int minor, found; @@ -230,7 +230,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch SEGMENT_SHARED); if (rc < 0) { BUG_ON(rc == -EINVAL); - if (rc == -EIO || rc == -ENOENT) + if (rc != -EAGAIN) goto removeseg; } else { dev_info->is_shared = 1; @@ -253,7 +253,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch SEGMENT_EXCLUSIVE); if (rc < 0) { BUG_ON(rc == -EINVAL); - if (rc == -EIO || rc == -ENOENT) + if (rc != -EAGAIN) goto removeseg; } else { dev_info->is_shared = 0; diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index c3e97b4fc186..293e667b50f2 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -2,7 +2,8 @@ # S/390 character devices # -obj-y += ctrlchar.o keyboard.o defkeymap.o +obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ + sclp_info.o obj-$(CONFIG_TN3270) += raw3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o @@ -11,7 +12,6 @@ obj-$(CONFIG_TN3270_FS) += fs3270.o obj-$(CONFIG_TN3215) += con3215.o -obj-$(CONFIG_SCLP) += sclp.o sclp_rw.o sclp_quiesce.o obj-$(CONFIG_SCLP_TTY) += sclp_tty.o obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 25b5d7a66417..9a328f14a641 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -1121,7 +1121,7 @@ static const struct tty_operations tty3215_ops = { * 3215 tty registration code called from tty_init(). * Most kernel services (incl. kmalloc) are available at this poimt. */ -int __init +static int __init tty3215_init(void) { struct tty_driver *driver; diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index 7566be890688..8e7f2d7633d6 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -69,8 +69,7 @@ static void con3270_update(struct con3270 *); /* * Setup timeout for a device. On timeout trigger an update. */ -void -con3270_set_timer(struct con3270 *cp, int expires) +static void con3270_set_timer(struct con3270 *cp, int expires) { if (expires == 0) { if (timer_pending(&cp->timer)) diff --git a/drivers/s390/char/defkeymap.c b/drivers/s390/char/defkeymap.c index 17027d918cf7..564baca01b7c 100644 --- a/drivers/s390/char/defkeymap.c +++ b/drivers/s390/char/defkeymap.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include u_short plain_map[NR_KEYS] = { 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 0893d306ae80..e1a746269c4c 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -23,7 +23,7 @@ #include "raw3270.h" #include "ctrlchar.h" -struct raw3270_fn fs3270_fn; +static struct raw3270_fn fs3270_fn; struct fs3270 { struct raw3270_view view; @@ -401,7 +401,7 @@ fs3270_release(struct raw3270_view *view) } /* View to a 3270 device. Can be console, tty or fullscreen. */ -struct raw3270_fn fs3270_fn = { +static struct raw3270_fn fs3270_fn = { .activate = fs3270_activate, .deactivate = fs3270_deactivate, .intv = (void *) fs3270_irq, diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index 3e86fd1756e5..f62f9a4e8950 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -148,6 +148,7 @@ kbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc) } } +#if 0 /* * Generate ebcdic -> ascii translation table from kbd_data. */ @@ -173,6 +174,7 @@ kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc) } } } +#endif /* * We have a combining character DIACR here, followed by the character CH. diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index cdb24f528112..9e451acc6491 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -67,8 +67,8 @@ static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn) return -EINVAL; } -static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv, - struct monwrite_hdr *monhdr) +static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv, + struct monwrite_hdr *monhdr) { struct mon_buf *entry, *next; diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 7a84014f2037..8facd14adb7c 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -29,7 +29,7 @@ #include #include -struct class *class3270; +static struct class *class3270; /* The main 3270 data structure. */ struct raw3270 { @@ -86,7 +86,7 @@ DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue); /* * Encode array for 12 bit 3270 addresses. */ -unsigned char raw3270_ebcgraf[64] = { +static unsigned char raw3270_ebcgraf[64] = { 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 8a056df09d6b..f171de3b0b11 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -59,7 +59,8 @@ static volatile enum sclp_init_state_t { /* Internal state: is a request active at the sclp? */ static volatile enum sclp_running_state_t { sclp_running_state_idle, - sclp_running_state_running + sclp_running_state_running, + sclp_running_state_reset_pending } sclp_running_state = sclp_running_state_idle; /* Internal state: is a read request pending? */ @@ -88,15 +89,15 @@ static volatile enum sclp_mask_state_t { /* Timeout intervals in seconds.*/ #define SCLP_BUSY_INTERVAL 10 -#define SCLP_RETRY_INTERVAL 15 +#define SCLP_RETRY_INTERVAL 30 static void sclp_process_queue(void); static int sclp_init_mask(int calculate); static int sclp_init(void); /* Perform service call. Return 0 on success, non-zero otherwise. */ -static int -service_call(sclp_cmdw_t command, void *sccb) +int +sclp_service_call(sclp_cmdw_t command, void *sccb) { int cc; @@ -113,19 +114,17 @@ service_call(sclp_cmdw_t command, void *sccb) return 0; } -/* Request timeout handler. Restart the request queue. If DATA is non-zero, - * force restart of running request. */ -static void -sclp_request_timeout(unsigned long data) -{ - unsigned long flags; +static inline void __sclp_make_read_req(void); - if (data) { - spin_lock_irqsave(&sclp_lock, flags); - sclp_running_state = sclp_running_state_idle; - spin_unlock_irqrestore(&sclp_lock, flags); +static void +__sclp_queue_read_req(void) +{ + if (sclp_reading_state == sclp_reading_state_idle) { + sclp_reading_state = sclp_reading_state_reading; + __sclp_make_read_req(); + /* Add request to head of queue */ + list_add(&sclp_read_req.list, &sclp_req_queue); } - sclp_process_queue(); } /* Set up request retry timer. Called while sclp_lock is locked. */ @@ -140,6 +139,29 @@ __sclp_set_request_timer(unsigned long time, void (*function)(unsigned long), add_timer(&sclp_request_timer); } +/* Request timeout handler. Restart the request queue. If DATA is non-zero, + * force restart of running request. */ +static void +sclp_request_timeout(unsigned long data) +{ + unsigned long flags; + + spin_lock_irqsave(&sclp_lock, flags); + if (data) { + if (sclp_running_state == sclp_running_state_running) { + /* Break running state and queue NOP read event request + * to get a defined interface state. */ + __sclp_queue_read_req(); + sclp_running_state = sclp_running_state_idle; + } + } else { + __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ, + sclp_request_timeout, 0); + } + spin_unlock_irqrestore(&sclp_lock, flags); + sclp_process_queue(); +} + /* Try to start a request. Return zero if the request was successfully * started or if it will be started at a later time. Return non-zero otherwise. * Called while sclp_lock is locked. */ @@ -151,7 +173,7 @@ __sclp_start_request(struct sclp_req *req) if (sclp_running_state != sclp_running_state_idle) return 0; del_timer(&sclp_request_timer); - rc = service_call(req->command, req->sccb); + rc = sclp_service_call(req->command, req->sccb); req->start_count++; if (rc == 0) { @@ -191,7 +213,15 @@ sclp_process_queue(void) rc = __sclp_start_request(req); if (rc == 0) break; - /* Request failed. */ + /* Request failed */ + if (req->start_count > 1) { + /* Cannot abort already submitted request - could still + * be active at the SCLP */ + __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ, + sclp_request_timeout, 0); + break; + } + /* Post-processing for aborted request */ list_del(&req->list); if (req->callback) { spin_unlock_irqrestore(&sclp_lock, flags); @@ -221,7 +251,8 @@ sclp_add_request(struct sclp_req *req) list_add_tail(&req->list, &sclp_req_queue); rc = 0; /* Start if request is first in list */ - if (req->list.prev == &sclp_req_queue) { + if (sclp_running_state == sclp_running_state_idle && + req->list.prev == &sclp_req_queue) { rc = __sclp_start_request(req); if (rc) list_del(&req->list); @@ -294,7 +325,7 @@ __sclp_make_read_req(void) sccb = (struct sccb_header *) sclp_read_sccb; clear_page(sccb); memset(&sclp_read_req, 0, sizeof(struct sclp_req)); - sclp_read_req.command = SCLP_CMDW_READDATA; + sclp_read_req.command = SCLP_CMDW_READ_EVENT_DATA; sclp_read_req.status = SCLP_REQ_QUEUED; sclp_read_req.start_count = 0; sclp_read_req.callback = sclp_read_cb; @@ -334,6 +365,8 @@ sclp_interrupt_handler(__u16 code) finished_sccb = S390_lowcore.ext_params & 0xfffffff8; evbuf_pending = S390_lowcore.ext_params & 0x3; if (finished_sccb) { + del_timer(&sclp_request_timer); + sclp_running_state = sclp_running_state_reset_pending; req = __sclp_find_req(finished_sccb); if (req) { /* Request post-processing */ @@ -348,13 +381,8 @@ sclp_interrupt_handler(__u16 code) sclp_running_state = sclp_running_state_idle; } if (evbuf_pending && sclp_receive_mask != 0 && - sclp_reading_state == sclp_reading_state_idle && - sclp_activation_state == sclp_activation_state_active ) { - sclp_reading_state = sclp_reading_state_reading; - __sclp_make_read_req(); - /* Add request to head of queue */ - list_add(&sclp_read_req.list, &sclp_req_queue); - } + sclp_activation_state == sclp_activation_state_active) + __sclp_queue_read_req(); spin_unlock(&sclp_lock); sclp_process_queue(); } @@ -374,6 +402,7 @@ sclp_sync_wait(void) unsigned long flags; unsigned long cr0, cr0_sync; u64 timeout; + int irq_context; /* We'll be disabling timer interrupts, so we need a custom timeout * mechanism */ @@ -386,7 +415,9 @@ sclp_sync_wait(void) } local_irq_save(flags); /* Prevent bottom half from executing once we force interrupts open */ - local_bh_disable(); + irq_context = in_interrupt(); + if (!irq_context) + local_bh_disable(); /* Enable service-signal interruption, disable timer interrupts */ trace_hardirqs_on(); __ctl_store(cr0, 0, 0); @@ -402,19 +433,19 @@ sclp_sync_wait(void) get_clock() > timeout && del_timer(&sclp_request_timer)) sclp_request_timer.function(sclp_request_timer.data); - barrier(); cpu_relax(); } local_irq_disable(); __ctl_load(cr0, 0, 0); - _local_bh_enable(); + if (!irq_context) + _local_bh_enable(); local_irq_restore(flags); } EXPORT_SYMBOL(sclp_sync_wait); /* Dispatch changes in send and receive mask to registered listeners. */ -static inline void +static void sclp_dispatch_state_change(void) { struct list_head *l; @@ -597,7 +628,7 @@ __sclp_make_init_req(u32 receive_mask, u32 send_mask) sccb = (struct init_sccb *) sclp_init_sccb; clear_page(sccb); memset(&sclp_init_req, 0, sizeof(struct sclp_req)); - sclp_init_req.command = SCLP_CMDW_WRITEMASK; + sclp_init_req.command = SCLP_CMDW_WRITE_EVENT_MASK; sclp_init_req.status = SCLP_REQ_FILLED; sclp_init_req.start_count = 0; sclp_init_req.callback = NULL; @@ -800,7 +831,7 @@ sclp_check_interface(void) for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) { __sclp_make_init_req(0, 0); sccb = (struct init_sccb *) sclp_init_req.sccb; - rc = service_call(sclp_init_req.command, sccb); + rc = sclp_service_call(sclp_init_req.command, sccb); if (rc == -EIO) break; sclp_init_req.status = SCLP_REQ_RUNNING; diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 2c71d6ee7b5b..7d29ab45a6ed 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -12,7 +12,7 @@ #include #include - +#include #include /* maximum number of pages concerning our own memory management */ @@ -49,9 +49,11 @@ typedef unsigned int sclp_cmdw_t; -#define SCLP_CMDW_READDATA 0x00770005 -#define SCLP_CMDW_WRITEDATA 0x00760005 -#define SCLP_CMDW_WRITEMASK 0x00780005 +#define SCLP_CMDW_READ_EVENT_DATA 0x00770005 +#define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005 +#define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005 +#define SCLP_CMDW_READ_SCP_INFO 0x00020001 +#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 #define GDS_ID_MDSMU 0x1310 #define GDS_ID_MDSRouteInfo 0x1311 @@ -66,13 +68,6 @@ typedef unsigned int sclp_cmdw_t; typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ -struct sccb_header { - u16 length; - u8 function_code; - u8 control_mask[3]; - u16 response_code; -} __attribute__((packed)); - struct gds_subvector { u8 length; u8 key; @@ -131,6 +126,7 @@ void sclp_unregister(struct sclp_register *reg); int sclp_remove_processed(struct sccb_header *sccb); int sclp_deactivate(void); int sclp_reactivate(void); +int sclp_service_call(sclp_cmdw_t command, void *sccb); /* useful inlines */ diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index 86864f641716..ead1043d788e 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c @@ -66,7 +66,7 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc) } while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback)); } -static inline void +static void sclp_conbuf_emit(void) { struct sclp_buffer* buffer; diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c index 4f873ae148b7..65aa2c85737f 100644 --- a/drivers/s390/char/sclp_cpi.c +++ b/drivers/s390/char/sclp_cpi.c @@ -169,7 +169,7 @@ cpi_prepare_req(void) } /* prepare request data structure presented to SCLP driver */ - req->command = SCLP_CMDW_WRITEDATA; + req->command = SCLP_CMDW_WRITE_EVENT_DATA; req->sccb = sccb; req->status = SCLP_REQ_FILLED; req->callback = cpi_callback; diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c new file mode 100644 index 000000000000..7bcbe643b087 --- /dev/null +++ b/drivers/s390/char/sclp_info.c @@ -0,0 +1,57 @@ +/* + * drivers/s390/char/sclp_info.c + * + * Copyright IBM Corp. 2007 + * Author(s): Heiko Carstens + */ + +#include +#include +#include +#include +#include "sclp.h" + +struct sclp_readinfo_sccb s390_readinfo_sccb; + +void __init sclp_readinfo_early(void) +{ + sclp_cmdw_t command; + struct sccb_header *sccb; + int ret; + + __ctl_set_bit(0, 9); /* enable service signal subclass mask */ + + sccb = &s390_readinfo_sccb.header; + command = SCLP_CMDW_READ_SCP_INFO_FORCED; + while (1) { + u16 response; + + memset(&s390_readinfo_sccb, 0, sizeof(s390_readinfo_sccb)); + sccb->length = sizeof(s390_readinfo_sccb); + sccb->control_mask[2] = 0x80; + + ret = sclp_service_call(command, &s390_readinfo_sccb); + + if (ret == -EIO) + goto out; + if (ret == -EBUSY) + continue; + + __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT | + PSW_MASK_WAIT | PSW_DEFAULT_KEY); + local_irq_disable(); + barrier(); + + response = sccb->response_code; + + if (response == 0x10) + break; + + if (response != 0x1f0 || command == SCLP_CMDW_READ_SCP_INFO) + break; + + command = SCLP_CMDW_READ_SCP_INFO; + } +out: + __ctl_clear_bit(0, 9); /* disable service signal subclass mask */ +} diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c index 0c92d3909cca..2486783ea58e 100644 --- a/drivers/s390/char/sclp_rw.c +++ b/drivers/s390/char/sclp_rw.c @@ -460,7 +460,7 @@ sclp_emit_buffer(struct sclp_buffer *buffer, sccb->msg_buf.header.type = EvTyp_PMsgCmd; else return -ENOSYS; - buffer->request.command = SCLP_CMDW_WRITEDATA; + buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA; buffer->request.status = SCLP_REQ_FILLED; buffer->request.callback = sclp_writedata_callback; buffer->request.callback_data = buffer; diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 2d173e5c8a09..90536f60bf50 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -721,7 +721,7 @@ static const struct tty_operations sclp_ops = { .ioctl = sclp_tty_ioctl, }; -int __init +static int __init sclp_tty_init(void) { struct tty_driver *driver; diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 723bf4191bfe..544f137d70d7 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -207,7 +207,7 @@ __sclp_vt220_emit(struct sclp_vt220_request *request) request->sclp_req.status = SCLP_REQ_FAILED; return -EIO; } - request->sclp_req.command = SCLP_CMDW_WRITEDATA; + request->sclp_req.command = SCLP_CMDW_WRITE_EVENT_DATA; request->sclp_req.status = SCLP_REQ_FILLED; request->sclp_req.callback = sclp_vt220_callback; request->sclp_req.callback_data = (void *) request; @@ -669,7 +669,7 @@ static const struct tty_operations sclp_vt220_ops = { /* * Register driver with SCLP and Linux and initialize internal tty structures. */ -int __init +static int __init sclp_vt220_tty_init(void) { struct tty_driver *driver; diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index c9f1c4c8bb13..bb4ff537729d 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h @@ -3,7 +3,7 @@ * tape device driver for 3480/3490E/3590 tapes. * * S390 and zSeries version - * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2001,2006 * Author(s): Carsten Otte * Tuan Ngo-Anh * Martin Schwidefsky @@ -99,7 +99,11 @@ enum tape_op { TO_DIS, /* Tape display */ TO_ASSIGN, /* Assign tape to channel path */ TO_UNASSIGN, /* Unassign tape from channel path */ - TO_SIZE /* #entries in tape_op_t */ + TO_CRYPT_ON, /* Enable encrpytion */ + TO_CRYPT_OFF, /* Disable encrpytion */ + TO_KEKL_SET, /* Set KEK label */ + TO_KEKL_QUERY, /* Query KEK label */ + TO_SIZE, /* #entries in tape_op_t */ }; /* Forward declaration */ @@ -112,6 +116,7 @@ enum tape_request_status { TAPE_REQUEST_IN_IO, /* request is currently in IO */ TAPE_REQUEST_DONE, /* request is completed. */ TAPE_REQUEST_CANCEL, /* request should be canceled. */ + TAPE_REQUEST_LONG_BUSY, /* request has to be restarted after long busy */ }; /* Tape CCW request */ @@ -164,10 +169,11 @@ struct tape_discipline { * The discipline irq function either returns an error code (<0) which * means that the request has failed with an error or one of the following: */ -#define TAPE_IO_SUCCESS 0 /* request successful */ -#define TAPE_IO_PENDING 1 /* request still running */ -#define TAPE_IO_RETRY 2 /* retry to current request */ -#define TAPE_IO_STOP 3 /* stop the running request */ +#define TAPE_IO_SUCCESS 0 /* request successful */ +#define TAPE_IO_PENDING 1 /* request still running */ +#define TAPE_IO_RETRY 2 /* retry to current request */ +#define TAPE_IO_STOP 3 /* stop the running request */ +#define TAPE_IO_LONG_BUSY 4 /* delay the running request */ /* Char Frontend Data */ struct tape_char_data { @@ -242,6 +248,10 @@ struct tape_device { /* Function to start or stop the next request later. */ struct delayed_work tape_dnr; + + /* Timer for long busy */ + struct timer_list lb_timeout; + }; /* Externals from tape_core.c */ diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 9df912f63188..50f5edab83d7 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -2,7 +2,7 @@ * drivers/s390/char/tape_3590.c * tape device discipline for 3590 tapes. * - * Copyright (C) IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001,2006 * Author(s): Stefan Bader * Michael Holzheu * Martin Schwidefsky @@ -11,6 +11,7 @@ #include #include #include +#include #define TAPE_DBF_AREA tape_3590_dbf @@ -30,7 +31,7 @@ EXPORT_SYMBOL(TAPE_DBF_AREA); * - Read Device (buffered) log: BRA * - Read Library log: BRA * - Swap Devices: BRA - * - Long Busy: BRA + * - Long Busy: implemented * - Special Intercept: BRA * - Read Alternate: implemented *******************************************************************/ @@ -94,6 +95,332 @@ static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = { [0xae] = "Subsystem environmental alert", }; +static int crypt_supported(struct tape_device *device) +{ + return TAPE390_CRYPT_SUPPORTED(TAPE_3590_CRYPT_INFO(device)); +} + +static int crypt_enabled(struct tape_device *device) +{ + return TAPE390_CRYPT_ON(TAPE_3590_CRYPT_INFO(device)); +} + +static void ext_to_int_kekl(struct tape390_kekl *in, + struct tape3592_kekl *out) +{ + int i; + + memset(out, 0, sizeof(*out)); + if (in->type == TAPE390_KEKL_TYPE_HASH) + out->flags |= 0x40; + if (in->type_on_tape == TAPE390_KEKL_TYPE_HASH) + out->flags |= 0x80; + strncpy(out->label, in->label, 64); + for (i = strlen(in->label); i < sizeof(out->label); i++) + out->label[i] = ' '; + ASCEBC(out->label, sizeof(out->label)); +} + +static void int_to_ext_kekl(struct tape3592_kekl *in, + struct tape390_kekl *out) +{ + memset(out, 0, sizeof(*out)); + if(in->flags & 0x40) + out->type = TAPE390_KEKL_TYPE_HASH; + else + out->type = TAPE390_KEKL_TYPE_LABEL; + if(in->flags & 0x80) + out->type_on_tape = TAPE390_KEKL_TYPE_HASH; + else + out->type_on_tape = TAPE390_KEKL_TYPE_LABEL; + memcpy(out->label, in->label, sizeof(in->label)); + EBCASC(out->label, sizeof(in->label)); + strstrip(out->label); +} + +static void int_to_ext_kekl_pair(struct tape3592_kekl_pair *in, + struct tape390_kekl_pair *out) +{ + if (in->count == 0) { + out->kekl[0].type = TAPE390_KEKL_TYPE_NONE; + out->kekl[0].type_on_tape = TAPE390_KEKL_TYPE_NONE; + out->kekl[1].type = TAPE390_KEKL_TYPE_NONE; + out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE; + } else if (in->count == 1) { + int_to_ext_kekl(&in->kekl[0], &out->kekl[0]); + out->kekl[1].type = TAPE390_KEKL_TYPE_NONE; + out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE; + } else if (in->count == 2) { + int_to_ext_kekl(&in->kekl[0], &out->kekl[0]); + int_to_ext_kekl(&in->kekl[1], &out->kekl[1]); + } else { + printk("Invalid KEKL number: %d\n", in->count); + BUG(); + } +} + +static int check_ext_kekl(struct tape390_kekl *kekl) +{ + if (kekl->type == TAPE390_KEKL_TYPE_NONE) + goto invalid; + if (kekl->type > TAPE390_KEKL_TYPE_HASH) + goto invalid; + if (kekl->type_on_tape == TAPE390_KEKL_TYPE_NONE) + goto invalid; + if (kekl->type_on_tape > TAPE390_KEKL_TYPE_HASH) + goto invalid; + if ((kekl->type == TAPE390_KEKL_TYPE_HASH) && + (kekl->type_on_tape == TAPE390_KEKL_TYPE_LABEL)) + goto invalid; + + return 0; +invalid: + return -EINVAL; +} + +static int check_ext_kekl_pair(struct tape390_kekl_pair *kekls) +{ + if (check_ext_kekl(&kekls->kekl[0])) + goto invalid; + if (check_ext_kekl(&kekls->kekl[1])) + goto invalid; + + return 0; +invalid: + return -EINVAL; +} + +/* + * Query KEKLs + */ +static int tape_3592_kekl_query(struct tape_device *device, + struct tape390_kekl_pair *ext_kekls) +{ + struct tape_request *request; + struct tape3592_kekl_query_order *order; + struct tape3592_kekl_query_data *int_kekls; + int rc; + + DBF_EVENT(6, "tape3592_kekl_query\n"); + int_kekls = kmalloc(sizeof(*int_kekls), GFP_KERNEL|GFP_DMA); + if (!int_kekls) + return -ENOMEM; + request = tape_alloc_request(2, sizeof(*order)); + if (IS_ERR(request)) { + rc = PTR_ERR(request); + goto fail_malloc; + } + order = request->cpdata; + memset(order,0,sizeof(*order)); + order->code = 0xe2; + order->max_count = 2; + request->op = TO_KEKL_QUERY; + tape_ccw_cc(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order); + tape_ccw_end(request->cpaddr + 1, READ_SS_DATA, sizeof(*int_kekls), + int_kekls); + rc = tape_do_io(device, request); + if (rc) + goto fail_request; + int_to_ext_kekl_pair(&int_kekls->kekls, ext_kekls); + + rc = 0; +fail_request: + tape_free_request(request); +fail_malloc: + kfree(int_kekls); + return rc; +} + +/* + * IOCTL: Query KEKLs + */ +static int tape_3592_ioctl_kekl_query(struct tape_device *device, + unsigned long arg) +{ + int rc; + struct tape390_kekl_pair *ext_kekls; + + DBF_EVENT(6, "tape_3592_ioctl_kekl_query\n"); + if (!crypt_supported(device)) + return -ENOSYS; + if (!crypt_enabled(device)) + return -EUNATCH; + ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL); + if (!ext_kekls) + return -ENOMEM; + rc = tape_3592_kekl_query(device, ext_kekls); + if (rc != 0) + goto fail; + if (copy_to_user((char __user *) arg, ext_kekls, sizeof(*ext_kekls))) { + rc = -EFAULT; + goto fail; + } + rc = 0; +fail: + kfree(ext_kekls); + return rc; +} + +static int tape_3590_mttell(struct tape_device *device, int mt_count); + +/* + * Set KEKLs + */ +static int tape_3592_kekl_set(struct tape_device *device, + struct tape390_kekl_pair *ext_kekls) +{ + struct tape_request *request; + struct tape3592_kekl_set_order *order; + + DBF_EVENT(6, "tape3592_kekl_set\n"); + if (check_ext_kekl_pair(ext_kekls)) { + DBF_EVENT(6, "invalid kekls\n"); + return -EINVAL; + } + if (tape_3590_mttell(device, 0) != 0) + return -EBADSLT; + request = tape_alloc_request(1, sizeof(*order)); + if (IS_ERR(request)) + return PTR_ERR(request); + order = request->cpdata; + memset(order, 0, sizeof(*order)); + order->code = 0xe3; + order->kekls.count = 2; + ext_to_int_kekl(&ext_kekls->kekl[0], &order->kekls.kekl[0]); + ext_to_int_kekl(&ext_kekls->kekl[1], &order->kekls.kekl[1]); + request->op = TO_KEKL_SET; + tape_ccw_end(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order); + + return tape_do_io_free(device, request); +} + +/* + * IOCTL: Set KEKLs + */ +static int tape_3592_ioctl_kekl_set(struct tape_device *device, + unsigned long arg) +{ + int rc; + struct tape390_kekl_pair *ext_kekls; + + DBF_EVENT(6, "tape_3592_ioctl_kekl_set\n"); + if (!crypt_supported(device)) + return -ENOSYS; + if (!crypt_enabled(device)) + return -EUNATCH; + ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL); + if (!ext_kekls) + return -ENOMEM; + if (copy_from_user(ext_kekls, (char __user *)arg, sizeof(*ext_kekls))) { + rc = -EFAULT; + goto out; + } + rc = tape_3592_kekl_set(device, ext_kekls); +out: + kfree(ext_kekls); + return rc; +} + +/* + * Enable encryption + */ +static int tape_3592_enable_crypt(struct tape_device *device) +{ + struct tape_request *request; + char *data; + + DBF_EVENT(6, "tape_3592_enable_crypt\n"); + if (!crypt_supported(device)) + return -ENOSYS; + request = tape_alloc_request(2, 72); + if (IS_ERR(request)) + return PTR_ERR(request); + data = request->cpdata; + memset(data,0,72); + + data[0] = 0x05; + data[36 + 0] = 0x03; + data[36 + 1] = 0x03; + data[36 + 4] = 0x40; + data[36 + 6] = 0x01; + data[36 + 14] = 0x2f; + data[36 + 18] = 0xc3; + data[36 + 35] = 0x72; + request->op = TO_CRYPT_ON; + tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); + tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36); + return tape_do_io_free(device, request); +} + +/* + * Disable encryption + */ +static int tape_3592_disable_crypt(struct tape_device *device) +{ + struct tape_request *request; + char *data; + + DBF_EVENT(6, "tape_3592_disable_crypt\n"); + if (!crypt_supported(device)) + return -ENOSYS; + request = tape_alloc_request(2, 72); + if (IS_ERR(request)) + return PTR_ERR(request); + data = request->cpdata; + memset(data,0,72); + + data[0] = 0x05; + data[36 + 0] = 0x03; + data[36 + 1] = 0x03; + data[36 + 35] = 0x32; + + request->op = TO_CRYPT_OFF; + tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); + tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36); + + return tape_do_io_free(device, request); +} + +/* + * IOCTL: Set encryption status + */ +static int tape_3592_ioctl_crypt_set(struct tape_device *device, + unsigned long arg) +{ + struct tape390_crypt_info info; + + DBF_EVENT(6, "tape_3592_ioctl_crypt_set\n"); + if (!crypt_supported(device)) + return -ENOSYS; + if (copy_from_user(&info, (char __user *)arg, sizeof(info))) + return -EFAULT; + if (info.status & ~TAPE390_CRYPT_ON_MASK) + return -EINVAL; + if (info.status & TAPE390_CRYPT_ON_MASK) + return tape_3592_enable_crypt(device); + else + return tape_3592_disable_crypt(device); +} + +static int tape_3590_sense_medium(struct tape_device *device); + +/* + * IOCTL: Query enryption status + */ +static int tape_3592_ioctl_crypt_query(struct tape_device *device, + unsigned long arg) +{ + DBF_EVENT(6, "tape_3592_ioctl_crypt_query\n"); + if (!crypt_supported(device)) + return -ENOSYS; + tape_3590_sense_medium(device); + if (copy_to_user((char __user *) arg, &TAPE_3590_CRYPT_INFO(device), + sizeof(TAPE_3590_CRYPT_INFO(device)))) + return -EFAULT; + else + return 0; +} + /* * 3590 IOCTL Overload */ @@ -109,6 +436,14 @@ tape_3590_ioctl(struct tape_device *device, unsigned int cmd, unsigned long arg) return tape_std_display(device, &disp); } + case TAPE390_KEKL_SET: + return tape_3592_ioctl_kekl_set(device, arg); + case TAPE390_KEKL_QUERY: + return tape_3592_ioctl_kekl_query(device, arg); + case TAPE390_CRYPT_SET: + return tape_3592_ioctl_crypt_set(device, arg); + case TAPE390_CRYPT_QUERY: + return tape_3592_ioctl_crypt_query(device, arg); default: return -EINVAL; /* no additional ioctls */ } @@ -248,6 +583,12 @@ tape_3590_work_handler(struct work_struct *work) case TO_READ_ATTMSG: tape_3590_read_attmsg(p->device); break; + case TO_CRYPT_ON: + tape_3592_enable_crypt(p->device); + break; + case TO_CRYPT_OFF: + tape_3592_disable_crypt(p->device); + break; default: DBF_EVENT(3, "T3590: work handler undefined for " "operation 0x%02x\n", p->op); @@ -365,6 +706,33 @@ tape_3590_check_locate(struct tape_device *device, struct tape_request *request) } #endif +static void tape_3590_med_state_set(struct tape_device *device, + struct tape_3590_med_sense *sense) +{ + struct tape390_crypt_info *c_info; + + c_info = &TAPE_3590_CRYPT_INFO(device); + + if (sense->masst == MSENSE_UNASSOCIATED) { + tape_med_state_set(device, MS_UNLOADED); + TAPE_3590_CRYPT_INFO(device).medium_status = 0; + return; + } + if (sense->masst != MSENSE_ASSOCIATED_MOUNT) { + PRINT_ERR("Unknown medium state: %x\n", sense->masst); + return; + } + tape_med_state_set(device, MS_LOADED); + c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK; + if (sense->flags & MSENSE_CRYPT_MASK) { + PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags); + c_info->medium_status |= TAPE390_MEDIUM_ENCRYPTED_MASK; + } else { + DBF_EVENT(6, "Medium is not encrypted %04x\n", sense->flags); + c_info->medium_status &= ~TAPE390_MEDIUM_ENCRYPTED_MASK; + } +} + /* * The done handler is called at device/channel end and wakes up the sleeping * process @@ -372,9 +740,10 @@ tape_3590_check_locate(struct tape_device *device, struct tape_request *request) static int tape_3590_done(struct tape_device *device, struct tape_request *request) { - struct tape_3590_med_sense *sense; + struct tape_3590_disc_data *disc_data; DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]); + disc_data = device->discdata; switch (request->op) { case TO_BSB: @@ -394,13 +763,20 @@ tape_3590_done(struct tape_device *device, struct tape_request *request) break; case TO_RUN: tape_med_state_set(device, MS_UNLOADED); + tape_3590_schedule_work(device, TO_CRYPT_OFF); break; case TO_MSEN: - sense = (struct tape_3590_med_sense *) request->cpdata; - if (sense->masst == MSENSE_UNASSOCIATED) - tape_med_state_set(device, MS_UNLOADED); - if (sense->masst == MSENSE_ASSOCIATED_MOUNT) - tape_med_state_set(device, MS_LOADED); + tape_3590_med_state_set(device, request->cpdata); + break; + case TO_CRYPT_ON: + TAPE_3590_CRYPT_INFO(device).status + |= TAPE390_CRYPT_ON_MASK; + *(device->modeset_byte) |= 0x03; + break; + case TO_CRYPT_OFF: + TAPE_3590_CRYPT_INFO(device).status + &= ~TAPE390_CRYPT_ON_MASK; + *(device->modeset_byte) &= ~0x03; break; case TO_RBI: /* RBI seems to succeed even without medium loaded. */ case TO_NOP: /* Same to NOP. */ @@ -409,8 +785,9 @@ tape_3590_done(struct tape_device *device, struct tape_request *request) case TO_DIS: case TO_ASSIGN: case TO_UNASSIGN: - break; case TO_SIZE: + case TO_KEKL_SET: + case TO_KEKL_QUERY: break; } return TAPE_IO_SUCCESS; @@ -540,10 +917,8 @@ static int tape_3590_erp_long_busy(struct tape_device *device, struct tape_request *request, struct irb *irb) { - /* FIXME: how about WAITING for a minute ? */ - PRINT_WARN("(%s): Device is busy! Please wait a minute!\n", - device->cdev->dev.bus_id); - return tape_3590_erp_basic(device, request, irb, -EBUSY); + DBF_EVENT(6, "Device is busy\n"); + return TAPE_IO_LONG_BUSY; } /* @@ -951,6 +1326,34 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb) device->cdev->dev.bus_id, sense->mc); } +static int tape_3590_crypt_error(struct tape_device *device, + struct tape_request *request, struct irb *irb) +{ + u8 cu_rc, ekm_rc1; + u16 ekm_rc2; + u32 drv_rc; + char *bus_id, *sense; + + sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data; + bus_id = device->cdev->dev.bus_id; + cu_rc = sense[0]; + drv_rc = *((u32*) &sense[5]) & 0xffffff; + ekm_rc1 = sense[9]; + ekm_rc2 = *((u16*) &sense[10]); + if ((cu_rc == 0) && (ekm_rc2 == 0xee31)) + /* key not defined on EKM */ + return tape_3590_erp_basic(device, request, irb, -EKEYREJECTED); + if ((cu_rc == 1) || (cu_rc == 2)) + /* No connection to EKM */ + return tape_3590_erp_basic(device, request, irb, -ENOTCONN); + + PRINT_ERR("(%s): Unable to get encryption key from EKM\n", bus_id); + PRINT_ERR("(%s): CU=%02X DRIVE=%06X EKM=%02X:%04X\n", bus_id, cu_rc, + drv_rc, ekm_rc1, ekm_rc2); + + return tape_3590_erp_basic(device, request, irb, -ENOKEY); +} + /* * 3590 error Recovery routine: * If possible, it tries to recover from the error. If this is not possible, @@ -979,6 +1382,8 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, sense = (struct tape_3590_sense *) irb->ecw; + DBF_EVENT(6, "Unit Check: RQC = %x\n", sense->rc_rqc); + /* * First check all RC-QRCs where we want to do something special * - "break": basic error recovery is done @@ -999,6 +1404,8 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, case 0x2231: tape_3590_print_era_msg(device, irb); return tape_3590_erp_special_interrupt(device, request, irb); + case 0x2240: + return tape_3590_crypt_error(device, request, irb); case 0x3010: DBF_EVENT(2, "(%08x): Backward at Beginning of Partition\n", @@ -1020,6 +1427,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, DBF_EVENT(2, "(%08x): Rewind Unload complete\n", device->cdev_id); tape_med_state_set(device, MS_UNLOADED); + tape_3590_schedule_work(device, TO_CRYPT_OFF); return tape_3590_erp_basic(device, request, irb, 0); case 0x4010: @@ -1030,9 +1438,15 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, PRINT_WARN("(%s): Tape operation when medium not loaded\n", device->cdev->dev.bus_id); tape_med_state_set(device, MS_UNLOADED); + tape_3590_schedule_work(device, TO_CRYPT_OFF); return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM); case 0x4012: /* Device Long Busy */ + /* XXX: Also use long busy handling here? */ + DBF_EVENT(6, "(%08x): LONG BUSY\n", device->cdev_id); tape_3590_print_era_msg(device, irb); + return tape_3590_erp_basic(device, request, irb, -EBUSY); + case 0x4014: + DBF_EVENT(6, "(%08x): Crypto LONG BUSY\n", device->cdev_id); return tape_3590_erp_long_busy(device, request, irb); case 0x5010: @@ -1064,6 +1478,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, case 0x5120: case 0x1120: tape_med_state_set(device, MS_UNLOADED); + tape_3590_schedule_work(device, TO_CRYPT_OFF); return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM); case 0x6020: @@ -1142,21 +1557,47 @@ tape_3590_setup_device(struct tape_device *device) { int rc; struct tape_3590_disc_data *data; + char *rdc_data; DBF_EVENT(6, "3590 device setup\n"); - data = kmalloc(sizeof(struct tape_3590_disc_data), - GFP_KERNEL | GFP_DMA); + data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA); if (data == NULL) return -ENOMEM; data->read_back_op = READ_PREVIOUS; device->discdata = data; - if ((rc = tape_std_assign(device)) == 0) { - /* Try to find out if medium is loaded */ - if ((rc = tape_3590_sense_medium(device)) != 0) - DBF_LH(3, "3590 medium sense returned %d\n", rc); + rdc_data = kmalloc(64, GFP_KERNEL | GFP_DMA); + if (!rdc_data) { + rc = -ENOMEM; + goto fail_kmalloc; } + rc = read_dev_chars(device->cdev, (void**)&rdc_data, 64); + if (rc) { + DBF_LH(3, "Read device characteristics failed!\n"); + goto fail_kmalloc; + } + rc = tape_std_assign(device); + if (rc) + goto fail_rdc_data; + if (rdc_data[31] == 0x13) { + PRINT_INFO("Device has crypto support\n"); + data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK; + tape_3592_disable_crypt(device); + } else { + DBF_EVENT(6, "Device has NO crypto support\n"); + } + /* Try to find out if medium is loaded */ + rc = tape_3590_sense_medium(device); + if (rc) { + DBF_LH(3, "3590 medium sense returned %d\n", rc); + goto fail_rdc_data; + } + return 0; +fail_rdc_data: + kfree(rdc_data); +fail_kmalloc: + kfree(data); return rc; } diff --git a/drivers/s390/char/tape_3590.h b/drivers/s390/char/tape_3590.h index cf274b9445a6..aa5138807af1 100644 --- a/drivers/s390/char/tape_3590.h +++ b/drivers/s390/char/tape_3590.h @@ -2,7 +2,7 @@ * drivers/s390/char/tape_3590.h * tape device discipline for 3590 tapes. * - * Copyright (C) IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001,2006 * Author(s): Stefan Bader * Michael Holzheu * Martin Schwidefsky @@ -38,16 +38,22 @@ #define MSENSE_UNASSOCIATED 0x00 #define MSENSE_ASSOCIATED_MOUNT 0x01 #define MSENSE_ASSOCIATED_UMOUNT 0x02 +#define MSENSE_CRYPT_MASK 0x00000010 #define TAPE_3590_MAX_MSG 0xb0 /* Datatypes */ struct tape_3590_disc_data { - unsigned char modeset_byte; + struct tape390_crypt_info crypt_info; int read_back_op; }; +#define TAPE_3590_CRYPT_INFO(device) \ + ((struct tape_3590_disc_data*)(device->discdata))->crypt_info +#define TAPE_3590_READ_BACK_OP(device) \ + ((struct tape_3590_disc_data*)(device->discdata))->read_back_op + struct tape_3590_sense { unsigned int command_rej:1; @@ -118,7 +124,48 @@ struct tape_3590_sense { struct tape_3590_med_sense { unsigned int macst:4; unsigned int masst:4; - char pad[127]; + char pad1[7]; + unsigned int flags; + char pad2[116]; +} __attribute__ ((packed)); + +/* Datastructures for 3592 encryption support */ + +struct tape3592_kekl { + __u8 flags; + char label[64]; +} __attribute__ ((packed)); + +struct tape3592_kekl_pair { + __u8 count; + struct tape3592_kekl kekl[2]; +} __attribute__ ((packed)); + +struct tape3592_kekl_query_data { + __u16 len; + __u8 fmt; + __u8 mc; + __u32 id; + __u8 flags; + struct tape3592_kekl_pair kekls; + char reserved[116]; +} __attribute__ ((packed)); + +struct tape3592_kekl_query_order { + __u8 code; + __u8 flags; + char reserved1[2]; + __u8 max_count; + char reserved2[35]; +} __attribute__ ((packed)); + +struct tape3592_kekl_set_order { + __u8 code; + __u8 flags; + char reserved1[2]; + __u8 op; + struct tape3592_kekl_pair kekls; + char reserved2[120]; } __attribute__ ((packed)); #endif /* _TAPE_3590_H */ diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index c8a89b3b87d4..dd0ecaed592e 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -73,7 +73,7 @@ tapeblock_trigger_requeue(struct tape_device *device) /* * Post finished request. */ -static inline void +static void tapeblock_end_request(struct request *req, int uptodate) { if (end_that_request_first(req, uptodate, req->hard_nr_sectors)) @@ -108,7 +108,7 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data) /* * Feed the tape device CCW queue with requests supplied in a list. */ -static inline int +static int tapeblock_start_request(struct tape_device *device, struct request *req) { struct tape_request * ccw_req; diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index 31198c8f2718..9faea04e11e9 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -3,7 +3,7 @@ * character device frontend for tape device driver * * S390 and zSeries version - * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2001,2006 * Author(s): Carsten Otte * Michael Holzheu * Tuan Ngo-Anh @@ -89,22 +89,7 @@ tapechar_cleanup_device(struct tape_device *device) device->nt = NULL; } -/* - * Terminate write command (we write two TMs and skip backward over last) - * This ensures that the tape is always correctly terminated. - * When the user writes afterwards a new file, he will overwrite the - * second TM and therefore one TM will remain to separate the - * two files on the tape... - */ -static inline void -tapechar_terminate_write(struct tape_device *device) -{ - if (tape_mtop(device, MTWEOF, 1) == 0 && - tape_mtop(device, MTWEOF, 1) == 0) - tape_mtop(device, MTBSR, 1); -} - -static inline int +static int tapechar_check_idalbuffer(struct tape_device *device, size_t block_size) { struct idal_buffer *new; @@ -137,7 +122,7 @@ tapechar_check_idalbuffer(struct tape_device *device, size_t block_size) /* * Tape device read function */ -ssize_t +static ssize_t tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) { struct tape_device *device; @@ -201,7 +186,7 @@ tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) /* * Tape device write function */ -ssize_t +static ssize_t tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t *ppos) { struct tape_device *device; @@ -291,7 +276,7 @@ tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t /* * Character frontend tape device open function. */ -int +static int tapechar_open (struct inode *inode, struct file *filp) { struct tape_device *device; @@ -326,7 +311,7 @@ tapechar_open (struct inode *inode, struct file *filp) * Character frontend tape device release function. */ -int +static int tapechar_release(struct inode *inode, struct file *filp) { struct tape_device *device; diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index c6c2e918b990..e2a8a1a04bab 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -3,7 +3,7 @@ * basic function of the tape device driver * * S390 and zSeries version - * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2001,2006 * Author(s): Carsten Otte * Michael Holzheu * Tuan Ngo-Anh @@ -26,9 +26,11 @@ #include "tape_std.h" #define PRINTK_HEADER "TAPE_CORE: " +#define LONG_BUSY_TIMEOUT 180 /* seconds */ static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *); static void tape_delayed_next_request(struct work_struct *); +static void tape_long_busy_timeout(unsigned long data); /* * One list to contain all tape devices of all disciplines, so @@ -69,10 +71,12 @@ const char *tape_op_verbose[TO_SIZE] = [TO_LOAD] = "LOA", [TO_READ_CONFIG] = "RCF", [TO_READ_ATTMSG] = "RAT", [TO_DIS] = "DIS", [TO_ASSIGN] = "ASS", - [TO_UNASSIGN] = "UAS" + [TO_UNASSIGN] = "UAS", [TO_CRYPT_ON] = "CON", + [TO_CRYPT_OFF] = "COF", [TO_KEKL_SET] = "KLS", + [TO_KEKL_QUERY] = "KLQ", }; -static inline int +static int busid_to_int(char *bus_id) { int dec; @@ -252,7 +256,7 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate) /* * Stop running ccw. Has to be called with the device lock held. */ -static inline int +static int __tape_cancel_io(struct tape_device *device, struct tape_request *request) { int retries; @@ -346,6 +350,9 @@ tape_generic_online(struct tape_device *device, return -EINVAL; } + init_timer(&device->lb_timeout); + device->lb_timeout.function = tape_long_busy_timeout; + /* Let the discipline have a go at the device. */ device->discipline = discipline; if (!try_module_get(discipline->owner)) { @@ -385,7 +392,7 @@ out: return rc; } -static inline void +static void tape_cleanup_device(struct tape_device *device) { tapeblock_cleanup_device(device); @@ -563,7 +570,7 @@ tape_generic_probe(struct ccw_device *cdev) return ret; } -static inline void +static void __tape_discard_requests(struct tape_device *device) { struct tape_request * request; @@ -703,7 +710,7 @@ tape_free_request (struct tape_request * request) kfree(request); } -static inline int +static int __tape_start_io(struct tape_device *device, struct tape_request *request) { int rc; @@ -733,7 +740,7 @@ __tape_start_io(struct tape_device *device, struct tape_request *request) return rc; } -static inline void +static void __tape_start_next_request(struct tape_device *device) { struct list_head *l, *n; @@ -801,7 +808,23 @@ tape_delayed_next_request(struct work_struct *work) spin_unlock_irq(get_ccwdev_lock(device->cdev)); } -static inline void +static void tape_long_busy_timeout(unsigned long data) +{ + struct tape_request *request; + struct tape_device *device; + + device = (struct tape_device *) data; + spin_lock_irq(get_ccwdev_lock(device->cdev)); + request = list_entry(device->req_queue.next, struct tape_request, list); + if (request->status != TAPE_REQUEST_LONG_BUSY) + BUG(); + DBF_LH(6, "%08x: Long busy timeout.\n", device->cdev_id); + __tape_start_next_request(device); + device->lb_timeout.data = (unsigned long) tape_put_device(device); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); +} + +static void __tape_end_request( struct tape_device * device, struct tape_request * request, @@ -878,7 +901,7 @@ tape_dump_sense_dbf(struct tape_device *device, struct tape_request *request, * and starts it if the tape is idle. Has to be called with * the device lock held. */ -static inline int +static int __tape_start_request(struct tape_device *device, struct tape_request *request) { int rc; @@ -1094,7 +1117,22 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) /* May be an unsolicited irq */ if(request != NULL) request->rescnt = irb->scsw.count; - + else if ((irb->scsw.dstat == 0x85 || irb->scsw.dstat == 0x80) && + !list_empty(&device->req_queue)) { + /* Not Ready to Ready after long busy ? */ + struct tape_request *req; + req = list_entry(device->req_queue.next, + struct tape_request, list); + if (req->status == TAPE_REQUEST_LONG_BUSY) { + DBF_EVENT(3, "(%08x): del timer\n", device->cdev_id); + if (del_timer(&device->lb_timeout)) { + device->lb_timeout.data = (unsigned long) + tape_put_device(device); + __tape_start_next_request(device); + } + return; + } + } if (irb->scsw.dstat != 0x0c) { /* Set the 'ONLINE' flag depending on sense byte 1 */ if(*(((__u8 *) irb->ecw) + 1) & SENSE_DRIVE_ONLINE) @@ -1142,6 +1180,15 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) break; case TAPE_IO_PENDING: break; + case TAPE_IO_LONG_BUSY: + device->lb_timeout.data = + (unsigned long)tape_get_device_reference(device); + device->lb_timeout.expires = jiffies + + LONG_BUSY_TIMEOUT * HZ; + DBF_EVENT(3, "(%08x): add timer\n", device->cdev_id); + add_timer(&device->lb_timeout); + request->status = TAPE_REQUEST_LONG_BUSY; + break; case TAPE_IO_RETRY: rc = __tape_start_io(device, request); if (rc) diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 09844621edc0..bc33068b9ce2 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -36,7 +36,7 @@ struct tty_driver *tty3270_driver; static int tty3270_max_index; -struct raw3270_fn tty3270_fn; +static struct raw3270_fn tty3270_fn; struct tty3270_cell { unsigned char character; @@ -119,8 +119,7 @@ static void tty3270_update(struct tty3270 *); /* * Setup timeout for a device. On timeout trigger an update. */ -void -tty3270_set_timer(struct tty3270 *tp, int expires) +static void tty3270_set_timer(struct tty3270 *tp, int expires) { if (expires == 0) { if (timer_pending(&tp->timer) && del_timer(&tp->timer)) @@ -841,7 +840,7 @@ tty3270_del_views(void) } } -struct raw3270_fn tty3270_fn = { +static struct raw3270_fn tty3270_fn = { .activate = tty3270_activate, .deactivate = tty3270_deactivate, .intv = (void *) tty3270_irq, @@ -1754,8 +1753,7 @@ static const struct tty_operations tty3270_ops = { .set_termios = tty3270_set_termios }; -void -tty3270_notifier(int index, int active) +static void tty3270_notifier(int index, int active) { if (active) tty_register_device(tty3270_driver, index, NULL); @@ -1767,8 +1765,7 @@ tty3270_notifier(int index, int active) * 3270 tty registration code called from tty_init(). * Most kernel services (incl. kmalloc) are available at this poimt. */ -int __init -tty3270_init(void) +static int __init tty3270_init(void) { struct tty_driver *driver; int ret; diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 6cb23040954b..4f894dc2373b 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -128,9 +128,8 @@ static iucv_interrupt_ops_t vmlogrdr_iucvops = { .MessagePending = vmlogrdr_iucv_MessagePending, }; - -DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue); -DECLARE_WAIT_QUEUE_HEAD(read_wait_queue); +static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue); +static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue); /* * pointer to system service private structure diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 12c2d6b746e6..aa65df4dfced 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -43,7 +43,7 @@ typedef enum {add, free} range_action; * Function: blacklist_range * (Un-)blacklist the devices from-to */ -static inline void +static void blacklist_range (range_action action, unsigned int from, unsigned int to, unsigned int ssid) { @@ -69,7 +69,7 @@ blacklist_range (range_action action, unsigned int from, unsigned int to, * Get devno/busid from given string. * Shamelessly grabbed from dasd_devmap.c. */ -static inline int +static int blacklist_busid(char **str, int *id0, int *ssid, int *devno) { int val, old_style; @@ -123,10 +123,10 @@ confused: return 1; } -static inline int +static int blacklist_parse_parameters (char *str, range_action action) { - unsigned int from, to, from_id0, to_id0, from_ssid, to_ssid; + int from, to, from_id0, to_id0, from_ssid, to_ssid; while (*str != 0 && *str != '\n') { range_action ra = action; @@ -227,7 +227,7 @@ is_blacklisted (int ssid, int devno) * Function: blacklist_parse_proc_parameters * parse the stuff which is piped to /proc/cio_ignore */ -static inline void +static void blacklist_parse_proc_parameters (char *buf) { if (strncmp (buf, "free ", 5) == 0) { diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 38954f5cd14c..d48e3ca4752c 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -53,7 +53,7 @@ ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer, static struct bus_type ccwgroup_bus_type; -static inline void +static void __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) { int i; @@ -104,7 +104,7 @@ ccwgroup_release (struct device *dev) kfree(gdev); } -static inline int +static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) { char str[8]; @@ -424,7 +424,7 @@ ccwgroup_probe_ccwdev(struct ccw_device *cdev) return 0; } -static inline struct ccwgroup_device * +static struct ccwgroup_device * __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) { struct ccwgroup_device *gdev; diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index cbab8d2ce5cf..6f05a44e3817 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -93,7 +93,7 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page) u16 sch; /* subchannel */ u8 chpid[8]; /* chpids 0-7 */ u16 fla[8]; /* full link addresses 0-7 */ - } *ssd_area; + } __attribute__ ((packed)) *ssd_area; ssd_area = page; @@ -277,7 +277,7 @@ out_unreg: return 0; } -static inline void +static void s390_set_chpid_offline( __u8 chpid) { char dbf_txt[15]; @@ -338,7 +338,7 @@ s390_process_res_acc_sch(struct res_acc_data *res_data, struct subchannel *sch) return 0x80 >> chp; } -static inline int +static int s390_process_res_acc_new_sch(struct subchannel_id schid) { struct schib schib; @@ -444,7 +444,7 @@ __get_chpid_from_lir(void *data) u32 andesc[28]; /* incident-specific information */ u32 isinfo[28]; - } *lir; + } __attribute__ ((packed)) *lir; lir = data; if (!(lir->iq&0x80)) @@ -461,154 +461,146 @@ __get_chpid_from_lir(void *data) return (u16) (lir->indesc[0]&0x000000ff); } -int -chsc_process_crw(void) +struct chsc_sei_area { + struct chsc_header request; + u32 reserved1; + u32 reserved2; + u32 reserved3; + struct chsc_header response; + u32 reserved4; + u8 flags; + u8 vf; /* validity flags */ + u8 rs; /* reporting source */ + u8 cc; /* content code */ + u16 fla; /* full link address */ + u16 rsid; /* reporting source id */ + u32 reserved5; + u32 reserved6; + u8 ccdf[4096 - 16 - 24]; /* content-code dependent field */ + /* ccdf has to be big enough for a link-incident record */ +} __attribute__ ((packed)); + +static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) +{ + int chpid; + + CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n", + sei_area->rs, sei_area->rsid); + if (sei_area->rs != 4) + return 0; + chpid = __get_chpid_from_lir(sei_area->ccdf); + if (chpid < 0) + CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n"); + else + s390_set_chpid_offline(chpid); + + return 0; +} + +static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) { - int chpid, ret; struct res_acc_data res_data; - struct { - struct chsc_header request; - u32 reserved1; - u32 reserved2; - u32 reserved3; - struct chsc_header response; - u32 reserved4; - u8 flags; - u8 vf; /* validity flags */ - u8 rs; /* reporting source */ - u8 cc; /* content code */ - u16 fla; /* full link address */ - u16 rsid; /* reporting source id */ - u32 reserved5; - u32 reserved6; - u32 ccdf[96]; /* content-code dependent field */ - /* ccdf has to be big enough for a link-incident record */ - } *sei_area; + struct device *dev; + int status; + int rc; + + CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, " + "rs_id=%04x)\n", sei_area->rs, sei_area->rsid); + if (sei_area->rs != 4) + return 0; + /* allocate a new channel path structure, if needed */ + status = get_chp_status(sei_area->rsid); + if (status < 0) + new_channel_path(sei_area->rsid); + else if (!status) + return 0; + dev = get_device(&css[0]->chps[sei_area->rsid]->dev); + memset(&res_data, 0, sizeof(struct res_acc_data)); + res_data.chp = to_channelpath(dev); + if ((sei_area->vf & 0xc0) != 0) { + res_data.fla = sei_area->fla; + if ((sei_area->vf & 0xc0) == 0xc0) + /* full link address */ + res_data.fla_mask = 0xffff; + else + /* link address */ + res_data.fla_mask = 0xff00; + } + rc = s390_process_res_acc(&res_data); + put_device(dev); + + return rc; +} + +static int chsc_process_sei(struct chsc_sei_area *sei_area) +{ + int rc; + + /* Check if we might have lost some information. */ + if (sei_area->flags & 0x40) + CIO_CRW_EVENT(2, "chsc: event overflow\n"); + /* which kind of information was stored? */ + rc = 0; + switch (sei_area->cc) { + case 1: /* link incident*/ + rc = chsc_process_sei_link_incident(sei_area); + break; + case 2: /* i/o resource accessibiliy */ + rc = chsc_process_sei_res_acc(sei_area); + break; + default: /* other stuff */ + CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n", + sei_area->cc); + break; + } + + return rc; +} + +int chsc_process_crw(void) +{ + struct chsc_sei_area *sei_area; + int ret; + int rc; if (!sei_page) return 0; - /* - * build the chsc request block for store event information - * and do the call - * This function is only called by the machine check handler thread, - * so we don't need locking for the sei_page. - */ + /* Access to sei_page is serialized through machine check handler + * thread, so no need for locking. */ sei_area = sei_page; CIO_TRACE_EVENT( 2, "prcss"); ret = 0; do { - int ccode, status; - struct device *dev; memset(sei_area, 0, sizeof(*sei_area)); - memset(&res_data, 0, sizeof(struct res_acc_data)); sei_area->request.length = 0x0010; sei_area->request.code = 0x000e; + if (chsc(sei_area)) + break; - ccode = chsc(sei_area); - if (ccode > 0) - return 0; - - switch (sei_area->response.code) { - /* for debug purposes, check for problems */ - case 0x0001: - CIO_CRW_EVENT(4, "chsc_process_crw: event information " - "successfully stored\n"); - break; /* everything ok */ - case 0x0002: - CIO_CRW_EVENT(2, - "chsc_process_crw: invalid command!\n"); - return 0; - case 0x0003: - CIO_CRW_EVENT(2, "chsc_process_crw: error in chsc " - "request block!\n"); - return 0; - case 0x0005: - CIO_CRW_EVENT(2, "chsc_process_crw: no event " - "information stored\n"); - return 0; - default: - CIO_CRW_EVENT(2, "chsc_process_crw: chsc response %d\n", + if (sei_area->response.code == 0x0001) { + CIO_CRW_EVENT(4, "chsc: sei successful\n"); + rc = chsc_process_sei(sei_area); + if (rc) + ret = rc; + } else { + CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", sei_area->response.code); - return 0; - } - - /* Check if we might have lost some information. */ - if (sei_area->flags & 0x40) - CIO_CRW_EVENT(2, "chsc_process_crw: Event information " - "has been lost due to overflow!\n"); - - if (sei_area->rs != 4) { - CIO_CRW_EVENT(2, "chsc_process_crw: reporting source " - "(%04X) isn't a chpid!\n", - sei_area->rsid); - continue; - } - - /* which kind of information was stored? */ - switch (sei_area->cc) { - case 1: /* link incident*/ - CIO_CRW_EVENT(4, "chsc_process_crw: " - "channel subsystem reports link incident," - " reporting source is chpid %x\n", - sei_area->rsid); - chpid = __get_chpid_from_lir(sei_area->ccdf); - if (chpid < 0) - CIO_CRW_EVENT(4, "%s: Invalid LIR, skipping\n", - __FUNCTION__); - else - s390_set_chpid_offline(chpid); - break; - - case 2: /* i/o resource accessibiliy */ - CIO_CRW_EVENT(4, "chsc_process_crw: " - "channel subsystem reports some I/O " - "devices may have become accessible\n"); - pr_debug("Data received after sei: \n"); - pr_debug("Validity flags: %x\n", sei_area->vf); - - /* allocate a new channel path structure, if needed */ - status = get_chp_status(sei_area->rsid); - if (status < 0) - new_channel_path(sei_area->rsid); - else if (!status) - break; - dev = get_device(&css[0]->chps[sei_area->rsid]->dev); - res_data.chp = to_channelpath(dev); - pr_debug("chpid: %x", sei_area->rsid); - if ((sei_area->vf & 0xc0) != 0) { - res_data.fla = sei_area->fla; - if ((sei_area->vf & 0xc0) == 0xc0) { - pr_debug(" full link addr: %x", - sei_area->fla); - res_data.fla_mask = 0xffff; - } else { - pr_debug(" link addr: %x", - sei_area->fla); - res_data.fla_mask = 0xff00; - } - } - ret = s390_process_res_acc(&res_data); - pr_debug("\n\n"); - put_device(dev); - break; - - default: /* other stuff */ - CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n", - sei_area->cc); + ret = 0; break; } } while (sei_area->flags & 0x80); + return ret; } -static inline int +static int __chp_add_new_sch(struct subchannel_id schid) { struct schib schib; int ret; - if (stsch(schid, &schib)) + if (stsch_err(schid, &schib)) /* We're through */ return need_rescan ? -EAGAIN : -ENXIO; @@ -709,7 +701,7 @@ chp_process_crw(int chpid, int on) return chp_add(chpid); } -static inline int check_for_io_on_path(struct subchannel *sch, int index) +static int check_for_io_on_path(struct subchannel *sch, int index) { int cc; @@ -741,7 +733,7 @@ static void terminate_internal_io(struct subchannel *sch) sch->driver->termination(&sch->dev); } -static inline void +static void __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) { int chp, old_lpm; @@ -967,8 +959,8 @@ static struct bin_attribute chp_measurement_attr = { static void chsc_remove_chp_cmg_attr(struct channel_path *chp) { - sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_chars_attr); - sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_attr); + device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr); + device_remove_bin_file(&chp->dev, &chp_measurement_attr); } static int @@ -976,14 +968,12 @@ chsc_add_chp_cmg_attr(struct channel_path *chp) { int ret; - ret = sysfs_create_bin_file(&chp->dev.kobj, - &chp_measurement_chars_attr); + ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr); if (ret) return ret; - ret = sysfs_create_bin_file(&chp->dev.kobj, &chp_measurement_attr); + ret = device_create_bin_file(&chp->dev, &chp_measurement_attr); if (ret) - sysfs_remove_bin_file(&chp->dev.kobj, - &chp_measurement_chars_attr); + device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr); return ret; } @@ -1042,7 +1032,7 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) u32 : 4; u32 fmt : 4; u32 : 16; - } *secm_area; + } __attribute__ ((packed)) *secm_area; int ret, ccode; secm_area = page; @@ -1253,7 +1243,7 @@ chsc_determine_channel_path_description(int chpid, struct chsc_header response; u32 zeroes2; struct channel_path_desc desc; - } *scpd_area; + } __attribute__ ((packed)) *scpd_area; scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scpd_area) @@ -1350,7 +1340,7 @@ chsc_get_channel_measurement_chars(struct channel_path *chp) u32 cmg : 8; u32 zeroes3; u32 data[NR_MEASUREMENT_CHARS]; - } *scmc_area; + } __attribute__ ((packed)) *scmc_area; scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scmc_area) @@ -1517,7 +1507,7 @@ chsc_enable_facility(int operation_code) u32 reserved5:4; u32 format2:4; u32 reserved6:24; - } *sda_area; + } __attribute__ ((packed)) *sda_area; sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA); if (!sda_area) @@ -1569,7 +1559,7 @@ chsc_determine_css_characteristics(void) u32 reserved4; u32 general_char[510]; u32 chsc_char[518]; - } *scsc_area; + } __attribute__ ((packed)) *scsc_area; scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scsc_area) { diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index a259245780ae..0fb2b024208f 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -10,17 +10,17 @@ struct chsc_header { u16 length; u16 code; -}; +} __attribute__ ((packed)); #define NR_MEASUREMENT_CHARS 5 struct cmg_chars { u32 values[NR_MEASUREMENT_CHARS]; -}; +} __attribute__ ((packed)); #define NR_MEASUREMENT_ENTRIES 8 struct cmg_entry { u32 values[NR_MEASUREMENT_ENTRIES]; -}; +} __attribute__ ((packed)); struct channel_path_desc { u8 flags; @@ -31,7 +31,7 @@ struct channel_path_desc { u8 zeroes; u8 chla; u8 chpp; -}; +} __attribute__ ((packed)); struct channel_path { int id; @@ -47,6 +47,9 @@ struct channel_path { extern void s390_process_css( void ); extern void chsc_validate_chpids(struct subchannel *); extern void chpid_is_actually_online(int); +extern int css_get_ssd_info(struct subchannel *); +extern int chsc_process_crw(void); +extern int chp_process_crw(int, int); struct css_general_char { u64 : 41; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index ae1bf231d089..b3a56dc5f68a 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -122,7 +122,7 @@ cio_get_options (struct subchannel *sch) * Use tpi to get a pending interrupt, call the interrupt handler and * return a pointer to the subchannel structure. */ -static inline int +static int cio_tpi(void) { struct tpi_info *tpi_info; @@ -152,7 +152,7 @@ cio_tpi(void) return 1; } -static inline int +static int cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) { char dbf_text[15]; @@ -585,7 +585,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) * This device must not be known to Linux. So we simply * say that there is no device and return ENODEV. */ - CIO_MSG_EVENT(0, "Blacklisted device detected " + CIO_MSG_EVENT(4, "Blacklisted device detected " "at devno %04X, subchannel set %x\n", sch->schib.pmcw.dev, sch->schid.ssid); err = -ENODEV; @@ -646,7 +646,7 @@ do_IRQ (struct pt_regs *regs) * Make sure that the i/o interrupt did not "overtake" * the last HZ timer interrupt. */ - account_ticks(); + account_ticks(S390_lowcore.int_clock); /* * Get interrupt information from lowcore */ @@ -832,7 +832,7 @@ cio_get_console_subchannel(void) } #endif -static inline int +static int __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) { int retry, cc; @@ -850,7 +850,20 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) return -EBUSY; /* uhm... */ } -static inline int +/* we can't use the normal udelay here, since it enables external interrupts */ + +static void udelay_reset(unsigned long usecs) +{ + uint64_t start_cc, end_cc; + + asm volatile ("STCK %0" : "=m" (start_cc)); + do { + cpu_relax(); + asm volatile ("STCK %0" : "=m" (end_cc)); + } while (((end_cc - start_cc)/4096) < usecs); +} + +static int __clear_subchannel_easy(struct subchannel_id schid) { int retry; @@ -865,7 +878,7 @@ __clear_subchannel_easy(struct subchannel_id schid) if (schid_equal(&ti.schid, &schid)) return 0; } - udelay(100); + udelay_reset(100); } return -EBUSY; } @@ -882,11 +895,11 @@ static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr) int rc; pgm_check_occured = 0; - s390_reset_pgm_handler = cio_reset_pgm_check_handler; + s390_base_pgm_handler_fn = cio_reset_pgm_check_handler; rc = stsch(schid, addr); - s390_reset_pgm_handler = NULL; + s390_base_pgm_handler_fn = NULL; - /* The program check handler could have changed pgm_check_occured */ + /* The program check handler could have changed pgm_check_occured. */ barrier(); if (pgm_check_occured) @@ -944,7 +957,7 @@ static void css_reset(void) /* Reset subchannels. */ for_each_subchannel(__shutdown_subchannel_easy, NULL); /* Reset channel paths. */ - s390_reset_mcck_handler = s390_reset_chpids_mcck_handler; + s390_base_mcck_handler_fn = s390_reset_chpids_mcck_handler; /* Enable channel report machine checks. */ __ctl_set_bit(14, 28); /* Temporarily reenable machine checks. */ @@ -969,7 +982,7 @@ static void css_reset(void) local_mcck_disable(); /* Disable channel report machine checks. */ __ctl_clear_bit(14, 28); - s390_reset_mcck_handler = NULL; + s390_base_mcck_handler_fn = NULL; } static struct reset_call css_reset_call = { diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 828b2d334f0a..90b22faabbf7 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -519,8 +519,8 @@ struct cmb { /* insert a single device into the cmb_area list * called with cmb_area.lock held from alloc_cmb */ -static inline int alloc_cmb_single (struct ccw_device *cdev, - struct cmb_data *cmb_data) +static int alloc_cmb_single(struct ccw_device *cdev, + struct cmb_data *cmb_data) { struct cmb *cmb; struct ccw_device_private *node; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 9d6c02446863..fe0ace7aece8 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -30,7 +30,7 @@ struct channel_subsystem *css[__MAX_CSSID + 1]; int css_characteristics_avail = 0; -inline int +int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data) { struct subchannel_id schid; @@ -108,9 +108,6 @@ css_subchannel_release(struct device *dev) } } -extern int css_get_ssd_info(struct subchannel *sch); - - int css_sch_device_register(struct subchannel *sch) { int ret; @@ -187,7 +184,7 @@ get_subchannel_by_schid(struct subchannel_id schid) return dev ? to_subchannel(dev) : NULL; } -static inline int css_get_subchannel_status(struct subchannel *sch) +static int css_get_subchannel_status(struct subchannel *sch) { struct schib schib; @@ -299,7 +296,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) /* Will be done on the slow path. */ return -EAGAIN; } - if (stsch(schid, &schib) || !schib.pmcw.dnv) { + if (stsch_err(schid, &schib) || !schib.pmcw.dnv) { /* Unusable - ignore. */ return 0; } @@ -417,7 +414,7 @@ static void reprobe_all(struct work_struct *unused) need_reprobe); } -DECLARE_WORK(css_reprobe_work, reprobe_all); +static DECLARE_WORK(css_reprobe_work, reprobe_all); /* Schedule reprobing of all unregistered subchannels. */ void css_schedule_reprobe(void) @@ -578,7 +575,7 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store); -static inline int __init setup_css(int nr) +static int __init setup_css(int nr) { u32 tod_high; int ret; diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 3464c5b875c4..ca2bab932a8a 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -143,6 +143,8 @@ extern void css_sch_device_unregister(struct subchannel *); extern struct subchannel * get_subchannel_by_schid(struct subchannel_id); extern int css_init_done; extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); +extern int css_process_crw(int, int); +extern void css_reiterate_subchannels(void); #define __MAX_SUBCHANNEL 65535 #define __MAX_SSID 3 diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 803579053c2f..e322111fb369 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -138,7 +138,6 @@ struct bus_type ccw_bus_type; static int io_subchannel_probe (struct subchannel *); static int io_subchannel_remove (struct subchannel *); -void io_subchannel_irq (struct device *); static int io_subchannel_notify(struct device *, int); static void io_subchannel_verify(struct device *); static void io_subchannel_ioterm(struct device *); @@ -235,11 +234,8 @@ chpids_show (struct device * dev, struct device_attribute *attr, char * buf) ssize_t ret = 0; int chp; - if (ssd) - for (chp = 0; chp < 8; chp++) - ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]); - else - ret += sprintf (buf, "n/a"); + for (chp = 0; chp < 8; chp++) + ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]); ret += sprintf (buf+ret, "\n"); return min((ssize_t)PAGE_SIZE, ret); } @@ -552,13 +548,13 @@ static struct attribute_group ccwdev_attr_group = { .attrs = ccwdev_attrs, }; -static inline int +static int device_add_files (struct device *dev) { return sysfs_create_group(&dev->kobj, &ccwdev_attr_group); } -static inline void +static void device_remove_files(struct device *dev) { sysfs_remove_group(&dev->kobj, &ccwdev_attr_group); diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 29db6341d632..b66338b76579 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -74,6 +74,7 @@ extern struct workqueue_struct *ccw_device_notify_work; extern wait_queue_head_t ccw_device_init_wq; extern atomic_t ccw_device_init_count; +void io_subchannel_irq (struct device *pdev); void io_subchannel_recog_done(struct ccw_device *cdev); int ccw_device_cancel_halt_clear(struct ccw_device *); @@ -118,6 +119,7 @@ int ccw_device_stlck(struct ccw_device *); /* qdio needs this. */ void ccw_device_set_timeout(struct ccw_device *, int); extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *); +extern struct bus_type ccw_bus_type; /* Channel measurement facility related */ void retry_set_schib(struct ccw_device *cdev); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index eed14572fc3b..51238e7555bb 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -206,7 +206,7 @@ ccw_device_handle_oper(struct ccw_device *cdev) * been varied online on the SE so we have to find out by magic (i. e. driving * the channel subsystem to device selection and updating our path masks). */ -static inline void +static void __recover_lost_chpids(struct subchannel *sch, int old_lpm) { int mask, i; @@ -387,7 +387,7 @@ ccw_device_done(struct ccw_device *cdev, int state) put_device (&cdev->dev); } -static inline int cmp_pgid(struct pgid *p1, struct pgid *p2) +static int cmp_pgid(struct pgid *p1, struct pgid *p2) { char *c1; char *c2; @@ -842,6 +842,8 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event) call_handler_unsol: if (cdev->handler) cdev->handler (cdev, 0, irb); + if (cdev->private->flags.doverify) + ccw_device_online_verify(cdev, 0); return; } /* Accumulate status and find out if a basic sense is needed. */ @@ -892,7 +894,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) /* * Got an interrupt for a basic sense. */ -void +static void ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) { struct irb *irb; diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index d269607336ec..d7b25b8f71d2 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -302,7 +302,7 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb) wake_up(&cdev->private->wait_q); } -static inline int +static int __ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, __u8 lpm) { int ret; diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index bdcf930f7beb..6b1caea622ea 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -25,7 +25,7 @@ * Check for any kind of channel or interface control check but don't * issue the message for the console device */ -static inline void +static void ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) { if (!(irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK | @@ -72,7 +72,7 @@ ccw_device_path_notoper(struct ccw_device *cdev) /* * Copy valid bits from the extended control word to device irb. */ -static inline void +static void ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb) { /* @@ -94,7 +94,7 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb) /* * Check if extended status word is valid. */ -static inline int +static int ccw_device_accumulate_esw_valid(struct irb *irb) { if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) @@ -109,7 +109,7 @@ ccw_device_accumulate_esw_valid(struct irb *irb) /* * Copy valid bits from the extended status word to device irb. */ -static inline void +static void ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) { struct irb *cdev_irb; diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 6fd1940842eb..d726cd5777de 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -66,7 +66,6 @@ MODULE_LICENSE("GPL"); /******************** HERE WE GO ***********************************/ static const char version[] = "QDIO base support version 2"; -extern struct bus_type ccw_bus_type; static int qdio_performance_stats = 0; static int proc_perf_file_registration; @@ -138,7 +137,7 @@ qdio_release_q(struct qdio_q *q) } /*check ccq */ -static inline int +static int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) { char dbf_text[15]; @@ -153,7 +152,7 @@ qdio_check_ccq(struct qdio_q *q, unsigned int ccq) return -EIO; } /* EQBS: extract buffer states */ -static inline int +static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, unsigned int *start, unsigned int *cnt) { @@ -188,7 +187,7 @@ again: } /* SQBS: set buffer states */ -static inline int +static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, unsigned int *start, unsigned int *cnt) { @@ -315,7 +314,7 @@ __do_siga_output(struct qdio_q *q, unsigned int *busy_bit) * returns QDIO_SIGA_ERROR_ACCESS_EXCEPTION as cc, when SIGA returns * an access exception */ -static inline int +static int qdio_siga_output(struct qdio_q *q) { int cc; @@ -349,7 +348,7 @@ qdio_siga_output(struct qdio_q *q) return cc; } -static inline int +static int qdio_siga_input(struct qdio_q *q) { int cc; @@ -421,7 +420,7 @@ tiqdio_sched_tl(void) tasklet_hi_schedule(&tiqdio_tasklet); } -static inline void +static void qdio_mark_tiq(struct qdio_q *q) { unsigned long flags; @@ -471,7 +470,7 @@ qdio_mark_q(struct qdio_q *q) tasklet_schedule(&q->tasklet); } -static inline int +static int qdio_stop_polling(struct qdio_q *q) { #ifdef QDIO_USE_PROCESSING_STATE @@ -525,7 +524,7 @@ qdio_stop_polling(struct qdio_q *q) * sophisticated locking outside of unmark_q, so that we don't need to * disable the interrupts :-) */ -static inline void +static void qdio_unmark_q(struct qdio_q *q) { unsigned long flags; @@ -691,7 +690,7 @@ qdio_qebsm_get_inbound_buffer_frontier(struct qdio_q *q) return q->first_to_check; } -static inline int +static int qdio_get_outbound_buffer_frontier(struct qdio_q *q) { struct qdio_irq *irq; @@ -774,7 +773,7 @@ out: } /* all buffers are processed */ -static inline int +static int qdio_is_outbound_q_done(struct qdio_q *q) { int no_used; @@ -796,7 +795,7 @@ qdio_is_outbound_q_done(struct qdio_q *q) return (no_used==0); } -static inline int +static int qdio_has_outbound_q_moved(struct qdio_q *q) { int i; @@ -816,7 +815,7 @@ qdio_has_outbound_q_moved(struct qdio_q *q) } } -static inline void +static void qdio_kick_outbound_q(struct qdio_q *q) { int result; @@ -905,7 +904,7 @@ qdio_kick_outbound_q(struct qdio_q *q) } } -static inline void +static void qdio_kick_outbound_handler(struct qdio_q *q) { int start, end, real_end, count; @@ -942,7 +941,7 @@ qdio_kick_outbound_handler(struct qdio_q *q) q->error_status_flags=0; } -static inline void +static void __qdio_outbound_processing(struct qdio_q *q) { int siga_attempts; @@ -1002,7 +1001,7 @@ qdio_outbound_processing(struct qdio_q *q) /************************* INBOUND ROUTINES *******************************/ -static inline int +static int qdio_get_inbound_buffer_frontier(struct qdio_q *q) { struct qdio_irq *irq; @@ -1133,7 +1132,7 @@ out: return q->first_to_check; } -static inline int +static int qdio_has_inbound_q_moved(struct qdio_q *q) { int i; @@ -1167,7 +1166,7 @@ qdio_has_inbound_q_moved(struct qdio_q *q) } /* means, no more buffers to be filled */ -static inline int +static int tiqdio_is_inbound_q_done(struct qdio_q *q) { int no_used; @@ -1228,7 +1227,7 @@ tiqdio_is_inbound_q_done(struct qdio_q *q) return 0; } -static inline int +static int qdio_is_inbound_q_done(struct qdio_q *q) { int no_used; @@ -1296,7 +1295,7 @@ qdio_is_inbound_q_done(struct qdio_q *q) } } -static inline void +static void qdio_kick_inbound_handler(struct qdio_q *q) { int count, start, end, real_end, i; @@ -1343,7 +1342,7 @@ qdio_kick_inbound_handler(struct qdio_q *q) } } -static inline void +static void __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set) { struct qdio_irq *irq_ptr; @@ -1442,7 +1441,7 @@ tiqdio_inbound_processing(struct qdio_q *q) __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount)); } -static inline void +static void __qdio_inbound_processing(struct qdio_q *q) { int q_laps=0; @@ -1493,7 +1492,7 @@ qdio_inbound_processing(struct qdio_q *q) /************************* MAIN ROUTINES *******************************/ #ifdef QDIO_USE_PROCESSING_STATE -static inline int +static int tiqdio_reset_processing_state(struct qdio_q *q, int q_laps) { if (!q) { @@ -1545,7 +1544,7 @@ tiqdio_reset_processing_state(struct qdio_q *q, int q_laps) } #endif /* QDIO_USE_PROCESSING_STATE */ -static inline void +static void tiqdio_inbound_checks(void) { struct qdio_q *q; @@ -1949,7 +1948,7 @@ qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state) mb(); } -static inline void +static void qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb) { char dbf_text[15]; @@ -1966,7 +1965,7 @@ qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb) } -static inline void +static void qdio_handle_pci(struct qdio_irq *irq_ptr) { int i; @@ -2002,7 +2001,7 @@ qdio_handle_pci(struct qdio_irq *irq_ptr) static void qdio_establish_handle_irq(struct ccw_device*, int, int); -static inline void +static void qdio_handle_activate_check(struct ccw_device *cdev, unsigned long intparm, int cstat, int dstat) { @@ -2229,7 +2228,7 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags, return cc; } -static inline void +static void qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, unsigned long token) { @@ -2740,7 +2739,7 @@ qdio_free(struct ccw_device *cdev) return 0; } -static inline void +static void qdio_allocate_do_dbf(struct qdio_initialize *init_data) { char dbf_text[20]; /* if a printf printed out more than 8 chars */ @@ -2773,7 +2772,7 @@ qdio_allocate_do_dbf(struct qdio_initialize *init_data) QDIO_DBF_HEX0(0,setup,&init_data->output_sbal_addr_array,sizeof(void*)); } -static inline void +static void qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt) { irq_ptr->input_qs[i]->is_iqdio_q = iqfmt; @@ -2792,7 +2791,7 @@ qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt) irq_ptr->qdr->qdf0[i].dkey=QDIO_STORAGE_KEY; } -static inline void +static void qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i, int j, int iqfmt) { @@ -2813,7 +2812,7 @@ qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i, } -static inline void +static void qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr) { int i; @@ -2839,7 +2838,7 @@ qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr) } } -static inline void +static void qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr) { int i; @@ -2865,7 +2864,7 @@ qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr) } } -static inline int +static int qdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat, int dstat) { @@ -3014,7 +3013,7 @@ qdio_allocate(struct qdio_initialize *init_data) return 0; } -int qdio_fill_irq(struct qdio_initialize *init_data) +static int qdio_fill_irq(struct qdio_initialize *init_data) { int i; char dbf_text[15]; @@ -3367,7 +3366,7 @@ qdio_activate(struct ccw_device *cdev, int flags) } /* buffers filled forwards again to make Rick happy */ -static inline void +static void qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx, unsigned int count, struct qdio_buffer *buffers) { @@ -3386,7 +3385,7 @@ qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx, } } -static inline void +static void qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx, unsigned int count, struct qdio_buffer *buffers) { @@ -3407,7 +3406,7 @@ qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx, } } -static inline void +static void do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags, unsigned int qidx, unsigned int count, struct qdio_buffer *buffers) @@ -3443,7 +3442,7 @@ do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags, qdio_mark_q(q); } -static inline void +static void do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags, unsigned int qidx, unsigned int count, struct qdio_buffer *buffers) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 81b5899f4010..c7d1355237b6 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -465,7 +465,7 @@ static int ap_device_probe(struct device *dev) * Flush all requests from the request/pending queue of an AP device. * @ap_dev: pointer to the AP device. */ -static inline void __ap_flush_queue(struct ap_device *ap_dev) +static void __ap_flush_queue(struct ap_device *ap_dev) { struct ap_message *ap_msg, *next; @@ -587,7 +587,7 @@ static struct bus_attribute *const ap_bus_attrs[] = { /** * Pick one of the 16 ap domains. */ -static inline int ap_select_domain(void) +static int ap_select_domain(void) { int queue_depth, device_type, count, max_count, best_domain; int rc, i, j; @@ -825,7 +825,7 @@ static inline void ap_schedule_poll_timer(void) * required, bit 2^1 is set if the poll timer needs to get armed * Returns 0 if the device is still present, -ENODEV if not. */ -static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags) +static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags) { struct ap_queue_status status; struct ap_message *ap_msg; @@ -872,7 +872,7 @@ static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags) * required, bit 2^1 is set if the poll timer needs to get armed * Returns 0 if the device is still present, -ENODEV if not. */ -static inline int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags) +static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags) { struct ap_queue_status status; struct ap_message *ap_msg; diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 1edc10a7a6f2..b9e59bc9435a 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -791,7 +791,7 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd, return rc; } -long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, +static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { if (cmd == ICARSAMODEXPO) @@ -833,8 +833,8 @@ static struct miscdevice zcrypt_misc_device = { */ static struct proc_dir_entry *zcrypt_entry; -static inline int sprintcl(unsigned char *outaddr, unsigned char *addr, - unsigned int len) +static int sprintcl(unsigned char *outaddr, unsigned char *addr, + unsigned int len) { int hl, i; @@ -845,8 +845,8 @@ static inline int sprintcl(unsigned char *outaddr, unsigned char *addr, return hl; } -static inline int sprintrw(unsigned char *outaddr, unsigned char *addr, - unsigned int len) +static int sprintrw(unsigned char *outaddr, unsigned char *addr, + unsigned int len) { int hl, inl, c, cx; @@ -865,8 +865,8 @@ static inline int sprintrw(unsigned char *outaddr, unsigned char *addr, return hl; } -static inline int sprinthx(unsigned char *title, unsigned char *outaddr, - unsigned char *addr, unsigned int len) +static int sprinthx(unsigned char *title, unsigned char *outaddr, + unsigned char *addr, unsigned int len) { int hl, inl, r, rx; @@ -885,8 +885,8 @@ static inline int sprinthx(unsigned char *title, unsigned char *outaddr, return hl; } -static inline int sprinthx4(unsigned char *title, unsigned char *outaddr, - unsigned int *array, unsigned int len) +static int sprinthx4(unsigned char *title, unsigned char *outaddr, + unsigned int *array, unsigned int len) { int hl, r; @@ -943,7 +943,7 @@ static int zcrypt_status_read(char *resp_buff, char **start, off_t offset, zcrypt_qdepth_mask(workarea); len += sprinthx("Waiting work element counts", resp_buff+len, workarea, AP_DEVICES); - zcrypt_perdev_reqcnt((unsigned int *) workarea); + zcrypt_perdev_reqcnt((int *) workarea); len += sprinthx4("Per-device successfully completed request counts", resp_buff+len,(unsigned int *) workarea, AP_DEVICES); *eof = 1; diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c index 32e37014345c..818ffe05ac00 100644 --- a/drivers/s390/crypto/zcrypt_pcica.c +++ b/drivers/s390/crypto/zcrypt_pcica.c @@ -191,10 +191,10 @@ static int ICACRT_msg_to_type4CRT_msg(struct zcrypt_device *zdev, * * Returns 0 on success or -EFAULT. */ -static inline int convert_type84(struct zcrypt_device *zdev, - struct ap_message *reply, - char __user *outputdata, - unsigned int outputdatalength) +static int convert_type84(struct zcrypt_device *zdev, + struct ap_message *reply, + char __user *outputdata, + unsigned int outputdatalength) { struct type84_hdr *t84h = reply->message; char *data; diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index b7153c1e15cd..252443b6bd1b 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -709,7 +709,8 @@ out_free: * PCIXCC/CEX2C device to the request distributor * @xcRB: pointer to the send_cprb request buffer */ -long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB) +static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, + struct ica_xcRB *xcRB) { struct ap_message ap_msg; struct response_type resp_type = { diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 95f4e105cb96..7809a79feec7 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -121,7 +121,7 @@ MODULE_LICENSE("GPL"); #define DEBUG #endif - char debug_buffer[255]; +static char debug_buffer[255]; /** * Debug Facility Stuff */ @@ -223,16 +223,14 @@ static void claw_timer ( struct chbk * p_ch ); /* Functions */ static int add_claw_reads(struct net_device *dev, struct ccwbk* p_first, struct ccwbk* p_last); -static void inline ccw_check_return_code (struct ccw_device *cdev, - int return_code); -static void inline ccw_check_unit_check (struct chbk * p_ch, - unsigned char sense ); +static void ccw_check_return_code (struct ccw_device *cdev, int return_code); +static void ccw_check_unit_check (struct chbk * p_ch, unsigned char sense ); static int find_link(struct net_device *dev, char *host_name, char *ws_name ); static int claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid); static int init_ccw_bk(struct net_device *dev); static void probe_error( struct ccwgroup_device *cgdev); static struct net_device_stats *claw_stats(struct net_device *dev); -static int inline pages_to_order_of_mag(int num_of_pages); +static int pages_to_order_of_mag(int num_of_pages); static struct sk_buff *claw_pack_skb(struct claw_privbk *privptr); #ifdef DEBUG static void dumpit (char *buf, int len); @@ -1310,7 +1308,7 @@ claw_timer ( struct chbk * p_ch ) * of magnitude get_free_pages() has an upper order of 9 * *--------------------------------------------------------------------*/ -static int inline +static int pages_to_order_of_mag(int num_of_pages) { int order_of_mag=1; /* assume 2 pages */ @@ -1482,7 +1480,7 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first, * * *-------------------------------------------------------------------*/ -static void inline +static void ccw_check_return_code(struct ccw_device *cdev, int return_code) { #ifdef FUNCTRACE @@ -1529,7 +1527,7 @@ ccw_check_return_code(struct ccw_device *cdev, int return_code) * ccw_check_unit_check * *--------------------------------------------------------------------*/ -static void inline +static void ccw_check_unit_check(struct chbk * p_ch, unsigned char sense ) { struct net_device *dev = p_ch->ndev; diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c index 03cc263fe0da..5a84fbbc6611 100644 --- a/drivers/s390/net/ctcmain.c +++ b/drivers/s390/net/ctcmain.c @@ -369,7 +369,7 @@ ctc_dump_skb(struct sk_buff *skb, int offset) * @param ch The channel where this skb has been received. * @param pskb The received skb. */ -static __inline__ void +static void ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb) { struct net_device *dev = ch->netdev; @@ -512,7 +512,7 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb) * @param ch The channel, the error belongs to. * @param return_code The error code to inspect. */ -static void inline +static void ccw_check_return_code(struct channel *ch, int return_code, char *msg) { DBF_TEXT(trace, 5, __FUNCTION__); @@ -547,7 +547,7 @@ ccw_check_return_code(struct channel *ch, int return_code, char *msg) * @param ch The channel, the sense code belongs to. * @param sense The sense code to inspect. */ -static void inline +static void ccw_unit_check(struct channel *ch, unsigned char sense) { DBF_TEXT(trace, 5, __FUNCTION__); @@ -603,7 +603,7 @@ ctc_purge_skb_queue(struct sk_buff_head *q) } } -static __inline__ int +static int ctc_checkalloc_buffer(struct channel *ch, int warn) { DBF_TEXT(trace, 5, __FUNCTION__); diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c index e965f03a7291..76728ae4b843 100644 --- a/drivers/s390/net/cu3088.c +++ b/drivers/s390/net/cu3088.c @@ -57,7 +57,7 @@ static struct ccw_device_id cu3088_ids[] = { static struct ccw_driver cu3088_driver; -struct device *cu3088_root_dev; +static struct device *cu3088_root_dev; static ssize_t group_write(struct device_driver *drv, const char *buf, size_t count) diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index e5665b6743a1..b97dd15bdb9a 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -828,7 +828,7 @@ lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd) /** * Emit buffer of a lan comand. */ -void +static void lcs_lancmd_timeout(unsigned long data) { struct lcs_reply *reply, *list_reply, *r; @@ -1360,7 +1360,7 @@ lcs_get_problem(struct ccw_device *cdev, struct irb *irb) return 0; } -void +static void lcs_schedule_recovery(struct lcs_card *card) { LCS_DBF_TEXT(2, trace, "startrec"); @@ -1990,7 +1990,7 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char } -DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store); +static DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store); static ssize_t lcs_dev_recover_store(struct device *dev, struct device_attribute *attr, diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index d7d1cc0a5c8e..3346088f47e0 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -2053,7 +2053,7 @@ out_free_ndev: return ret; } -DRIVER_ATTR(connection, 0200, NULL, conn_write); +static DRIVER_ATTR(connection, 0200, NULL, conn_write); static ssize_t remove_write (struct device_driver *drv, const char *buf, size_t count) @@ -2112,7 +2112,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) return -EINVAL; } -DRIVER_ATTR(remove, 0200, NULL, remove_write); +static DRIVER_ATTR(remove, 0200, NULL, remove_write); static void netiucv_banner(void) diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c index 6bb558a9a032..7c735e1fe063 100644 --- a/drivers/s390/net/qeth_eddp.c +++ b/drivers/s390/net/qeth_eddp.c @@ -49,7 +49,7 @@ qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *queue, return buffers_needed; } -static inline void +static void qeth_eddp_free_context(struct qeth_eddp_context *ctx) { int i; @@ -91,7 +91,7 @@ qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf) } } -static inline int +static int qeth_eddp_buf_ref_context(struct qeth_qdio_out_buffer *buf, struct qeth_eddp_context *ctx) { @@ -196,7 +196,7 @@ out: return flush_cnt; } -static inline void +static void qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx, struct qeth_eddp_data *eddp, int data_len) { @@ -256,7 +256,7 @@ qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx, ctx->offset += eddp->thl; } -static inline void +static void qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len, __wsum *hcsum) { @@ -302,7 +302,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len, } } -static inline void +static void qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx, struct qeth_eddp_data *eddp, int data_len, __wsum hcsum) @@ -349,7 +349,7 @@ qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx, ((struct tcphdr *)eddp->th_in_ctx)->check = csum_fold(hcsum); } -static inline __wsum +static __wsum qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len) { __wsum phcsum; /* pseudo header checksum */ @@ -363,7 +363,7 @@ qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len) return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum); } -static inline __wsum +static __wsum qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len) { __be32 proto; @@ -381,7 +381,7 @@ qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len) return phcsum; } -static inline struct qeth_eddp_data * +static struct qeth_eddp_data * qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl) { struct qeth_eddp_data *eddp; @@ -399,7 +399,7 @@ qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl) return eddp; } -static inline void +static void __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, struct qeth_eddp_data *eddp) { @@ -464,7 +464,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, } } -static inline int +static int qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, struct sk_buff *skb, struct qeth_hdr *qhdr) { @@ -505,7 +505,7 @@ qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, return 0; } -static inline void +static void qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb, int hdr_len) { @@ -529,7 +529,7 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb, (skb_shinfo(skb)->gso_segs + 1); } -static inline struct qeth_eddp_context * +static struct qeth_eddp_context * qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb, int hdr_len) { @@ -581,7 +581,7 @@ qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb, return ctx; } -static inline struct qeth_eddp_context * +static struct qeth_eddp_context * qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *qhdr) { @@ -625,5 +625,3 @@ qeth_eddp_create_context(struct qeth_card *card, struct sk_buff *skb, } return NULL; } - - diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index d2efa5ff125d..2257e45594b3 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -651,7 +651,7 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo, return 0; } -static inline int +static int __qeth_address_exists_in_list(struct list_head *list, struct qeth_ipaddr *addr, int same_type) { @@ -795,7 +795,7 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr) return rc; } -static inline void +static void __qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags) { struct qeth_ipaddr *addr, *tmp; @@ -882,7 +882,7 @@ static void qeth_layer2_add_multicast(struct qeth_card *); static void qeth_add_multicast_ipv6(struct qeth_card *); #endif -static inline int +static int qeth_set_thread_start_bit(struct qeth_card *card, unsigned long thread) { unsigned long flags; @@ -920,7 +920,7 @@ qeth_clear_thread_running_bit(struct qeth_card *card, unsigned long thread) wake_up(&card->wait_q); } -static inline int +static int __qeth_do_run_thread(struct qeth_card *card, unsigned long thread) { unsigned long flags; @@ -1764,9 +1764,9 @@ out: qeth_release_buffer(channel,iob); } -static inline void +static void qeth_prepare_control_data(struct qeth_card *card, int len, -struct qeth_cmd_buffer *iob) + struct qeth_cmd_buffer *iob) { qeth_setup_ccw(&card->write,iob->data,len); iob->callback = qeth_release_buffer; @@ -2160,7 +2160,7 @@ qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error, return 0; } -static inline struct sk_buff * +static struct sk_buff * qeth_get_skb(unsigned int length, struct qeth_hdr *hdr) { struct sk_buff* skb; @@ -2179,7 +2179,7 @@ qeth_get_skb(unsigned int length, struct qeth_hdr *hdr) return skb; } -static inline struct sk_buff * +static struct sk_buff * qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, struct qdio_buffer_element **__element, int *__offset, struct qeth_hdr **hdr) @@ -2264,7 +2264,7 @@ no_mem: return NULL; } -static inline __be16 +static __be16 qeth_type_trans(struct sk_buff *skb, struct net_device *dev) { struct qeth_card *card; @@ -2297,7 +2297,7 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev) return htons(ETH_P_802_2); } -static inline void +static void qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) { @@ -2351,7 +2351,7 @@ qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb, fake_llc->ethertype = ETH_P_IP; } -static inline void +static void qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) { @@ -2420,7 +2420,7 @@ qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, *((__u32 *)skb->cb) = ++card->seqno.pkt_seqno; } -static inline __u16 +static __u16 qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) { @@ -2476,7 +2476,7 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, return vlan_id; } -static inline void +static void qeth_process_inbound_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf, int index) { @@ -2528,7 +2528,7 @@ qeth_process_inbound_buffer(struct qeth_card *card, } } -static inline struct qeth_buffer_pool_entry * +static struct qeth_buffer_pool_entry * qeth_get_buffer_pool_entry(struct qeth_card *card) { struct qeth_buffer_pool_entry *entry; @@ -2543,7 +2543,7 @@ qeth_get_buffer_pool_entry(struct qeth_card *card) return NULL; } -static inline void +static void qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) { struct qeth_buffer_pool_entry *pool_entry; @@ -2570,7 +2570,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) buf->state = QETH_QDIO_BUF_EMPTY; } -static inline void +static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf) { @@ -2595,7 +2595,7 @@ qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); } -static inline void +static void qeth_queue_input_buffer(struct qeth_card *card, int index) { struct qeth_qdio_q *queue = card->qdio.in_q; @@ -2699,7 +2699,7 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status, card->perf_stats.inbound_start_time; } -static inline int +static int qeth_handle_send_error(struct qeth_card *card, struct qeth_qdio_out_buffer *buffer, unsigned int qdio_err, unsigned int siga_err) @@ -2821,7 +2821,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, * Switched to packing state if the number of used buffers on a queue * reaches a certain limit. */ -static inline void +static void qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue) { if (!queue->do_pack) { @@ -2842,7 +2842,7 @@ qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue) * In that case 1 is returned to inform the caller. If no buffer * has to be flushed, zero is returned. */ -static inline int +static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue) { struct qeth_qdio_out_buffer *buffer; @@ -2877,7 +2877,7 @@ qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue) * Checks if there is a packing buffer and prepares it to be flushed. * In that case returns 1, otherwise zero. */ -static inline int +static int qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue) { struct qeth_qdio_out_buffer *buffer; @@ -2894,7 +2894,7 @@ qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue) return 0; } -static inline void +static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) { int index; @@ -3594,7 +3594,7 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev, } } -static inline int +static int qeth_send_packet(struct qeth_card *, struct sk_buff *); static int @@ -3759,7 +3759,7 @@ qeth_stop(struct net_device *dev) return 0; } -static inline int +static int qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) { int cast_type = RTN_UNSPEC; @@ -3806,7 +3806,7 @@ qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) return cast_type; } -static inline int +static int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb, int ipv, int cast_type) { @@ -3853,7 +3853,7 @@ qeth_get_ip_version(struct sk_buff *skb) } } -static inline struct qeth_hdr * +static struct qeth_hdr * __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv) { #ifdef CONFIG_QETH_VLAN @@ -3882,14 +3882,14 @@ __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv) qeth_push_skb(card, skb, sizeof(struct qeth_hdr))); } -static inline void +static void __qeth_free_new_skb(struct sk_buff *orig_skb, struct sk_buff *new_skb) { if (orig_skb != new_skb) dev_kfree_skb_any(new_skb); } -static inline struct sk_buff * +static struct sk_buff * qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr **hdr, int ipv) { @@ -3940,7 +3940,7 @@ qeth_get_qeth_hdr_flags6(int cast_type) return ct | QETH_CAST_UNICAST; } -static inline void +static void qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb) { @@ -3977,7 +3977,7 @@ qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr, } } -static inline void +static void qeth_layer2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb, int cast_type) { @@ -4068,7 +4068,7 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, } } -static inline void +static void __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill) { @@ -4112,7 +4112,7 @@ __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer, *next_element_to_fill = element; } -static inline int +static int qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf, struct sk_buff *skb) @@ -4171,7 +4171,7 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue, return flush_cnt; } -static inline int +static int qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_hdr *hdr, int elements_needed, @@ -4222,7 +4222,7 @@ out: return -EBUSY; } -static inline int +static int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_hdr *hdr, int elements_needed, struct qeth_eddp_context *ctx) @@ -4328,7 +4328,7 @@ out: return rc; } -static inline int +static int qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb, int elems) { @@ -4349,7 +4349,7 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr, } -static inline int +static int qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) { int ipv = 0; @@ -4536,7 +4536,7 @@ qeth_mdio_read(struct net_device *dev, int phy_id, int regnum) } -static inline const char * +static const char * qeth_arp_get_error_cause(int *rc) { switch (*rc) { @@ -4597,7 +4597,7 @@ qeth_arp_set_no_entries(struct qeth_card *card, int no_entries) return rc; } -static inline void +static void qeth_copy_arp_entries_stripped(struct qeth_arp_query_info *qinfo, struct qeth_arp_query_data *qdata, int entry_size, int uentry_size) @@ -5214,7 +5214,7 @@ qeth_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) spin_unlock_irqrestore(&card->vlanlock, flags); } -static inline void +static void qeth_free_vlan_buffer(struct qeth_card *card, struct qeth_qdio_out_buffer *buf, unsigned short vid) { @@ -5625,7 +5625,7 @@ qeth_delete_mc_addresses(struct qeth_card *card) spin_unlock_irqrestore(&card->ip_lock, flags); } -static inline void +static void qeth_add_mc(struct qeth_card *card, struct in_device *in4_dev) { struct qeth_ipaddr *ipm; @@ -5711,7 +5711,7 @@ qeth_layer2_add_multicast(struct qeth_card *card) } #ifdef CONFIG_QETH_IPV6 -static inline void +static void qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev) { struct qeth_ipaddr *ipm; @@ -6022,7 +6022,7 @@ qeth_send_setdelmc(struct qeth_card *card, struct qeth_ipaddr *addr, int ipacmd) return rc; } -static inline void +static void qeth_fill_netmask(u8 *netmask, unsigned int len) { int i,j; @@ -6626,7 +6626,7 @@ qeth_send_setadp_mode(struct qeth_card *card, __u32 command, __u32 mode) return rc; } -static inline int +static int qeth_setadapter_hstr(struct qeth_card *card) { int rc; @@ -6889,7 +6889,7 @@ qeth_send_simple_setassparms(struct qeth_card *card, return rc; } -static inline int +static int qeth_start_ipa_arp_processing(struct qeth_card *card) { int rc; @@ -7529,7 +7529,7 @@ qeth_set_allowed_threads(struct qeth_card *card, unsigned long threads, wake_up(&card->wait_q); } -static inline int +static int qeth_threads_running(struct qeth_card *card, unsigned long threads) { unsigned long flags; @@ -8118,7 +8118,7 @@ qeth_del_ipato_entry(struct qeth_card *card, enum qeth_prot_versions proto, spin_unlock_irqrestore(&card->ip_lock, flags); } -static inline void +static void qeth_convert_addr_to_bits(u8 *addr, u8 *bits, int len) { int i, j; diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index 5836737ac58f..d518419cd0c6 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c @@ -328,7 +328,7 @@ qeth_dev_bufcnt_store(struct device *dev, struct device_attribute *attr, const c static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show, qeth_dev_bufcnt_store); -static inline ssize_t +static ssize_t qeth_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route, char *buf) { @@ -368,7 +368,7 @@ qeth_dev_route4_show(struct device *dev, struct device_attribute *attr, char *bu return qeth_dev_route_show(card, &card->options.route4, buf); } -static inline ssize_t +static ssize_t qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route, enum qeth_prot_versions prot, const char *buf, size_t count) { @@ -998,7 +998,7 @@ struct device_attribute dev_attr_##_id = { \ .store = _store, \ }; -int +static int qeth_check_layer2(struct qeth_card *card) { if (card->options.layer2) @@ -1100,7 +1100,7 @@ static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644, qeth_dev_ipato_invert4_show, qeth_dev_ipato_invert4_store); -static inline ssize_t +static ssize_t qeth_dev_ipato_add_show(char *buf, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1146,7 +1146,7 @@ qeth_dev_ipato_add4_show(struct device *dev, struct device_attribute *attr, char return qeth_dev_ipato_add_show(buf, card, QETH_PROT_IPV4); } -static inline int +static int qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto, u8 *addr, int *mask_bits) { @@ -1178,7 +1178,7 @@ qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto, return 0; } -static inline ssize_t +static ssize_t qeth_dev_ipato_add_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1223,7 +1223,7 @@ static QETH_DEVICE_ATTR(ipato_add4, add4, 0644, qeth_dev_ipato_add4_show, qeth_dev_ipato_add4_store); -static inline ssize_t +static ssize_t qeth_dev_ipato_del_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1361,7 +1361,7 @@ static struct attribute_group qeth_device_ipato_group = { .attrs = (struct attribute **)qeth_ipato_device_attrs, }; -static inline ssize_t +static ssize_t qeth_dev_vipa_add_show(char *buf, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1407,7 +1407,7 @@ qeth_dev_vipa_add4_show(struct device *dev, struct device_attribute *attr, char return qeth_dev_vipa_add_show(buf, card, QETH_PROT_IPV4); } -static inline int +static int qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto, u8 *addr) { @@ -1418,7 +1418,7 @@ qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto, return 0; } -static inline ssize_t +static ssize_t qeth_dev_vipa_add_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1451,7 +1451,7 @@ static QETH_DEVICE_ATTR(vipa_add4, add4, 0644, qeth_dev_vipa_add4_show, qeth_dev_vipa_add4_store); -static inline ssize_t +static ssize_t qeth_dev_vipa_del_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1542,7 +1542,7 @@ static struct attribute_group qeth_device_vipa_group = { .attrs = (struct attribute **)qeth_vipa_device_attrs, }; -static inline ssize_t +static ssize_t qeth_dev_rxip_add_show(char *buf, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1588,7 +1588,7 @@ qeth_dev_rxip_add4_show(struct device *dev, struct device_attribute *attr, char return qeth_dev_rxip_add_show(buf, card, QETH_PROT_IPV4); } -static inline int +static int qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto, u8 *addr) { @@ -1599,7 +1599,7 @@ qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto, return 0; } -static inline ssize_t +static ssize_t qeth_dev_rxip_add_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1632,7 +1632,7 @@ static QETH_DEVICE_ATTR(rxip_add4, add4, 0644, qeth_dev_rxip_add4_show, qeth_dev_rxip_add4_store); -static inline ssize_t +static ssize_t qeth_dev_rxip_del_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index e088b5e28711..806bb1a921eb 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -13,22 +13,18 @@ #include #include #include +#include #include - +#include #include - +#include +#include "cio/cio.h" +#include "cio/chsc.h" +#include "cio/css.h" #include "s390mach.h" static struct semaphore m_sem; -extern int css_process_crw(int, int); -extern int chsc_process_crw(void); -extern int chp_process_crw(int, int); -extern void css_reiterate_subchannels(void); - -extern struct workqueue_struct *slow_path_wq; -extern struct work_struct slow_path_work; - static NORET_TYPE void s390_handle_damage(char *msg) { @@ -470,6 +466,19 @@ s390_do_machine_check(struct pt_regs *regs) s390_handle_damage("unable to revalidate registers."); } + if (mci->cd) { + /* Timing facility damage */ + s390_handle_damage("TOD clock damaged"); + } + + if (mci->ed && mci->ec) { + /* External damage */ + if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC)) + etr_sync_check(); + if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH)) + etr_switch_to_local(); + } + if (mci->se) /* Storage error uncorrected */ s390_handle_damage("received storage error uncorrected " @@ -508,7 +517,7 @@ static int machine_check_init(void) { init_MUTEX_LOCKED(&m_sem); - ctl_clear_bit(14, 25); /* disable external damage MCH */ + ctl_set_bit(14, 25); /* enable external damage MCH */ ctl_set_bit(14, 27); /* enable system recovery MCH */ #ifdef CONFIG_MACHCHK_WARNING ctl_set_bit(14, 24); /* enable warning MCH */ @@ -529,7 +538,11 @@ arch_initcall(machine_check_init); static int __init machine_check_crw_init (void) { - kthread_run(s390_collect_crw_info, &m_sem, "kmcheck"); + struct task_struct *task; + + task = kthread_run(s390_collect_crw_info, &m_sem, "kmcheck"); + if (IS_ERR(task)) + return PTR_ERR(task); ctl_set_bit(14, 28); /* enable channel report MCH */ return 0; } diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h index 7abb42a09ae2..d3ca4281a494 100644 --- a/drivers/s390/s390mach.h +++ b/drivers/s390/s390mach.h @@ -102,4 +102,7 @@ static inline int stcrw(struct crw *pcrw ) return ccode; } +#define ED_ETR_SYNC 12 /* External damage ETR sync check */ +#define ED_ETR_SWITCH 13 /* External damage ETR switch to local */ + #endif /* __s390mach */ diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 85093b71f9fa..39a885266790 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -47,13 +47,12 @@ static int __init zfcp_module_init(void); static void zfcp_ns_gid_pn_handler(unsigned long); /* miscellaneous */ -static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); -static inline void zfcp_sg_list_free(struct zfcp_sg_list *); -static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, - void __user *, size_t); -static inline int zfcp_sg_list_copy_to_user(void __user *, - struct zfcp_sg_list *, size_t); - +static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); +static void zfcp_sg_list_free(struct zfcp_sg_list *); +static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, + void __user *, size_t); +static int zfcp_sg_list_copy_to_user(void __user *, + struct zfcp_sg_list *, size_t); static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long); #define ZFCP_CFDC_IOC_MAGIC 0xDD @@ -605,7 +604,7 @@ zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, * elements of the scatter-gather list. The maximum size of a single element * in the scatter-gather list is PAGE_SIZE. */ -static inline int +static int zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) { struct scatterlist *sg; @@ -652,7 +651,7 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) * Memory for each element in the scatter-gather list is freed. * Finally sg_list->sg is freed itself and sg_list->count is reset. */ -static inline void +static void zfcp_sg_list_free(struct zfcp_sg_list *sg_list) { struct scatterlist *sg; @@ -697,7 +696,7 @@ zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count) * @size: number of bytes to be copied * Return: 0 on success, -EFAULT if copy_from_user fails. */ -static inline int +static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, void __user *user_buffer, size_t size) @@ -735,7 +734,7 @@ zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, * @size: number of bytes to be copied * Return: 0 on success, -EFAULT if copy_to_user fails */ -static inline int +static int zfcp_sg_list_copy_to_user(void __user *user_buffer, struct zfcp_sg_list *sg_list, size_t size) @@ -1799,7 +1798,7 @@ static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = { * @code: reason code * @rc_table: table of reason codes and descriptions */ -static inline const char * +static const char * zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table) { const char *descr = "unknown reason code"; @@ -1847,7 +1846,7 @@ zfcp_check_ct_response(struct ct_hdr *rjt) * @rjt_par: reject parameter acc. to FC-PH/FC-FS * @rc_table: table of reason codes and descriptions */ -static inline void +static void zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par, const struct zfcp_rc_entry *rc_table) { diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 0aa3b1ac76af..d8191d115c14 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -31,7 +31,7 @@ MODULE_PARM_DESC(dbfsize, #define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER -static inline int +static int zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck) { unsigned long long sec; @@ -106,7 +106,7 @@ zfcp_dbf_view_dump(char *out_buf, const char *label, return len; } -static inline int +static int zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area, debug_entry_t * entry, char *out_buf) { @@ -130,7 +130,7 @@ zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area, return len; } -inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) +void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) { struct zfcp_adapter *adapter = fsf_req->adapter; struct fsf_qtcb *qtcb = fsf_req->qtcb; @@ -241,7 +241,7 @@ inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); } -inline void +void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, struct fsf_status_read_buffer *status_buffer) { @@ -295,7 +295,7 @@ zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); } -inline void +void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status, unsigned int qdio_error, unsigned int siga_error, int sbal_index, int sbal_count) @@ -316,7 +316,7 @@ zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status, spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); } -static inline int +static int zfcp_hba_dbf_view_response(char *out_buf, struct zfcp_hba_dbf_record_response *rec) { @@ -403,7 +403,7 @@ zfcp_hba_dbf_view_response(char *out_buf, return len; } -static inline int +static int zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec) { int len = 0; @@ -424,7 +424,7 @@ zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec) return len; } -static inline int +static int zfcp_hba_dbf_view_qdio(char *out_buf, struct zfcp_hba_dbf_record_qdio *rec) { int len = 0; @@ -469,7 +469,7 @@ zfcp_hba_dbf_view_format(debug_info_t * id, struct debug_view *view, return len; } -struct debug_view zfcp_hba_dbf_view = { +static struct debug_view zfcp_hba_dbf_view = { "structured", NULL, &zfcp_dbf_view_header, @@ -478,7 +478,7 @@ struct debug_view zfcp_hba_dbf_view = { NULL }; -inline void +void _zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req, u32 s_id, u32 d_id, void *buffer, int buflen) { @@ -519,7 +519,7 @@ _zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req, spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); } -inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; struct zfcp_port *port = ct->port; @@ -531,7 +531,7 @@ inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) ct->req->length); } -inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; struct zfcp_port *port = ct->port; @@ -543,7 +543,7 @@ inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) ct->resp->length); } -static inline void +static void _zfcp_san_dbf_event_common_els(const char *tag, int level, struct zfcp_fsf_req *fsf_req, u32 s_id, u32 d_id, u8 ls_code, void *buffer, int buflen) @@ -585,7 +585,7 @@ _zfcp_san_dbf_event_common_els(const char *tag, int level, spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); } -inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data; @@ -597,7 +597,7 @@ inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req) els->req->length); } -inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data; @@ -608,7 +608,7 @@ inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req) els->resp->length); } -inline void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req) { struct zfcp_adapter *adapter = fsf_req->adapter; struct fsf_status_read_buffer *status_buffer = @@ -693,7 +693,7 @@ zfcp_san_dbf_view_format(debug_info_t * id, struct debug_view *view, return len; } -struct debug_view zfcp_san_dbf_view = { +static struct debug_view zfcp_san_dbf_view = { "structured", NULL, &zfcp_dbf_view_header, @@ -702,7 +702,7 @@ struct debug_view zfcp_san_dbf_view = { NULL }; -static inline void +static void _zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level, struct zfcp_adapter *adapter, struct scsi_cmnd *scsi_cmnd, @@ -786,7 +786,7 @@ _zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level, spin_unlock_irqrestore(&adapter->scsi_dbf_lock, flags); } -inline void +void zfcp_scsi_dbf_event_result(const char *tag, int level, struct zfcp_adapter *adapter, struct scsi_cmnd *scsi_cmnd, @@ -796,7 +796,7 @@ zfcp_scsi_dbf_event_result(const char *tag, int level, adapter, scsi_cmnd, fsf_req, 0); } -inline void +void zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter, struct scsi_cmnd *scsi_cmnd, struct zfcp_fsf_req *new_fsf_req, @@ -806,7 +806,7 @@ zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter, adapter, scsi_cmnd, new_fsf_req, old_req_id); } -inline void +void zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, struct zfcp_unit *unit, struct scsi_cmnd *scsi_cmnd) { @@ -884,7 +884,7 @@ zfcp_scsi_dbf_view_format(debug_info_t * id, struct debug_view *view, return len; } -struct debug_view zfcp_scsi_dbf_view = { +static struct debug_view zfcp_scsi_dbf_view = { "structured", NULL, &zfcp_dbf_view_header, diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index c88babce9bca..88642dec080c 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -200,7 +200,7 @@ void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout) * returns: 0 - initiated action successfully * <0 - failed to initiate action */ -int +static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask) { int retval; @@ -295,7 +295,7 @@ zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask) * zfcp_erp_adisc - send ADISC ELS command * @port: port structure */ -int +static int zfcp_erp_adisc(struct zfcp_port *port) { struct zfcp_adapter *adapter = port->adapter; @@ -380,7 +380,7 @@ zfcp_erp_adisc(struct zfcp_port *port) * * If ADISC failed (LS_RJT or timed out) forced reopen of the port is triggered. */ -void +static void zfcp_erp_adisc_handler(unsigned long data) { struct zfcp_send_els *send_els; @@ -3141,7 +3141,6 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: if (result != ZFCP_ERP_SUCCEEDED) { - struct zfcp_port *port; list_for_each_entry(port, &adapter->port_list_head, list) if (port->rport && !atomic_test_mask(ZFCP_STATUS_PORT_WKA, diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index b8794d77285d..cda0cc095ad1 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -119,8 +119,8 @@ extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *); -extern void set_host_byte(u32 *, char); -extern void set_driver_byte(u32 *, char); +extern void set_host_byte(int *, char); +extern void set_driver_byte(int *, char); extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 067f1519eb04..4b3ae3f22e78 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -4563,7 +4563,7 @@ zfcp_fsf_req_sbal_check(unsigned long *flags, /* * set qtcb pointer in fsf_req and initialize QTCB */ -static inline void +static void zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req) { if (likely(fsf_req->qtcb != NULL)) { diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index dbd9f48e863e..1e12a78e8edd 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -21,22 +21,22 @@ #include "zfcp_ext.h" -static inline void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int); +static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int); static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get (struct zfcp_qdio_queue *, int, int); static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp (struct zfcp_fsf_req *, int, int); -static inline volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain +static volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain (struct zfcp_fsf_req *, unsigned long); -static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_next +static volatile struct qdio_buffer_element *zfcp_qdio_sbale_next (struct zfcp_fsf_req *, unsigned long); -static inline int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int); +static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int); static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *); -static inline void zfcp_qdio_sbale_fill +static void zfcp_qdio_sbale_fill (struct zfcp_fsf_req *, unsigned long, void *, int); -static inline int zfcp_qdio_sbals_from_segment +static int zfcp_qdio_sbals_from_segment (struct zfcp_fsf_req *, unsigned long, void *, unsigned long); -static inline int zfcp_qdio_sbals_from_buffer +static int zfcp_qdio_sbals_from_buffer (struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int); static qdio_handler_t zfcp_qdio_request_handler; @@ -201,7 +201,7 @@ zfcp_qdio_allocate(struct zfcp_adapter *adapter) * returns: error flag * */ -static inline int +static int zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status, unsigned int qdio_error, unsigned int siga_error, int first_element, int elements_processed) @@ -462,7 +462,7 @@ zfcp_qdio_sbale_get(struct zfcp_qdio_queue *queue, int sbal, int sbale) * zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for * a struct zfcp_fsf_req */ -inline volatile struct qdio_buffer_element * +volatile struct qdio_buffer_element * zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale) { return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue, @@ -484,7 +484,7 @@ zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale) * zfcp_qdio_sbale_curr - return current SBALE on request_queue for * a struct zfcp_fsf_req */ -inline volatile struct qdio_buffer_element * +volatile struct qdio_buffer_element * zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req) { return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, @@ -499,7 +499,7 @@ zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req) * * Note: We can assume at least one free SBAL in the request_queue when called. */ -static inline void +static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) { int count = atomic_read(&fsf_req->adapter->request_queue.free_count); @@ -517,7 +517,7 @@ zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) * * This function changes sbal_curr, sbale_curr, sbal_number of fsf_req. */ -static inline volatile struct qdio_buffer_element * +static volatile struct qdio_buffer_element * zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) { volatile struct qdio_buffer_element *sbale; @@ -554,7 +554,7 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) /** * zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed */ -static inline volatile struct qdio_buffer_element * +static volatile struct qdio_buffer_element * zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) { if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) @@ -569,7 +569,7 @@ zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) * zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue * with zero from */ -static inline int +static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last) { struct qdio_buffer **buf = queue->buffer; @@ -603,7 +603,7 @@ zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req) * zfcp_qdio_sbale_fill - set address and lenght in current SBALE * on request_queue */ -static inline void +static void zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, void *addr, int length) { @@ -624,7 +624,7 @@ zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, * Alignment and length of the segment determine how many SBALEs are needed * for the memory segment. */ -static inline int +static int zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, void *start_addr, unsigned long total_length) { @@ -659,7 +659,7 @@ zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, * @sg_count: number of elements in scatter-gather list * @max_sbals: upper bound for number of SBALs to be used */ -inline int +int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, struct scatterlist *sg, int sg_count, int max_sbals) { @@ -707,7 +707,7 @@ out: * @length: length of buffer * @max_sbals: upper bound for number of SBALs to be used */ -static inline int +static int zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, void *buffer, unsigned long length, int max_sbals) { @@ -728,7 +728,7 @@ zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, * @scsi_cmnd: either scatter-gather list or buffer contained herein is used * to fill SBALs */ -inline int +int zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, struct scsi_cmnd *scsi_cmnd) { diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 452d96f92a14..99db02062c3b 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -90,7 +90,7 @@ zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) return fcp_sns_info_ptr; } -fcp_dl_t * +static fcp_dl_t * zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd) { int additional_length = fcp_cmd->add_fcp_cdb_length << 2; @@ -124,19 +124,19 @@ zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl) * regarding the specified byte */ static inline void -set_byte(u32 * result, char status, char pos) +set_byte(int *result, char status, char pos) { *result |= status << (pos * 8); } void -set_host_byte(u32 * result, char status) +set_host_byte(int *result, char status) { set_byte(result, status, 2); } void -set_driver_byte(u32 * result, char status) +set_driver_byte(int *result, char status) { set_byte(result, status, 3); } @@ -280,7 +280,7 @@ out: return retval; } -void +static void zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt) { struct completion *wait = (struct completion *) scpnt->SCp.ptr; @@ -324,7 +324,7 @@ zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt, * returns: 0 - success, SCSI command enqueued * !0 - failure */ -int +static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, void (*done) (struct scsi_cmnd *)) { @@ -380,7 +380,7 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id, * will handle late commands. (Usually, the normal completion of late * commands is ignored with respect to the running abort operation.) */ -int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) +static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) { struct Scsi_Host *scsi_host; struct zfcp_adapter *adapter; @@ -445,7 +445,7 @@ int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) return retval; } -int +static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) { int retval; @@ -541,7 +541,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags, /** * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset */ -int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) +static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { struct zfcp_unit *unit; struct zfcp_adapter *adapter; diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c index 1e788e815ce7..090743d2f914 100644 --- a/drivers/s390/sysinfo.c +++ b/drivers/s390/sysinfo.c @@ -9,8 +9,14 @@ #include #include #include +#include #include +/* Sigh, math-emu. Don't ask. */ +#include +#include +#include + struct sysinfo_1_1_1 { char reserved_0[32]; char manufacturer[16]; @@ -198,7 +204,7 @@ static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len) * if the higher order 8 bits are not zero. Printing * a floating point number in the kernel is a no-no, * always print the number as 32 bit unsigned integer. - * The user-space needs to know about the stange + * The user-space needs to know about the strange * encoding of the alternate cpu capability. */ len += sprintf(page + len, "Capability: %u %u\n", @@ -351,3 +357,58 @@ static __init int create_proc_sysinfo(void) __initcall(create_proc_sysinfo); +/* + * CPU capability might have changed. Therefore recalculate loops_per_jiffy. + */ +void s390_adjust_jiffies(void) +{ + struct sysinfo_1_2_2 *info; + const unsigned int fmil = 0x4b189680; /* 1e7 as 32-bit float. */ + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + unsigned int capability; + + info = (void *) get_zeroed_page(GFP_KERNEL); + if (!info) + return; + + if (stsi(info, 1, 2, 2) != -ENOSYS) { + /* + * Major sigh. The cpu capability encoding is "special". + * If the first 9 bits of info->capability are 0 then it + * is a 32 bit unsigned integer in the range 0 .. 2^23. + * If the first 9 bits are != 0 then it is a 32 bit float. + * In addition a lower value indicates a proportionally + * higher cpu capacity. Bogomips are the other way round. + * To get to a halfway suitable number we divide 1e7 + * by the cpu capability number. Yes, that means a floating + * point division .. math-emu here we come :-) + */ + FP_UNPACK_SP(SA, &fmil); + if ((info->capability >> 23) == 0) + FP_FROM_INT_S(SB, info->capability, 32, int); + else + FP_UNPACK_SP(SB, &info->capability); + FP_DIV_S(SR, SA, SB); + FP_TO_INT_S(capability, SR, 32, 0); + } else + /* + * Really old machine without stsi block for basic + * cpu information. Report 42.0 bogomips. + */ + capability = 42; + loops_per_jiffy = capability * (500000/HZ); + free_page((unsigned long) info); +} + +/* + * calibrate the delay loop + */ +void __init calibrate_delay(void) +{ + s390_adjust_jiffies(); + /* Print the good old Bogomips line .. */ + printk(KERN_DEBUG "Calibrating delay loop (skipped)... " + "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100); +} diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index b318500785e5..821386c7b576 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -7558,9 +7558,6 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = { { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B8, - 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] }, 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/class/usblp.c b/drivers/usb/class/usblp.c index 6377db1b446d..63e50a1f1396 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -398,6 +398,9 @@ static int usblp_open(struct inode *inode, struct file *file) retval = 0; #endif + retval = usb_autopm_get_interface(intf); + if (retval < 0) + goto out; usblp->used = 1; file->private_data = usblp; @@ -442,6 +445,7 @@ static int usblp_release(struct inode *inode, struct file *file) usblp->used = 0; if (usblp->present) { usblp_unlink_urbs(usblp); + usb_autopm_put_interface(usblp->intf); } else /* finish cleanup from disconnect */ usblp_cleanup (usblp); mutex_unlock (&usblp_mutex); @@ -1203,14 +1207,9 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message) { struct usblp *usblp = usb_get_intfdata (intf); - /* this races against normal access and open */ - mutex_lock (&usblp_mutex); - mutex_lock (&usblp->mut); /* we take no more IO */ usblp->sleeping = 1; usblp_unlink_urbs(usblp); - mutex_unlock (&usblp->mut); - mutex_unlock (&usblp_mutex); return 0; } @@ -1220,15 +1219,9 @@ static int usblp_resume (struct usb_interface *intf) struct usblp *usblp = usb_get_intfdata (intf); int r; - mutex_lock (&usblp_mutex); - mutex_lock (&usblp->mut); - usblp->sleeping = 0; r = handle_bidir (usblp); - mutex_unlock (&usblp->mut); - mutex_unlock (&usblp_mutex); - return r; } @@ -1251,6 +1244,7 @@ static struct usb_driver usblp_driver = { .suspend = usblp_suspend, .resume = usblp_resume, .id_table = usblp_ids, + .supports_autosuspend = 1, }; static int __init usblp_init(void) 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/buffer.c b/drivers/usb/core/buffer.c index c3915dc28608..ead2475406b8 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -49,9 +49,9 @@ static const size_t pool_max [HCD_BUFFER_POOLS] = { * * Call hcd_buffer_destroy() to clean up after using those pools. */ -int hcd_buffer_create (struct usb_hcd *hcd) +int hcd_buffer_create(struct usb_hcd *hcd) { - char name [16]; + char name[16]; int i, size; if (!hcd->self.controller->dma_mask) @@ -60,11 +60,11 @@ int hcd_buffer_create (struct usb_hcd *hcd) for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (!(size = pool_max [i])) continue; - snprintf (name, sizeof name, "buffer-%d", size); - hcd->pool [i] = dma_pool_create (name, hcd->self.controller, + snprintf(name, sizeof name, "buffer-%d", size); + hcd->pool[i] = dma_pool_create(name, hcd->self.controller, size, size, 0); if (!hcd->pool [i]) { - hcd_buffer_destroy (hcd); + hcd_buffer_destroy(hcd); return -ENOMEM; } } @@ -79,14 +79,14 @@ int hcd_buffer_create (struct usb_hcd *hcd) * * This frees the buffer pools created by hcd_buffer_create(). */ -void hcd_buffer_destroy (struct usb_hcd *hcd) +void hcd_buffer_destroy(struct usb_hcd *hcd) { int i; for (i = 0; i < HCD_BUFFER_POOLS; i++) { - struct dma_pool *pool = hcd->pool [i]; + struct dma_pool *pool = hcd->pool[i]; if (pool) { - dma_pool_destroy (pool); + dma_pool_destroy(pool); hcd->pool[i] = NULL; } } @@ -97,8 +97,8 @@ void hcd_buffer_destroy (struct usb_hcd *hcd) * better sharing and to leverage mm/slab.c intelligence. */ -void *hcd_buffer_alloc ( - struct usb_bus *bus, +void *hcd_buffer_alloc( + struct usb_bus *bus, size_t size, gfp_t mem_flags, dma_addr_t *dma @@ -110,18 +110,18 @@ void *hcd_buffer_alloc ( /* some USB hosts just use PIO */ if (!bus->controller->dma_mask) { *dma = ~(dma_addr_t) 0; - return kmalloc (size, mem_flags); + return kmalloc(size, mem_flags); } for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (size <= pool_max [i]) - return dma_pool_alloc (hcd->pool [i], mem_flags, dma); + return dma_pool_alloc(hcd->pool [i], mem_flags, dma); } - return dma_alloc_coherent (hcd->self.controller, size, dma, 0); + return dma_alloc_coherent(hcd->self.controller, size, dma, 0); } -void hcd_buffer_free ( - struct usb_bus *bus, +void hcd_buffer_free( + struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma @@ -134,15 +134,15 @@ void hcd_buffer_free ( return; if (!bus->controller->dma_mask) { - kfree (addr); + kfree(addr); return; } for (i = 0; i < HCD_BUFFER_POOLS; i++) { if (size <= pool_max [i]) { - dma_pool_free (hcd->pool [i], addr, dma); + dma_pool_free(hcd->pool [i], addr, dma); return; } } - dma_free_coherent (hcd->self.controller, size, addr, dma); + dma_free_coherent(hcd->self.controller, size, addr, dma); } diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index ea398e5d50af..a47c30b2d764 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -104,7 +104,7 @@ static const char *format_config = static const char *format_iface = /* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/ - "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n"; + "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n"; static const char *format_endpt = /* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */ @@ -164,10 +164,10 @@ static const char *class_decode(const int class) for (ix = 0; clas_info[ix].class != -1; ix++) if (clas_info[ix].class == class) break; - return (clas_info[ix].class_name); + return clas_info[ix].class_name; } -static char *usb_dump_endpoint_descriptor ( +static char *usb_dump_endpoint_descriptor( int speed, char *start, char *end, @@ -212,9 +212,9 @@ static char *usb_dump_endpoint_descriptor ( break; case USB_ENDPOINT_XFER_INT: type = "Int."; - if (speed == USB_SPEED_HIGH) { + if (speed == USB_SPEED_HIGH) interval = 1 << (desc->bInterval - 1); - } else + else interval = desc->bInterval; break; default: /* "can't happen" */ @@ -242,15 +242,19 @@ static char *usb_dump_interface_descriptor(char *start, char *end, { const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc; const char *driver_name = ""; + int active = 0; if (start > end) return start; down_read(&usb_bus_type.subsys.rwsem); - if (iface) + if (iface) { driver_name = (iface->dev.driver ? iface->dev.driver->name : "(none)"); + active = (desc == &iface->cur_altsetting->desc); + } start += sprintf(start, format_iface, + active ? '*' : ' ', /* mark active altsetting */ desc->bInterfaceNumber, desc->bAlternateSetting, desc->bNumEndpoints, @@ -343,7 +347,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb if (start > end) return start; - start += sprintf (start, format_device1, + start += sprintf(start, format_device1, bcdUSB >> 8, bcdUSB & 0xff, desc->bDeviceClass, class_decode (desc->bDeviceClass), @@ -363,7 +367,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb /* * Dump the different strings that this device holds. */ -static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev) +static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev) { if (start > end) return start; @@ -395,7 +399,7 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev) if (start > end) return start; - start = usb_dump_device_strings (start, end, dev); + start = usb_dump_device_strings(start, end, dev); for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { if (start > end) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 4b3a6ab29bd3..2087766f9e88 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; }; /* @@ -570,6 +570,7 @@ static int usbdev_open(struct inode *inode, struct file *file) ps->dev = dev; ps->file = file; spin_lock_init(&ps->lock); + INIT_LIST_HEAD(&ps->list); INIT_LIST_HEAD(&ps->async_pending); INIT_LIST_HEAD(&ps->async_completed); init_waitqueue_head(&ps->wait); @@ -1596,19 +1597,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/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d6eb5ce1dd1d..600d1bc8272a 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 @@ -750,7 +753,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 +767,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/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/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index ebb20ff7ac58..b531a4fd30c2 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -25,6 +25,20 @@ static inline const char *plural(int n) return (n == 1 ? "" : "s"); } +static int is_rndis(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_COMM + && desc->bInterfaceSubClass == 2 + && desc->bInterfaceProtocol == 0xff; +} + +static int is_activesync(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_MISC + && desc->bInterfaceSubClass == 1 + && desc->bInterfaceProtocol == 1; +} + static int choose_configuration(struct usb_device *udev) { int i; @@ -87,14 +101,12 @@ static int choose_configuration(struct usb_device *udev) continue; } - /* If the first config's first interface is COMM/2/0xff - * (MSFT RNDIS), rule it out unless Linux has host-side - * RNDIS support. */ - if (i == 0 && desc - && desc->bInterfaceClass == USB_CLASS_COMM - && desc->bInterfaceSubClass == 2 - && desc->bInterfaceProtocol == 0xff) { -#ifndef CONFIG_USB_NET_RNDIS_HOST + /* When the first config's first interface is one of Microsoft's + * pet nonstandard Ethernet-over-USB protocols, ignore it unless + * this kernel has enabled the necessary host side driver. + */ + if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) { +#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) continue; #else best = c; 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/hub.c b/drivers/usb/core/hub.c index 1988224b362b..590ec82d0515 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -87,9 +87,6 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); static struct task_struct *khubd_task; -/* multithreaded probe logic */ -static int multithread_probe = 0; - /* cycle leds on hubs that aren't blinking for attention */ static int blinkenlights = 0; module_param (blinkenlights, bool, S_IRUGO); @@ -1256,9 +1253,28 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) static int __usb_port_suspend(struct usb_device *, int port1); #endif -static int __usb_new_device(void *void_data) +/** + * usb_new_device - perform initial device setup (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * This is called with devices which have been enumerated, but not yet + * configured. The device descriptor is available, but not descriptors + * for any device configuration. The caller must have locked either + * the parent hub (if udev is a normal device) or else the + * usb_bus_list_lock (if udev is a root hub). The parent's pointer to + * udev has already been installed, but udev is not yet visible through + * sysfs or other filesystem code. + * + * It will return if the device is configured properly or not. Zero if + * the interface was registered with the driver core; else a negative + * errno value. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Only the hub driver or root-hub registrar should ever call this. + */ +int usb_new_device(struct usb_device *udev) { - struct usb_device *udev = void_data; int err; /* Lock ourself into memory in order to keep a probe sequence @@ -1375,44 +1391,6 @@ fail: goto exit; } -/** - * usb_new_device - perform initial device setup (usbcore-internal) - * @udev: newly addressed device (in ADDRESS state) - * - * This is called with devices which have been enumerated, but not yet - * configured. The device descriptor is available, but not descriptors - * for any device configuration. The caller must have locked either - * the parent hub (if udev is a normal device) or else the - * usb_bus_list_lock (if udev is a root hub). The parent's pointer to - * udev has already been installed, but udev is not yet visible through - * sysfs or other filesystem code. - * - * The return value for this function depends on if the - * multithread_probe variable is set or not. If it's set, it will - * return a if the probe thread was successfully created or not. If the - * variable is not set, it will return if the device is configured - * properly or not. interfaces, in sysfs); else a negative errno value. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Only the hub driver or root-hub registrar should ever call this. - */ -int usb_new_device(struct usb_device *udev) -{ - struct task_struct *probe_task; - int ret = 0; - - if (multithread_probe) { - probe_task = kthread_run(__usb_new_device, udev, - "usb-probe-%s", udev->devnum); - if (IS_ERR(probe_task)) - ret = PTR_ERR(probe_task); - } else - ret = __usb_new_device(udev); - - return ret; -} - static int hub_port_status(struct usb_hub *hub, int port1, u16 *status, u16 *change) { diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 149aa8bfb1fe..8aca3574c2b5 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1545,11 +1545,7 @@ int usb_driver_set_configuration(struct usb_device *udev, int config) INIT_WORK(&req->work, driver_set_config_work); usb_get_dev(udev); - if (!schedule_work(&req->work)) { - usb_put_dev(udev); - kfree(req); - return -EINVAL; - } + schedule_work(&req->work); return 0; } EXPORT_SYMBOL_GPL(usb_driver_set_configuration); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 55d8f575206d..4eaa0ee8e72f 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -16,16 +16,16 @@ /* Active configuration fields */ #define usb_actconfig_show(field, multiplier, format_string) \ -static ssize_t show_##field (struct device *dev, \ +static ssize_t show_##field(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct usb_device *udev; \ struct usb_host_config *actconfig; \ \ - udev = to_usb_device (dev); \ + udev = to_usb_device(dev); \ actconfig = udev->actconfig; \ if (actconfig) \ - return sprintf (buf, format_string, \ + return sprintf(buf, format_string, \ actconfig->desc.field * multiplier); \ else \ return 0; \ @@ -35,9 +35,9 @@ static ssize_t show_##field (struct device *dev, \ usb_actconfig_show(field, multiplier, format_string) \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); -usb_actconfig_attr (bNumInterfaces, 1, "%2d\n") -usb_actconfig_attr (bmAttributes, 1, "%2x\n") -usb_actconfig_attr (bMaxPower, 2, "%3dmA\n") +usb_actconfig_attr(bNumInterfaces, 1, "%2d\n") +usb_actconfig_attr(bmAttributes, 1, "%2x\n") +usb_actconfig_attr(bMaxPower, 2, "%3dmA\n") static ssize_t show_configuration_string(struct device *dev, struct device_attribute *attr, char *buf) @@ -45,7 +45,7 @@ static ssize_t show_configuration_string(struct device *dev, struct usb_device *udev; struct usb_host_config *actconfig; - udev = to_usb_device (dev); + udev = to_usb_device(dev); actconfig = udev->actconfig; if ((!actconfig) || (!actconfig->string)) return 0; @@ -57,16 +57,16 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); usb_actconfig_show(bConfigurationValue, 1, "%u\n"); static ssize_t -set_bConfigurationValue (struct device *dev, struct device_attribute *attr, +set_bConfigurationValue(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct usb_device *udev = to_usb_device (dev); + struct usb_device *udev = to_usb_device(dev); int config, value; - if (sscanf (buf, "%u", &config) != 1 || config > 255) + if (sscanf(buf, "%u", &config) != 1 || config > 255) return -EINVAL; usb_lock_device(udev); - value = usb_set_configuration (udev, config); + value = usb_set_configuration(udev, config); usb_unlock_device(udev); return (value < 0) ? value : count; } @@ -81,7 +81,7 @@ static ssize_t show_##name(struct device *dev, \ { \ struct usb_device *udev; \ \ - udev = to_usb_device (dev); \ + udev = to_usb_device(dev); \ return sprintf(buf, "%s\n", udev->name); \ } \ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); @@ -91,12 +91,12 @@ usb_string_attr(manufacturer); usb_string_attr(serial); static ssize_t -show_speed (struct device *dev, struct device_attribute *attr, char *buf) +show_speed(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; char *speed; - udev = to_usb_device (dev); + udev = to_usb_device(dev); switch (udev->speed) { case USB_SPEED_LOW: @@ -112,22 +112,22 @@ show_speed (struct device *dev, struct device_attribute *attr, char *buf) default: speed = "unknown"; } - return sprintf (buf, "%s\n", speed); + return sprintf(buf, "%s\n", speed); } static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL); static ssize_t -show_devnum (struct device *dev, struct device_attribute *attr, char *buf) +show_devnum(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; - udev = to_usb_device (dev); - return sprintf (buf, "%d\n", udev->devnum); + udev = to_usb_device(dev); + return sprintf(buf, "%d\n", udev->devnum); } static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL); static ssize_t -show_version (struct device *dev, struct device_attribute *attr, char *buf) +show_version(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; u16 bcdUSB; @@ -139,25 +139,25 @@ show_version (struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); static ssize_t -show_maxchild (struct device *dev, struct device_attribute *attr, char *buf) +show_maxchild(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev; - udev = to_usb_device (dev); - return sprintf (buf, "%d\n", udev->maxchild); + udev = to_usb_device(dev); + return sprintf(buf, "%d\n", udev->maxchild); } static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); /* Descriptor fields */ #define usb_descriptor_attr_le16(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, \ +show_##field(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct usb_device *udev; \ \ - udev = to_usb_device (dev); \ - return sprintf (buf, format_string, \ + udev = to_usb_device(dev); \ + return sprintf(buf, format_string, \ le16_to_cpu(udev->descriptor.field)); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); @@ -168,21 +168,21 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n") #define usb_descriptor_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, \ +show_##field(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct usb_device *udev; \ \ - udev = to_usb_device (dev); \ - return sprintf (buf, format_string, udev->descriptor.field); \ + udev = to_usb_device(dev); \ + return sprintf(buf, format_string, udev->descriptor.field); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); -usb_descriptor_attr (bDeviceClass, "%02x\n") -usb_descriptor_attr (bDeviceSubClass, "%02x\n") -usb_descriptor_attr (bDeviceProtocol, "%02x\n") -usb_descriptor_attr (bNumConfigurations, "%d\n") -usb_descriptor_attr (bMaxPacketSize0, "%d\n") +usb_descriptor_attr(bDeviceClass, "%02x\n") +usb_descriptor_attr(bDeviceSubClass, "%02x\n") +usb_descriptor_attr(bDeviceProtocol, "%02x\n") +usb_descriptor_attr(bNumConfigurations, "%d\n") +usb_descriptor_attr(bMaxPacketSize0, "%d\n") static struct attribute *dev_attrs[] = { /* current configuration's attributes */ @@ -220,17 +220,17 @@ int usb_create_sysfs_dev_files(struct usb_device *udev) return retval; if (udev->manufacturer) { - retval = device_create_file (dev, &dev_attr_manufacturer); + retval = device_create_file(dev, &dev_attr_manufacturer); if (retval) goto error; } if (udev->product) { - retval = device_create_file (dev, &dev_attr_product); + retval = device_create_file(dev, &dev_attr_product); if (retval) goto error; } if (udev->serial) { - retval = device_create_file (dev, &dev_attr_serial); + retval = device_create_file(dev, &dev_attr_serial); if (retval) goto error; } @@ -246,7 +246,7 @@ error: return retval; } -void usb_remove_sysfs_dev_files (struct usb_device *udev) +void usb_remove_sysfs_dev_files(struct usb_device *udev) { struct device *dev = &udev->dev; @@ -264,22 +264,22 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev) /* Interface fields */ #define usb_intf_attr(field, format_string) \ static ssize_t \ -show_##field (struct device *dev, struct device_attribute *attr, \ +show_##field(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ - struct usb_interface *intf = to_usb_interface (dev); \ + struct usb_interface *intf = to_usb_interface(dev); \ \ - return sprintf (buf, format_string, \ + return sprintf(buf, format_string, \ intf->cur_altsetting->desc.field); \ } \ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); -usb_intf_attr (bInterfaceNumber, "%02x\n") -usb_intf_attr (bAlternateSetting, "%2d\n") -usb_intf_attr (bNumEndpoints, "%02x\n") -usb_intf_attr (bInterfaceClass, "%02x\n") -usb_intf_attr (bInterfaceSubClass, "%02x\n") -usb_intf_attr (bInterfaceProtocol, "%02x\n") +usb_intf_attr(bInterfaceNumber, "%02x\n") +usb_intf_attr(bAlternateSetting, "%2d\n") +usb_intf_attr(bNumEndpoints, "%02x\n") +usb_intf_attr(bInterfaceClass, "%02x\n") +usb_intf_attr(bInterfaceSubClass, "%02x\n") +usb_intf_attr(bInterfaceProtocol, "%02x\n") static ssize_t show_interface_string(struct device *dev, struct device_attribute *attr, char *buf) @@ -288,8 +288,8 @@ static ssize_t show_interface_string(struct device *dev, struct usb_device *udev; int len; - intf = to_usb_interface (dev); - udev = interface_to_usbdev (intf); + intf = to_usb_interface(dev); + udev = interface_to_usbdev(intf); len = snprintf(buf, 256, "%s", intf->cur_altsetting->string); if (len < 0) return 0; @@ -384,7 +384,7 @@ error: return retval; } -void usb_remove_sysfs_intf_files (struct usb_interface *intf) +void usb_remove_sysfs_intf_files(struct usb_interface *intf) { usb_remove_intf_ep_files(intf); sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 9801d08edacf..94ea9727ff55 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -235,16 +235,15 @@ 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 */ pipe = urb->pipe; - temp = usb_pipetype (pipe); - is_out = usb_pipeout (pipe); + temp = usb_pipetype(pipe); + is_out = usb_pipeout(pipe); - if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED) + if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED) return -ENODEV; /* FIXME there should be a sharable lock protecting us against @@ -253,11 +252,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) * checks get made.) */ - max = usb_maxpacket (dev, pipe, is_out); + max = usb_maxpacket(dev, pipe, is_out); if (max <= 0) { dev_dbg(&dev->dev, "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", - usb_pipeendpoint (pipe), is_out ? "out" : "in", + usb_pipeendpoint(pipe), is_out ? "out" : "in", __FUNCTION__, max); return -EMSGSIZE; } @@ -279,11 +278,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) if (urb->number_of_packets <= 0) return -EINVAL; for (n = 0; n < urb->number_of_packets; n++) { - len = urb->iso_frame_desc [n].length; + len = urb->iso_frame_desc[n].length; if (len < 0 || len > max) return -EMSGSIZE; - urb->iso_frame_desc [n].status = -EXDEV; - urb->iso_frame_desc [n].actual_length = 0; + urb->iso_frame_desc[n].status = -EXDEV; + urb->iso_frame_desc[n].actual_length = 0; } } @@ -322,7 +321,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* fail if submitter gave bogus flags */ if (urb->transfer_flags != orig_flags) { - err ("BOGUS urb flags, %x --> %x", + err("BOGUS urb flags, %x --> %x", orig_flags, urb->transfer_flags); return -EINVAL; } @@ -373,7 +372,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) urb->interval = temp; } - return usb_hcd_submit_urb (urb, mem_flags); + return usb_hcd_submit_urb(urb, mem_flags); } /*-------------------------------------------------------------------*/ diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 02426d0b9a34..3db721cd557a 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -233,7 +233,7 @@ static void usb_autosuspend_work(struct work_struct *work) * @parent: hub to which device is connected; null to allocate a root hub * @bus: bus used to access the device * @port1: one-based index of port; ignored for root hubs - * Context: !in_interrupt () + * Context: !in_interrupt() * * Only hub drivers (including virtual root hub drivers for host * controllers) should ever call this. @@ -277,22 +277,22 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) * as stable: bus->busnum changes easily from modprobe order, * cardbus or pci hotplugging, and so on. */ - if (unlikely (!parent)) { - dev->devpath [0] = '0'; + if (unlikely(!parent)) { + dev->devpath[0] = '0'; dev->dev.parent = bus->controller; - sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum); + sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum); } else { /* match any labeling on the hubs; it's one-based */ - if (parent->devpath [0] == '0') - snprintf (dev->devpath, sizeof dev->devpath, + if (parent->devpath[0] == '0') + snprintf(dev->devpath, sizeof dev->devpath, "%d", port1); else - snprintf (dev->devpath, sizeof dev->devpath, + snprintf(dev->devpath, sizeof dev->devpath, "%s.%d", parent->devpath, port1); dev->dev.parent = &parent->dev; - sprintf (&dev->dev.bus_id[0], "%d-%s", + sprintf(&dev->dev.bus_id[0], "%d-%s", bus->busnum, dev->devpath); /* hub driver sets up TT records */ @@ -463,7 +463,7 @@ static struct usb_device *match_device(struct usb_device *dev, /* see if this device matches */ if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) && (product_id == le16_to_cpu(dev->descriptor.idProduct))) { - dev_dbg (&dev->dev, "matched this device!\n"); + dev_dbg(&dev->dev, "matched this device!\n"); ret_dev = usb_get_dev(dev); goto exit; } @@ -535,7 +535,7 @@ exit: */ int usb_get_current_frame_number(struct usb_device *dev) { - return usb_hcd_get_frame_number (dev); + return usb_hcd_get_frame_number(dev); } /*-------------------------------------------------------------------*/ @@ -593,7 +593,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, * * When the buffer is no longer used, free it with usb_buffer_free(). */ -void *usb_buffer_alloc ( +void *usb_buffer_alloc( struct usb_device *dev, size_t size, gfp_t mem_flags, @@ -602,7 +602,7 @@ void *usb_buffer_alloc ( { if (!dev || !dev->bus) return NULL; - return hcd_buffer_alloc (dev->bus, size, mem_flags, dma); + return hcd_buffer_alloc(dev->bus, size, mem_flags, dma); } /** @@ -616,7 +616,7 @@ void *usb_buffer_alloc ( * been allocated using usb_buffer_alloc(), and the parameters must match * those provided in that allocation request. */ -void usb_buffer_free ( +void usb_buffer_free( struct usb_device *dev, size_t size, void *addr, @@ -627,7 +627,7 @@ void usb_buffer_free ( return; if (!addr) return; - hcd_buffer_free (dev->bus, size, addr, dma); + hcd_buffer_free(dev->bus, size, addr, dma); } /** @@ -647,7 +647,7 @@ void usb_buffer_free ( * Reverse the effect of this call with usb_buffer_unmap(). */ #if 0 -struct urb *usb_buffer_map (struct urb *urb) +struct urb *usb_buffer_map(struct urb *urb) { struct usb_bus *bus; struct device *controller; @@ -659,14 +659,14 @@ struct urb *usb_buffer_map (struct urb *urb) return NULL; if (controller->dma_mask) { - urb->transfer_dma = dma_map_single (controller, + urb->transfer_dma = dma_map_single(controller, urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_pipein(urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - if (usb_pipecontrol (urb->pipe)) - urb->setup_dma = dma_map_single (controller, + if (usb_pipecontrol(urb->pipe)) + urb->setup_dma = dma_map_single(controller, urb->setup_packet, - sizeof (struct usb_ctrlrequest), + sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); // FIXME generic api broken like pci, can't report errors // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; @@ -689,7 +689,7 @@ struct urb *usb_buffer_map (struct urb *urb) * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s) * @urb: urb whose transfer_buffer/setup_packet will be synchronized */ -void usb_buffer_dmasync (struct urb *urb) +void usb_buffer_dmasync(struct urb *urb) { struct usb_bus *bus; struct device *controller; @@ -702,14 +702,14 @@ void usb_buffer_dmasync (struct urb *urb) return; if (controller->dma_mask) { - dma_sync_single (controller, + dma_sync_single(controller, urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_pipein(urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - if (usb_pipecontrol (urb->pipe)) - dma_sync_single (controller, + if (usb_pipecontrol(urb->pipe)) + dma_sync_single(controller, urb->setup_dma, - sizeof (struct usb_ctrlrequest), + sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); } } @@ -722,7 +722,7 @@ void usb_buffer_dmasync (struct urb *urb) * Reverses the effect of usb_buffer_map(). */ #if 0 -void usb_buffer_unmap (struct urb *urb) +void usb_buffer_unmap(struct urb *urb) { struct usb_bus *bus; struct device *controller; @@ -735,14 +735,14 @@ void usb_buffer_unmap (struct urb *urb) return; if (controller->dma_mask) { - dma_unmap_single (controller, + dma_unmap_single(controller, urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein (urb->pipe) + usb_pipein(urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - if (usb_pipecontrol (urb->pipe)) - dma_unmap_single (controller, + if (usb_pipecontrol(urb->pipe)) + dma_unmap_single(controller, urb->setup_dma, - sizeof (struct usb_ctrlrequest), + sizeof(struct usb_ctrlrequest), DMA_TO_DEVICE); } urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP @@ -783,15 +783,15 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe, struct device *controller; if (!dev - || usb_pipecontrol (pipe) + || usb_pipecontrol(pipe) || !(bus = dev->bus) || !(controller = bus->controller) || !controller->dma_mask) return -1; // FIXME generic api broken like pci, can't report errors - return dma_map_sg (controller, sg, nents, - usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + return dma_map_sg(controller, sg, nents, + usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* XXX DISABLED, no users currently. If you wish to re-enable this @@ -823,8 +823,8 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe, || !controller->dma_mask) return; - dma_sync_sg (controller, sg, n_hw_ents, - usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + dma_sync_sg(controller, sg, n_hw_ents, + usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } #endif @@ -849,8 +849,8 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe, || !controller->dma_mask) return; - dma_unmap_sg (controller, sg, n_hw_ents, - usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + dma_unmap_sg(controller, sg, n_hw_ents, + usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* format to disable USB on kernel command line is: nousb */ @@ -871,7 +871,7 @@ static int __init usb_init(void) { int retval; if (nousb) { - pr_info ("%s: USB support disabled\n", usbcore_name); + pr_info("%s: USB support disabled\n", usbcore_name); return 0; } @@ -971,19 +971,19 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor); EXPORT_SYMBOL(usb_find_device); EXPORT_SYMBOL(usb_get_current_frame_number); -EXPORT_SYMBOL (usb_buffer_alloc); -EXPORT_SYMBOL (usb_buffer_free); +EXPORT_SYMBOL(usb_buffer_alloc); +EXPORT_SYMBOL(usb_buffer_free); #if 0 -EXPORT_SYMBOL (usb_buffer_map); -EXPORT_SYMBOL (usb_buffer_dmasync); -EXPORT_SYMBOL (usb_buffer_unmap); +EXPORT_SYMBOL(usb_buffer_map); +EXPORT_SYMBOL(usb_buffer_dmasync); +EXPORT_SYMBOL(usb_buffer_unmap); #endif -EXPORT_SYMBOL (usb_buffer_map_sg); +EXPORT_SYMBOL(usb_buffer_map_sg); #if 0 -EXPORT_SYMBOL (usb_buffer_dmasync_sg); +EXPORT_SYMBOL(usb_buffer_dmasync_sg); #endif -EXPORT_SYMBOL (usb_buffer_unmap_sg); +EXPORT_SYMBOL(usb_buffer_unmap_sg); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 812c733ba8ce..f39050145f1f 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 @@ -1807,16 +1807,13 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) || !wake || at91_suspend_entering_slow_clock()) { pullup(udc, 0); - disable_irq_wake(udc->udp_irq); + wake = 0; } else enable_irq_wake(udc->udp_irq); - if (udc->board.vbus_pin > 0) { - if (wake) - enable_irq_wake(udc->board.vbus_pin); - else - disable_irq_wake(udc->board.vbus_pin); - } + udc->active_suspend = wake; + if (udc->board.vbus_pin > 0 && wake) + enable_irq_wake(udc->board.vbus_pin); return 0; } @@ -1824,8 +1821,14 @@ static int at91udc_resume(struct platform_device *pdev) { struct at91_udc *udc = platform_get_drvdata(pdev); + if (udc->board.vbus_pin > 0 && udc->active_suspend) + disable_irq_wake(udc->board.vbus_pin); + /* maybe reconnect to host; if so, clocks on */ - pullup(udc, 1); + if (udc->active_suspend) + disable_irq_wake(udc->udp_irq); + else + pullup(udc, 1); return 0; } #else diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index 677089baa59d..7e34e2f864f9 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -136,6 +136,7 @@ struct at91_udc { unsigned wait_for_addr_ack:1; unsigned wait_for_config_ack:1; unsigned selfpowered:1; + unsigned active_suspend:1; u8 addr; struct at91_udc_data board; struct clk *iclk, *fclk; 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..22e3c9443641 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -47,7 +47,7 @@ #include #include -#include +#include #include #include @@ -72,9 +72,18 @@ * * There's some hardware that can't talk CDC. We make that hardware * implement a "minimalist" vendor-agnostic CDC core: same framing, but - * link-level setup only requires activating the configuration. - * Linux supports it, but other host operating systems may not. - * (This is a subset of CDC Ethernet.) + * link-level setup only requires activating the configuration. Only the + * endpoint descriptors, and product/vendor IDs, are relevant; no control + * operations are available. Linux supports it, but other host operating + * systems may not. (This is a subset of CDC Ethernet.) + * + * It turns out that if you add a few descriptors to that "CDC Subset", + * (Windows) host side drivers from MCCI can treat it as one submode of + * a proprietary scheme called "SAFE" ... without needing to know about + * specific product/vendor IDs. So we do that, making it easier to use + * those MS-Windows drivers. Those added descriptors make it resemble a + * CDC MDLM device, but they don't change device behavior at all. (See + * MCCI Engineering report 950198 "SAFE Networking Functions".) * * A third option is also in use. Rather than CDC Ethernet, or something * simpler, Microsoft pushes their own approach: RNDIS. The published @@ -254,6 +263,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_S3C2410 +#define DEV_CONFIG_CDC +#endif + #ifdef CONFIG_USB_GADGET_AT91 #define DEV_CONFIG_CDC #endif @@ -266,6 +279,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_HUSB2DEV +#define DEV_CONFIG_CDC +#endif + /* For CDC-incapable hardware, choose the simple cdc subset. * Anything that talks bulk (without notable bugs) can do this. @@ -283,9 +300,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_SUBSET #endif -#ifdef CONFIG_USB_GADGET_S3C2410 -#define DEV_CONFIG_CDC -#endif /*-------------------------------------------------------------------------*/ @@ -487,8 +501,17 @@ rndis_config = { * endpoint. Both have a "data" interface and two bulk endpoints. * There are also differences in how control requests are handled. * - * RNDIS shares a lot with CDC-Ethernet, since it's a variant of - * the CDC-ACM (modem) spec. + * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the + * CDC-ACM (modem) spec. Unfortunately MSFT's RNDIS driver is buggy; it + * may hang or oops. Since bugfixes (or accurate specs, letting Linux + * work around those bugs) are unlikely to ever come from MSFT, you may + * wish to avoid using RNDIS. + * + * MCCI offers an alternative to RNDIS if you need to connect to Windows + * but have hardware that can't support CDC Ethernet. We add descriptors + * to present the CDC Subset as a (nonconformant) CDC MDLM variant called + * "SAFE". That borrows from both CDC Ethernet and CDC MDLM. You can + * get those drivers from MCCI, or bundled with various products. */ #ifdef DEV_CONFIG_CDC @@ -522,8 +545,6 @@ rndis_control_intf = { }; #endif -#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) - static const struct usb_cdc_header_desc header_desc = { .bLength = sizeof header_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -532,6 +553,8 @@ static const struct usb_cdc_header_desc header_desc = { .bcdCDC = __constant_cpu_to_le16 (0x0110), }; +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) + static const struct usb_cdc_union_desc union_desc = { .bLength = sizeof union_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -564,7 +587,40 @@ static const struct usb_cdc_acm_descriptor acm_descriptor = { #endif -#ifdef DEV_CONFIG_CDC +#ifndef DEV_CONFIG_CDC + +/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various + * ways: data endpoints live in the control interface, there's no data + * interface, and it's not used to talk to a cell phone radio. + */ + +static const struct usb_cdc_mdlm_desc mdlm_desc = { + .bLength = sizeof mdlm_desc, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_MDLM_TYPE, + + .bcdVersion = __constant_cpu_to_le16(0x0100), + .bGUID = { + 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, + 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, + }, +}; + +/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we + * can't really use its struct. All we do here is say that we're using + * the submode of "SAFE" which directly matches the CDC Subset. + */ +static const u8 mdlm_detail_desc[] = { + 6, + USB_DT_CS_INTERFACE, + USB_CDC_MDLM_DETAIL_TYPE, + + 0, /* "SAFE" */ + 0, /* network control capabilities (none) */ + 0, /* network data capabilities ("raw" encapsulation) */ +}; + +#endif static const struct usb_cdc_ether_desc ether_desc = { .bLength = sizeof ether_desc, @@ -579,7 +635,6 @@ static const struct usb_cdc_ether_desc ether_desc = { .bNumberPowerFilters = 0, }; -#endif #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) @@ -672,6 +727,9 @@ rndis_data_intf = { /* * "Simple" CDC-subset option is a simple vendor-neutral model that most * full speed controllers can handle: one interface, two bulk endpoints. + * + * To assist host side drivers, we fancy it up a bit, and add descriptors + * so some host side drivers will understand it as a "SAFE" variant. */ static const struct usb_interface_descriptor @@ -682,8 +740,8 @@ subset_data_intf = { .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 0, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM, .bInterfaceProtocol = 0, .iInterface = STRING_DATA, }; @@ -731,10 +789,15 @@ static const struct usb_descriptor_header *fs_eth_function [11] = { static inline void __init fs_subset_descriptors(void) { #ifdef DEV_CONFIG_SUBSET + /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; - fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc; - fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc; - fs_eth_function[4] = NULL; + fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; + fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc; + fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc; + fs_eth_function[5] = (struct usb_descriptor_header *) ðer_desc; + fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc; + fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc; + fs_eth_function[8] = NULL; #else fs_eth_function[1] = NULL; #endif @@ -828,10 +891,15 @@ static const struct usb_descriptor_header *hs_eth_function [11] = { static inline void __init hs_subset_descriptors(void) { #ifdef DEV_CONFIG_SUBSET + /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; - hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc; - hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc; - hs_eth_function[4] = NULL; + hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; + hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc; + hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc; + hs_eth_function[5] = (struct usb_descriptor_header *) ðer_desc; + hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc; + hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc; + hs_eth_function[8] = NULL; #else hs_eth_function[1] = NULL; #endif @@ -878,10 +946,8 @@ static char manufacturer [50]; static char product_desc [40] = DRIVER_DESC; static char serial_number [20]; -#ifdef DEV_CONFIG_CDC /* address that the host will use ... usually assigned at random */ static char ethaddr [2 * ETH_ALEN + 1]; -#endif /* static strings, in UTF-8 */ static struct usb_string strings [] = { @@ -889,9 +955,9 @@ static struct usb_string strings [] = { { STRING_PRODUCT, product_desc, }, { STRING_SERIALNUMBER, serial_number, }, { STRING_DATA, "Ethernet Data", }, + { STRING_ETHADDR, ethaddr, }, #ifdef DEV_CONFIG_CDC { STRING_CDC, "CDC Ethernet", }, - { STRING_ETHADDR, ethaddr, }, { STRING_CONTROL, "CDC Communications Control", }, #endif #ifdef DEV_CONFIG_SUBSET @@ -986,10 +1052,10 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags) } #endif - dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); + dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc); dev->in_ep->driver_data = dev; - dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); + dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc); dev->out_ep->driver_data = dev; /* With CDC, the host isn't allowed to use these two data @@ -2278,10 +2344,10 @@ eth_bind (struct usb_gadget *gadget) "RNDIS/%s", driver_desc); /* CDC subset ... recognized by Linux since 2.4.10, but Windows - * drivers aren't widely available. + * drivers aren't widely available. (That may be improved by + * supporting one submode of the "SAFE" variant of MDLM.) */ } else if (!cdc) { - device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; device_desc.idVendor = __constant_cpu_to_le16(SIMPLE_VENDOR_NUM); device_desc.idProduct = @@ -2352,6 +2418,10 @@ autoconf_fail: if (!cdc) { eth_config.bNumInterfaces = 1; eth_config.iConfiguration = STRING_SUBSET; + + /* use functions to set these up, in case we're built to work + * with multiple controllers and must override CDC Ethernet. + */ fs_subset_descriptors(); hs_subset_descriptors(); } @@ -2415,22 +2485,20 @@ autoconf_fail: /* Module params for these addresses should come from ID proms. * The host side address is used with CDC and RNDIS, and commonly - * ends up in a persistent config database. + * ends up in a persistent config database. It's not clear if + * host side code for the SAFE thing cares -- its original BLAN + * thing didn't, Sharp never assigned those addresses on Zaurii. */ if (get_ether_addr(dev_addr, net->dev_addr)) dev_warn(&gadget->dev, "using random %s ethernet address\n", "self"); - if (cdc || rndis) { - if (get_ether_addr(host_addr, dev->host_mac)) - dev_warn(&gadget->dev, - "using random %s ethernet address\n", "host"); -#ifdef DEV_CONFIG_CDC - snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", - dev->host_mac [0], dev->host_mac [1], - dev->host_mac [2], dev->host_mac [3], - dev->host_mac [4], dev->host_mac [5]); -#endif - } + if (get_ether_addr(host_addr, dev->host_mac)) + dev_warn(&gadget->dev, + "using random %s ethernet address\n", "host"); + snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", + dev->host_mac [0], dev->host_mac [1], + dev->host_mac [2], dev->host_mac [3], + dev->host_mac [4], dev->host_mac [5]); if (rndis) { status = rndis_init(); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 72f2ae96fbf3..f04a29a46646 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" @@ -1148,7 +1148,7 @@ static int ep0_queue(struct fsg_dev *fsg) static void ep0_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; + struct fsg_dev *fsg = ep->driver_data; if (req->actual > 0) dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual); @@ -1170,8 +1170,8 @@ static void ep0_complete(struct usb_ep *ep, struct usb_request *req) static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; - struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; if (req->status || req->actual != req->length) DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, @@ -1190,8 +1190,8 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; - struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; dump_msg(fsg, "bulk-out", req->buf, req->actual); if (req->status || req->actual != bh->bulk_out_intended_length) @@ -1214,8 +1214,8 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) #ifdef CONFIG_USB_FILE_STORAGE_TEST static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) { - struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; - struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; + struct fsg_dev *fsg = ep->driver_data; + struct fsg_buffhd *bh = req->context; if (req->status || req->actual != req->length) DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, @@ -2577,7 +2577,7 @@ static int send_status(struct fsg_dev *fsg) } if (transport_is_bbb()) { - struct bulk_cs_wrap *csw = (struct bulk_cs_wrap *) bh->buf; + struct bulk_cs_wrap *csw = bh->buf; /* Store and send the Bulk-only CSW */ csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG); @@ -2596,8 +2596,7 @@ static int send_status(struct fsg_dev *fsg) return 0; } else { // USB_PR_CBI - struct interrupt_data *buf = (struct interrupt_data *) - bh->buf; + struct interrupt_data *buf = bh->buf; /* Store and send the Interrupt data. UFI sends the ASC * and ASCQ bytes. Everything else sends a Type (which @@ -2982,7 +2981,7 @@ static int do_scsi_command(struct fsg_dev *fsg) static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) { struct usb_request *req = bh->outreq; - struct bulk_cb_wrap *cbw = (struct bulk_cb_wrap *) req->buf; + struct bulk_cb_wrap *cbw = req->buf; /* Was this a real packet? */ if (req->status) @@ -3428,7 +3427,7 @@ static void handle_exception(struct fsg_dev *fsg) static int fsg_main_thread(void *fsg_) { - struct fsg_dev *fsg = (struct fsg_dev *) fsg_; + struct fsg_dev *fsg = fsg_; /* Allow the thread to be killed by a signal, but set the signal mask * to block everything but INT, TERM, KILL, and USR1. */ @@ -3600,7 +3599,7 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char * static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) { struct lun *curlun = dev_to_lun(dev); - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); char *p; ssize_t rc; @@ -3629,7 +3628,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); int i; if (sscanf(buf, "%d", &i) != 1) @@ -3652,7 +3651,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); int rc = 0; if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) { @@ -3700,7 +3699,7 @@ static void fsg_release(struct kref *ref) static void lun_release(struct device *dev) { - struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); + struct fsg_dev *fsg = dev_get_drvdata(dev); kref_put(&fsg->ref, fsg_release); } diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index aa80f0910720..2e3d6620d216 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -75,6 +75,12 @@ #define gadget_is_pxa27x(g) 0 #endif +#ifdef CONFIG_USB_GADGET_HUSB2DEV +#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name) +#else +#define gadget_is_husb2dev(g) 0 +#endif + #ifdef CONFIG_USB_GADGET_S3C2410 #define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name) #else @@ -169,5 +175,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x16; else if (gadget_is_mpc8272(gadget)) return 0x17; + else if (gadget_is_husb2dev(gadget)) + return 0x18; return -ENOENT; } 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/inode.c b/drivers/usb/gadget/inode.c index 3fb1044a4db0..34296e79edcf 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -20,7 +20,7 @@ */ -// #define DEBUG /* data to help fault diagnosis */ +// #define DEBUG /* data to help fault diagnosis */ // #define VERBOSE /* extra debug messages (success too) */ #include @@ -59,11 +59,11 @@ * may serve as a source of device events, used to handle all control * requests other than basic enumeration. * - * - Then either immediately, or after a SET_CONFIGURATION control request, - * ep_config() is called when each /dev/gadget/ep* file is configured - * (by writing endpoint descriptors). Afterwards these files are used - * to write() IN data or to read() OUT data. To halt the endpoint, a - * "wrong direction" request is issued (like reading an IN endpoint). + * - Then, after a SET_CONFIGURATION control request, ep_config() is + * called when each /dev/gadget/ep* file is configured (by writing + * endpoint descriptors). Afterwards these files are used to write() + * IN data or to read() OUT data. To halt the endpoint, a "wrong + * direction" request is issued (like reading an IN endpoint). * * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe * not possible on all hardware. For example, precise fault handling with @@ -98,16 +98,16 @@ enum ep0_state { * must always write descriptors to initialize the device, then * the device becomes UNCONNECTED until enumeration. */ - STATE_OPENED, + STATE_DEV_OPENED, /* From then on, ep0 fd is in either of two basic modes: * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it * - SETUP: read/write will transfer control data and succeed; * or if "wrong direction", performs protocol stall */ - STATE_UNCONNECTED, - STATE_CONNECTED, - STATE_SETUP, + STATE_DEV_UNCONNECTED, + STATE_DEV_CONNECTED, + STATE_DEV_SETUP, /* UNBOUND means the driver closed ep0, so the device won't be * accessible again (DEV_DISABLED) until all fds are closed. @@ -121,7 +121,7 @@ enum ep0_state { struct dev_data { spinlock_t lock; atomic_t count; - enum ep0_state state; + enum ep0_state state; /* P: lock */ struct usb_gadgetfs_event event [N_EVENT]; unsigned ev_next; struct fasync_struct *fasync; @@ -188,7 +188,6 @@ static struct dev_data *dev_new (void) enum ep_state { STATE_EP_DISABLED = 0, STATE_EP_READY, - STATE_EP_DEFER_ENABLE, STATE_EP_ENABLED, STATE_EP_UNBOUND, }; @@ -313,18 +312,10 @@ nonblock: if ((val = down_interruptible (&epdata->lock)) < 0) return val; -newstate: + switch (epdata->state) { case STATE_EP_ENABLED: break; - case STATE_EP_DEFER_ENABLE: - DBG (epdata->dev, "%s wait for host\n", epdata->name); - if ((val = wait_event_interruptible (epdata->wait, - epdata->state != STATE_EP_DEFER_ENABLE - || epdata->dev->state == STATE_DEV_UNBOUND - )) < 0) - goto fail; - goto newstate; // case STATE_EP_DISABLED: /* "can't happen" */ // case STATE_EP_READY: /* "can't happen" */ default: /* error! */ @@ -333,7 +324,6 @@ newstate: // FALLTHROUGH case STATE_EP_UNBOUND: /* clean disconnect */ val = -ENODEV; -fail: up (&epdata->lock); } return val; @@ -565,29 +555,28 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb) ssize_t len, total; int i; - /* we "retry" to get the right mm context for this: */ + /* we "retry" to get the right mm context for this: */ - /* copy stuff into user buffers */ - total = priv->actual; - len = 0; - for (i=0; i < priv->nr_segs; i++) { - ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); + /* copy stuff into user buffers */ + total = priv->actual; + len = 0; + for (i=0; i < priv->nr_segs; i++) { + ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); - if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) { - if (len == 0) - len = -EFAULT; - break; - } + if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) { + if (len == 0) + len = -EFAULT; + break; + } - total -= this; - len += this; - if (total == 0) - break; - } - kfree(priv->buf); - kfree(priv); - aio_put_req(iocb); - return len; + total -= this; + len += this; + if (total == 0) + break; + } + kfree(priv->buf); + kfree(priv); + return len; } static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) @@ -600,18 +589,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) spin_lock(&epdata->dev->lock); priv->req = NULL; priv->epdata = NULL; - if (priv->iv == NULL - || unlikely(req->actual == 0) - || unlikely(kiocbIsCancelled(iocb))) { + + /* if this was a write or a read returning no data then we + * don't need to copy anything to userspace, so we can + * complete the aio request immediately. + */ + if (priv->iv == NULL || unlikely(req->actual == 0)) { kfree(req->buf); kfree(priv); iocb->private = NULL; /* aio_complete() reports bytes-transferred _and_ faults */ - if (unlikely(kiocbIsCancelled(iocb))) - aio_put_req(iocb); - else - aio_complete(iocb, - req->actual ? req->actual : req->status, + aio_complete(iocb, req->actual ? req->actual : req->status, req->status); } else { /* retry() won't report both; so we hide some faults */ @@ -636,7 +624,7 @@ ep_aio_rwtail( size_t len, struct ep_data *epdata, const struct iovec *iv, - unsigned long nr_segs + unsigned long nr_segs ) { struct kiocb_priv *priv; @@ -852,9 +840,9 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) break; #endif default: - DBG (data->dev, "unconnected, %s init deferred\n", + DBG(data->dev, "unconnected, %s init abandoned\n", data->name); - data->state = STATE_EP_DEFER_ENABLE; + value = -EINVAL; } if (value == 0) { fd->f_op = &ep_io_operations; @@ -943,22 +931,24 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req) static void ep0_complete (struct usb_ep *ep, struct usb_request *req) { struct dev_data *dev = ep->driver_data; + unsigned long flags; int free = 1; /* for control OUT, data must still get to userspace */ + spin_lock_irqsave(&dev->lock, flags); if (!dev->setup_in) { dev->setup_out_error = (req->status != 0); if (!dev->setup_out_error) free = 0; dev->setup_out_ready = 1; ep0_readable (dev); - } else if (dev->state == STATE_SETUP) - dev->state = STATE_CONNECTED; + } /* clean up as appropriate */ if (free && req->buf != &dev->rbuf) clean_req (ep, req); req->complete = epio_complete; + spin_unlock_irqrestore(&dev->lock, flags); } static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len) @@ -998,13 +988,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) } /* control DATA stage */ - if ((state = dev->state) == STATE_SETUP) { + if ((state = dev->state) == STATE_DEV_SETUP) { if (dev->setup_in) { /* stall IN */ VDEBUG(dev, "ep0in stall\n"); (void) usb_ep_set_halt (dev->gadget->ep0); retval = -EL2HLT; - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; } else if (len == 0) { /* ack SET_CONFIGURATION etc */ struct usb_ep *ep = dev->gadget->ep0; @@ -1012,7 +1002,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) if ((retval = setup_req (ep, req, 0)) == 0) retval = usb_ep_queue (ep, req, GFP_ATOMIC); - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; /* assume that was SET_CONFIGURATION */ if (dev->current_config) { @@ -1040,6 +1030,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) spin_lock_irq (&dev->lock); if (retval) goto done; + + if (dev->state != STATE_DEV_SETUP) { + retval = -ECANCELED; + goto done; + } + dev->state = STATE_DEV_CONNECTED; + if (dev->setup_out_error) retval = -EIO; else { @@ -1066,39 +1063,36 @@ scan: /* return queued events right away */ if (dev->ev_next != 0) { unsigned i, n; - int tmp = dev->ev_next; - len = min (len, tmp * sizeof (struct usb_gadgetfs_event)); n = len / sizeof (struct usb_gadgetfs_event); + if (dev->ev_next < n) + n = dev->ev_next; - /* ep0 can't deliver events when STATE_SETUP */ + /* ep0 i/o has special semantics during STATE_DEV_SETUP */ for (i = 0; i < n; i++) { if (dev->event [i].type == GADGETFS_SETUP) { - len = i + 1; - len *= sizeof (struct usb_gadgetfs_event); - n = 0; + dev->state = STATE_DEV_SETUP; + n = i + 1; break; } } spin_unlock_irq (&dev->lock); + len = n * sizeof (struct usb_gadgetfs_event); if (copy_to_user (buf, &dev->event, len)) retval = -EFAULT; else retval = len; if (len > 0) { - len /= sizeof (struct usb_gadgetfs_event); - /* NOTE this doesn't guard against broken drivers; * concurrent ep0 readers may lose events. */ spin_lock_irq (&dev->lock); - dev->ev_next -= len; - if (dev->ev_next != 0) - memmove (&dev->event, &dev->event [len], + if (dev->ev_next > n) { + memmove(&dev->event[0], &dev->event[n], sizeof (struct usb_gadgetfs_event) - * (tmp - len)); - if (n == 0) - dev->state = STATE_SETUP; + * (dev->ev_next - n)); + } + dev->ev_next -= n; spin_unlock_irq (&dev->lock); } return retval; @@ -1113,8 +1107,8 @@ scan: DBG (dev, "fail %s, state %d\n", __FUNCTION__, state); retval = -ESRCH; break; - case STATE_UNCONNECTED: - case STATE_CONNECTED: + case STATE_DEV_UNCONNECTED: + case STATE_DEV_CONNECTED: spin_unlock_irq (&dev->lock); DBG (dev, "%s wait\n", __FUNCTION__); @@ -1141,7 +1135,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type) switch (type) { /* these events purge the queue */ case GADGETFS_DISCONNECT: - if (dev->state == STATE_SETUP) + if (dev->state == STATE_DEV_SETUP) dev->setup_abort = 1; // FALL THROUGH case GADGETFS_CONNECT: @@ -1153,7 +1147,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type) for (i = 0; i != dev->ev_next; i++) { if (dev->event [i].type != type) continue; - DBG (dev, "discard old event %d\n", type); + DBG(dev, "discard old event[%d] %d\n", i, type); dev->ev_next--; if (i == dev->ev_next) break; @@ -1166,9 +1160,9 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type) default: BUG (); } + VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type); event = &dev->event [dev->ev_next++]; BUG_ON (dev->ev_next > N_EVENT); - VDEBUG (dev, "ev %d, next %d\n", type, dev->ev_next); memset (event, 0, sizeof *event); event->type = type; return event; @@ -1188,12 +1182,13 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) retval = -EIDRM; /* data and/or status stage for control request */ - } else if (dev->state == STATE_SETUP) { + } else if (dev->state == STATE_DEV_SETUP) { /* IN DATA+STATUS caller makes len <= wLength */ if (dev->setup_in) { retval = setup_req (dev->gadget->ep0, dev->req, len); if (retval == 0) { + dev->state = STATE_DEV_CONNECTED; spin_unlock_irq (&dev->lock); if (copy_from_user (dev->req->buf, buf, len)) retval = -EFAULT; @@ -1219,7 +1214,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) VDEBUG(dev, "ep0out stall\n"); (void) usb_ep_set_halt (dev->gadget->ep0); retval = -EL2HLT; - dev->state = STATE_CONNECTED; + dev->state = STATE_DEV_CONNECTED; } else { DBG(dev, "bogus ep0out stall!\n"); } @@ -1261,7 +1256,9 @@ dev_release (struct inode *inode, struct file *fd) put_dev (dev); /* other endpoints were all decoupled from this device */ + spin_lock_irq(&dev->lock); dev->state = STATE_DEV_DISABLED; + spin_unlock_irq(&dev->lock); return 0; } @@ -1282,7 +1279,7 @@ ep0_poll (struct file *fd, poll_table *wait) goto out; } - if (dev->state == STATE_SETUP) { + if (dev->state == STATE_DEV_SETUP) { if (dev->setup_in || dev->setup_can_stall) mask = POLLOUT; } else { @@ -1392,52 +1389,29 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) spin_lock (&dev->lock); dev->setup_abort = 0; - if (dev->state == STATE_UNCONNECTED) { - struct usb_ep *ep; - struct ep_data *data; - - dev->state = STATE_CONNECTED; - dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; - + if (dev->state == STATE_DEV_UNCONNECTED) { #ifdef CONFIG_USB_GADGET_DUALSPEED if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) { + spin_unlock(&dev->lock); ERROR (dev, "no high speed config??\n"); return -EINVAL; } #endif /* CONFIG_USB_GADGET_DUALSPEED */ + dev->state = STATE_DEV_CONNECTED; + dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; + INFO (dev, "connected\n"); event = next_event (dev, GADGETFS_CONNECT); event->u.speed = gadget->speed; ep0_readable (dev); - list_for_each_entry (ep, &gadget->ep_list, ep_list) { - data = ep->driver_data; - /* ... down_trylock (&data->lock) ... */ - if (data->state != STATE_EP_DEFER_ENABLE) - continue; -#ifdef CONFIG_USB_GADGET_DUALSPEED - if (gadget->speed == USB_SPEED_HIGH) - value = usb_ep_enable (ep, &data->hs_desc); - else -#endif /* CONFIG_USB_GADGET_DUALSPEED */ - value = usb_ep_enable (ep, &data->desc); - if (value) { - ERROR (dev, "deferred %s enable --> %d\n", - data->name, value); - continue; - } - data->state = STATE_EP_ENABLED; - wake_up (&data->wait); - DBG (dev, "woke up %s waiters\n", data->name); - } - /* host may have given up waiting for response. we can miss control * requests handled lower down (device/endpoint status and features); * then ep0_{read,write} will report the wrong status. controller * driver will have aborted pending i/o. */ - } else if (dev->state == STATE_SETUP) + } else if (dev->state == STATE_DEV_SETUP) dev->setup_abort = 1; req->buf = dev->rbuf; @@ -1583,7 +1557,7 @@ delegate: } /* proceed with data transfer and status phases? */ - if (value >= 0 && dev->state != STATE_SETUP) { + if (value >= 0 && dev->state != STATE_DEV_SETUP) { req->length = value; req->zero = value < w_length; value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); @@ -1747,7 +1721,9 @@ gadgetfs_bind (struct usb_gadget *gadget) goto enomem; INFO (dev, "bound to %s driver\n", gadget->name); - dev->state = STATE_UNCONNECTED; + spin_lock_irq(&dev->lock); + dev->state = STATE_DEV_UNCONNECTED; + spin_unlock_irq(&dev->lock); get_dev (dev); return 0; @@ -1762,11 +1738,9 @@ gadgetfs_disconnect (struct usb_gadget *gadget) struct dev_data *dev = get_gadget_data (gadget); spin_lock (&dev->lock); - if (dev->state == STATE_UNCONNECTED) { - DBG (dev, "already unconnected\n"); + if (dev->state == STATE_DEV_UNCONNECTED) goto exit; - } - dev->state = STATE_UNCONNECTED; + dev->state = STATE_DEV_UNCONNECTED; INFO (dev, "disconnected\n"); next_event (dev, GADGETFS_DISCONNECT); @@ -1783,9 +1757,9 @@ gadgetfs_suspend (struct usb_gadget *gadget) INFO (dev, "suspended from state %d\n", dev->state); spin_lock (&dev->lock); switch (dev->state) { - case STATE_SETUP: // VERY odd... host died?? - case STATE_CONNECTED: - case STATE_UNCONNECTED: + case STATE_DEV_SETUP: // VERY odd... host died?? + case STATE_DEV_CONNECTED: + case STATE_DEV_UNCONNECTED: next_event (dev, GADGETFS_SUSPEND); ep0_readable (dev); /* FALLTHROUGH */ @@ -1808,7 +1782,7 @@ static struct usb_gadget_driver gadgetfs_driver = { .disconnect = gadgetfs_disconnect, .suspend = gadgetfs_suspend, - .driver = { + .driver = { .name = (char *) shortname, }, }; @@ -1829,7 +1803,7 @@ static struct usb_gadget_driver probe_driver = { .unbind = gadgetfs_nop, .setup = (void *)gadgetfs_nop, .disconnect = gadgetfs_nop, - .driver = { + .driver = { .name = "nop", }, }; @@ -1849,19 +1823,16 @@ static struct usb_gadget_driver probe_driver = { * . full/low speed config ... all wTotalLength bytes (with interface, * class, altsetting, endpoint, and other descriptors) * . high speed config ... all descriptors, for high speed operation; - * this one's optional except for high-speed hardware + * this one's optional except for high-speed hardware * . device descriptor * - * Endpoints are not yet enabled. Drivers may want to immediately - * initialize them, using the /dev/gadget/ep* files that are available - * as soon as the kernel sees the configuration, or they can wait - * until device configuration and interface altsetting changes create + * Endpoints are not yet enabled. Drivers must wait until device + * configuration and interface altsetting changes create * the need to configure (or unconfigure) them. * * After initialization, the device stays active for as long as that - * $CHIP file is open. Events may then be read from that descriptor, - * such as configuration notifications. More complex drivers will handle - * some control requests in user space. + * $CHIP file is open. Events must then be read from that descriptor, + * such as configuration notifications. */ static int is_valid_config (struct usb_config_descriptor *config) @@ -1884,9 +1855,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) u32 tag; char *kbuf; - if (dev->state != STATE_OPENED) - return -EEXIST; - if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4)) return -EINVAL; @@ -1978,13 +1946,15 @@ dev_open (struct inode *inode, struct file *fd) struct dev_data *dev = inode->i_private; int value = -EBUSY; + spin_lock_irq(&dev->lock); if (dev->state == STATE_DEV_DISABLED) { dev->ev_next = 0; - dev->state = STATE_OPENED; + dev->state = STATE_DEV_OPENED; fd->private_data = dev; get_dev (dev); value = 0; } + spin_unlock_irq(&dev->lock); return value; } 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/host/Kconfig b/drivers/usb/host/Kconfig index cc60759083bf..62711870f8ee 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -67,6 +67,11 @@ config USB_EHCI_TT_NEWSCHED If unsure, say N. +config USB_EHCI_BIG_ENDIAN_MMIO + bool + depends on USB_EHCI_HCD + default n + config USB_ISP116X_HCD tristate "ISP116X HCD support" depends on USB @@ -101,21 +106,48 @@ config USB_OHCI_HCD_PPC_SOC bool "OHCI support for on-chip PPC USB controller" depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx) default y - select USB_OHCI_BIG_ENDIAN + select USB_OHCI_BIG_ENDIAN_DESC + select USB_OHCI_BIG_ENDIAN_MMIO ---help--- Enables support for the USB controller on the MPC52xx or STB03xxx processor chip. If unsure, say Y. +config USB_OHCI_HCD_PPC_OF + bool "OHCI support for PPC USB controller on OF platform bus" + depends on USB_OHCI_HCD && PPC_OF + default y + ---help--- + Enables support for the USB controller PowerPC present on the + OpenFirmware platform bus. + +config USB_OHCI_HCD_PPC_OF_BE + bool "Support big endian HC" + depends on USB_OHCI_HCD_PPC_OF + default y + select USB_OHCI_BIG_ENDIAN_DESC + select USB_OHCI_BIG_ENDIAN_MMIO + +config USB_OHCI_HCD_PPC_OF_LE + bool "Support little endian HC" + depends on USB_OHCI_HCD_PPC_OF + default n + select USB_OHCI_LITTLE_ENDIAN + config USB_OHCI_HCD_PCI bool "OHCI support for PCI-bus USB controllers" - depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx) + depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF) default y select USB_OHCI_LITTLE_ENDIAN ---help--- Enables support for PCI-bus plug-in USB controller cards. If unsure, say Y. -config USB_OHCI_BIG_ENDIAN +config USB_OHCI_BIG_ENDIAN_DESC + bool + depends on USB_OHCI_HCD + default n + +config USB_OHCI_BIG_ENDIAN_MMIO bool depends on USB_OHCI_HCD default n diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 56349d21e6ea..246afea9e83b 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -43,7 +43,7 @@ */ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label) { - u32 params = readl (&ehci->caps->hcs_params); + u32 params = ehci_readl(ehci, &ehci->caps->hcs_params); ehci_dbg (ehci, "%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n", @@ -87,7 +87,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {} * */ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label) { - u32 params = readl (&ehci->caps->hcc_params); + u32 params = ehci_readl(ehci, &ehci->caps->hcc_params); if (HCC_ISOC_CACHE (params)) { ehci_dbg (ehci, @@ -653,7 +653,7 @@ show_registers (struct class_device *class_dev, char *buf) } /* Capability Registers */ - i = HC_VERSION(readl (&ehci->caps->hc_capbase)); + i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); temp = scnprintf (next, size, "bus %s, device %s (driver " DRIVER_VERSION ")\n" "%s\n" @@ -673,7 +673,7 @@ show_registers (struct class_device *class_dev, char *buf) unsigned count = 256/4; pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); - offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); + offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params)); while (offset && count--) { pci_read_config_dword (pdev, offset, &cap); switch (cap & 0xff) { @@ -704,50 +704,50 @@ show_registers (struct class_device *class_dev, char *buf) #endif // FIXME interpret both types of params - i = readl (&ehci->caps->hcs_params); + i = ehci_readl(ehci, &ehci->caps->hcs_params); temp = scnprintf (next, size, "structural params 0x%08x\n", i); size -= temp; next += temp; - i = readl (&ehci->caps->hcc_params); + i = ehci_readl(ehci, &ehci->caps->hcc_params); temp = scnprintf (next, size, "capability params 0x%08x\n", i); size -= temp; next += temp; /* Operational Registers */ temp = dbg_status_buf (scratch, sizeof scratch, label, - readl (&ehci->regs->status)); + ehci_readl(ehci, &ehci->regs->status)); temp = scnprintf (next, size, fmt, temp, scratch); size -= temp; next += temp; temp = dbg_command_buf (scratch, sizeof scratch, label, - readl (&ehci->regs->command)); + ehci_readl(ehci, &ehci->regs->command)); temp = scnprintf (next, size, fmt, temp, scratch); size -= temp; next += temp; temp = dbg_intr_buf (scratch, sizeof scratch, label, - readl (&ehci->regs->intr_enable)); + ehci_readl(ehci, &ehci->regs->intr_enable)); temp = scnprintf (next, size, fmt, temp, scratch); size -= temp; next += temp; temp = scnprintf (next, size, "uframe %04x\n", - readl (&ehci->regs->frame_index)); + ehci_readl(ehci, &ehci->regs->frame_index)); size -= temp; next += temp; for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) { temp = dbg_port_buf (scratch, sizeof scratch, label, i, - readl (&ehci->regs->port_status [i - 1])); + ehci_readl(ehci, &ehci->regs->port_status [i - 1])); temp = scnprintf (next, size, fmt, temp, scratch); size -= temp; next += temp; if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) { temp = scnprintf (next, size, " debug control %08x\n", - readl (&ehci->debug->control)); + ehci_readl(ehci, &ehci->debug->control)); size -= temp; next += temp; } diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 1a915e982c1c..a52480505f78 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -177,7 +177,7 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci, case FSL_USB2_PHY_NONE: break; } - writel(portsc, &ehci->regs->port_status[port_offset]); + ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); } static void mpc83xx_usb_setup(struct usb_hcd *hcd) @@ -214,7 +214,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd) } /* put controller in host mode. */ - writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE); + ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE); out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c); out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040); out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); @@ -238,12 +238,12 @@ static int ehci_fsl_setup(struct usb_hcd *hcd) /* EHCI registers start at offset 0x100 */ ehci->caps = hcd->regs + 0x100; ehci->regs = hcd->regs + 0x100 + - HC_LENGTH(readl(&ehci->caps->hc_capbase)); + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); dbg_hcs_params(ehci, "reset"); dbg_hcc_params(ehci, "reset"); /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = readl(&ehci->caps->hcs_params); + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); retval = ehci_halt(ehci); if (retval) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 025d33313681..185721dba42b 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -157,12 +157,13 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); * before driver shutdown. But it also seems to be caused by bugs in cardbus * bridge shutdown: shutting down the bridge before the devices using it. */ -static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec) +static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, + u32 mask, u32 done, int usec) { u32 result; do { - result = readl (ptr); + result = ehci_readl(ehci, ptr); if (result == ~(u32)0) /* card removed */ return -ENODEV; result &= mask; @@ -177,18 +178,19 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec) /* force HC to halt state from unknown (EHCI spec section 2.3) */ static int ehci_halt (struct ehci_hcd *ehci) { - u32 temp = readl (&ehci->regs->status); + u32 temp = ehci_readl(ehci, &ehci->regs->status); /* disable any irqs left enabled by previous code */ - writel (0, &ehci->regs->intr_enable); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); if ((temp & STS_HALT) != 0) return 0; - temp = readl (&ehci->regs->command); + temp = ehci_readl(ehci, &ehci->regs->command); temp &= ~CMD_RUN; - writel (temp, &ehci->regs->command); - return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125); + ehci_writel(ehci, temp, &ehci->regs->command); + return handshake (ehci, &ehci->regs->status, + STS_HALT, STS_HALT, 16 * 125); } /* put TDI/ARC silicon into EHCI mode */ @@ -198,23 +200,24 @@ static void tdi_reset (struct ehci_hcd *ehci) u32 tmp; reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68); - tmp = readl (reg_ptr); + tmp = ehci_readl(ehci, reg_ptr); tmp |= 0x3; - writel (tmp, reg_ptr); + ehci_writel(ehci, tmp, reg_ptr); } /* reset a non-running (STS_HALT == 1) controller */ static int ehci_reset (struct ehci_hcd *ehci) { int retval; - u32 command = readl (&ehci->regs->command); + u32 command = ehci_readl(ehci, &ehci->regs->command); command |= CMD_RESET; dbg_cmd (ehci, "reset", command); - writel (command, &ehci->regs->command); + ehci_writel(ehci, command, &ehci->regs->command); ehci_to_hcd(ehci)->state = HC_STATE_HALT; ehci->next_statechange = jiffies; - retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000); + retval = handshake (ehci, &ehci->regs->command, + CMD_RESET, 0, 250 * 1000); if (retval) return retval; @@ -236,21 +239,21 @@ static void ehci_quiesce (struct ehci_hcd *ehci) #endif /* wait for any schedule enables/disables to take effect */ - temp = readl (&ehci->regs->command) << 10; + temp = ehci_readl(ehci, &ehci->regs->command) << 10; temp &= STS_ASS | STS_PSS; - if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, + if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS, temp, 16 * 125) != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return; } /* then disable anything that's still active */ - temp = readl (&ehci->regs->command); + temp = ehci_readl(ehci, &ehci->regs->command); temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); - writel (temp, &ehci->regs->command); + ehci_writel(ehci, temp, &ehci->regs->command); /* hardware can take 16 microframes to turn off ... */ - if (handshake (&ehci->regs->status, STS_ASS | STS_PSS, + if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS, 0, 16 * 125) != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return; @@ -277,11 +280,11 @@ static void ehci_watchdog (unsigned long param) /* lost IAA irqs wedge things badly; seen with a vt8235 */ if (ehci->reclaim) { - u32 status = readl (&ehci->regs->status); + u32 status = ehci_readl(ehci, &ehci->regs->status); if (status & STS_IAA) { ehci_vdbg (ehci, "lost IAA\n"); COUNT (ehci->stats.lost_iaa); - writel (STS_IAA, &ehci->regs->status); + ehci_writel(ehci, STS_IAA, &ehci->regs->status); ehci->reclaim_ready = 1; } } @@ -309,7 +312,7 @@ ehci_shutdown (struct usb_hcd *hcd) (void) ehci_halt (ehci); /* make BIOS/etc use companion controller during reboot */ - writel (0, &ehci->regs->configured_flag); + ehci_writel(ehci, 0, &ehci->regs->configured_flag); } static void ehci_port_power (struct ehci_hcd *ehci, int is_on) @@ -379,12 +382,13 @@ static void ehci_stop (struct usb_hcd *hcd) ehci_quiesce (ehci); ehci_reset (ehci); - writel (0, &ehci->regs->intr_enable); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); spin_unlock_irq(&ehci->lock); /* let companion controllers work when we aren't */ - writel (0, &ehci->regs->configured_flag); + ehci_writel(ehci, 0, &ehci->regs->configured_flag); + remove_companion_file(ehci); remove_debug_files (ehci); /* root hub is shut down separately (first, when possible) */ @@ -402,7 +406,8 @@ static void ehci_stop (struct usb_hcd *hcd) ehci->stats.complete, ehci->stats.unlink); #endif - dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status)); + dbg_status (ehci, "ehci_stop completed", + ehci_readl(ehci, &ehci->regs->status)); } /* one-time init, only for memory state */ @@ -428,7 +433,7 @@ static int ehci_init(struct usb_hcd *hcd) return retval; /* controllers may cache some of the periodic schedule ... */ - hcc_params = readl(&ehci->caps->hcc_params); + hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); if (HCC_ISOC_CACHE(hcc_params)) // full frame cache ehci->i_thresh = 8; else // N microframes cached @@ -496,13 +501,16 @@ static int ehci_run (struct usb_hcd *hcd) u32 temp; u32 hcc_params; + hcd->uses_new_polling = 1; + hcd->poll_rh = 0; + /* EHCI spec section 4.1 */ if ((retval = ehci_reset(ehci)) != 0) { ehci_mem_cleanup(ehci); return retval; } - writel(ehci->periodic_dma, &ehci->regs->frame_list); - writel((u32)ehci->async->qh_dma, &ehci->regs->async_next); + ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); + ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next); /* * hcc_params controls whether ehci->regs->segment must (!!!) @@ -516,9 +524,9 @@ static int ehci_run (struct usb_hcd *hcd) * Scsi_Host.highmem_io, and so forth. It's readonly to all * host side drivers though. */ - hcc_params = readl(&ehci->caps->hcc_params); + hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); if (HCC_64BIT_ADDR(hcc_params)) { - writel(0, &ehci->regs->segment); + ehci_writel(ehci, 0, &ehci->regs->segment); #if 0 // this is deeply broken on almost all architectures if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK)) @@ -531,7 +539,7 @@ static int ehci_run (struct usb_hcd *hcd) // root hub will detect new devices (why?); NEC doesn't ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); ehci->command |= CMD_RUN; - writel (ehci->command, &ehci->regs->command); + ehci_writel(ehci, ehci->command, &ehci->regs->command); dbg_cmd (ehci, "init", ehci->command); /* @@ -541,23 +549,25 @@ static int ehci_run (struct usb_hcd *hcd) * and there's no companion controller unless maybe for USB OTG.) */ hcd->state = HC_STATE_RUNNING; - writel (FLAG_CF, &ehci->regs->configured_flag); - readl (&ehci->regs->command); /* unblock posted writes */ + ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); + ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ - temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); + temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci_info (ehci, "USB %x.%x started, EHCI %x.%02x, driver %s%s\n", ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), temp >> 8, temp & 0xff, DRIVER_VERSION, ignore_oc ? ", overcurrent ignored" : ""); - writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ + ehci_writel(ehci, INTR_MASK, + &ehci->regs->intr_enable); /* Turn On Interrupts */ /* GRR this is run-once init(), being done every time the HC starts. * So long as they're part of class devices, we can't do it init() * since the class device isn't created that early. */ create_debug_files(ehci); + create_companion_file(ehci); return 0; } @@ -567,12 +577,12 @@ static int ehci_run (struct usb_hcd *hcd) static irqreturn_t ehci_irq (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); - u32 status; + u32 status, pcd_status = 0; int bh; spin_lock (&ehci->lock); - status = readl (&ehci->regs->status); + status = ehci_readl(ehci, &ehci->regs->status); /* e.g. cardbus physical eject */ if (status == ~(u32) 0) { @@ -587,8 +597,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) } /* clear (just) interrupts */ - writel (status, &ehci->regs->status); - readl (&ehci->regs->command); /* unblock posted write */ + ehci_writel(ehci, status, &ehci->regs->status); + ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */ bh = 0; #ifdef EHCI_VERBOSE_DEBUG @@ -617,13 +627,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* remote wakeup [4.3.1] */ if (status & STS_PCD) { unsigned i = HCS_N_PORTS (ehci->hcs_params); + pcd_status = status; /* resume root hub? */ - if (!(readl(&ehci->regs->command) & CMD_RUN)) + if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN)) usb_hcd_resume_root_hub(hcd); while (i--) { - int pstatus = readl (&ehci->regs->port_status [i]); + int pstatus = ehci_readl(ehci, + &ehci->regs->port_status [i]); if (pstatus & PORT_OWNER) continue; @@ -643,14 +655,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* PCI errors [4.15.2.4] */ if (unlikely ((status & STS_FATAL) != 0)) { /* bogus "fatal" IRQs appear on some chips... why? */ - status = readl (&ehci->regs->status); - dbg_cmd (ehci, "fatal", readl (&ehci->regs->command)); + status = ehci_readl(ehci, &ehci->regs->status); + dbg_cmd (ehci, "fatal", ehci_readl(ehci, + &ehci->regs->command)); dbg_status (ehci, "fatal", status); if (status & STS_HALT) { ehci_err (ehci, "fatal error\n"); dead: ehci_reset (ehci); - writel (0, &ehci->regs->configured_flag); + ehci_writel(ehci, 0, &ehci->regs->configured_flag); /* generic layer kills/unlinks all urbs, then * uses ehci_stop to clean up the rest */ @@ -661,6 +674,8 @@ dead: if (bh) ehci_work (ehci); spin_unlock (&ehci->lock); + if (pcd_status & STS_PCD) + usb_hcd_poll_rh_status(hcd); return IRQ_HANDLED; } @@ -873,7 +888,8 @@ done: static int ehci_get_frame (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); - return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size; + return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) % + ehci->periodic_size; } /*-------------------------------------------------------------------------*/ @@ -899,7 +915,13 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_hcd_au1xxx_driver #endif -#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) +#ifdef CONFIG_PPC_PS3 +#include "ehci-ps3.c" +#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_sb_driver +#endif + +#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ + !defined(PS3_SYSTEM_BUS_DRIVER) #error "missing bus glue for ehci-hcd" #endif @@ -924,6 +946,20 @@ static int __init ehci_hcd_init(void) #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); #endif + return retval; + } +#endif + +#ifdef PS3_SYSTEM_BUS_DRIVER + retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER); + if (retval < 0) { +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); +#endif +#ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); +#endif + return retval; } #endif @@ -939,6 +975,9 @@ static void __exit ehci_hcd_cleanup(void) #ifdef PCI_DRIVER pci_unregister_driver(&PCI_DRIVER); #endif +#ifdef PS3_SYSTEM_BUS_DRIVER + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); +#endif } module_exit(ehci_hcd_cleanup); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index bfe5f307cba6..0d83c6df1a3b 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -47,7 +47,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) ehci_quiesce (ehci); hcd->state = HC_STATE_QUIESCING; } - ehci->command = readl (&ehci->regs->command); + ehci->command = ehci_readl(ehci, &ehci->regs->command); if (ehci->reclaim) ehci->reclaim_ready = 1; ehci_work(ehci); @@ -60,7 +60,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) ehci->bus_suspended = 0; while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; - u32 t1 = readl (reg) & ~PORT_RWC_BITS; + u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; u32 t2 = t1; /* keep track of which ports we suspend */ @@ -79,7 +79,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) if (t1 != t2) { ehci_vdbg (ehci, "port %d, %08x -> %08x\n", port + 1, t1, t2); - writel (t2, reg); + ehci_writel(ehci, t2, reg); } } @@ -92,8 +92,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) mask = INTR_MASK; if (!device_may_wakeup(&hcd->self.root_hub->dev)) mask &= ~STS_PCD; - writel(mask, &ehci->regs->intr_enable); - readl(&ehci->regs->intr_enable); + ehci_writel(ehci, mask, &ehci->regs->intr_enable); + ehci_readl(ehci, &ehci->regs->intr_enable); ehci->next_statechange = jiffies + msecs_to_jiffies(10); spin_unlock_irq (&ehci->lock); @@ -118,26 +118,26 @@ static int ehci_bus_resume (struct usb_hcd *hcd) * the last user of the controller, not reset/pm hardware keeping * state we gave to it. */ - temp = readl(&ehci->regs->intr_enable); + temp = ehci_readl(ehci, &ehci->regs->intr_enable); ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss"); /* at least some APM implementations will try to deliver * IRQs right away, so delay them until we're ready. */ - writel(0, &ehci->regs->intr_enable); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); /* re-init operational registers */ - writel(0, &ehci->regs->segment); - writel(ehci->periodic_dma, &ehci->regs->frame_list); - writel((u32) ehci->async->qh_dma, &ehci->regs->async_next); + ehci_writel(ehci, 0, &ehci->regs->segment); + ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); + ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next); /* restore CMD_RUN, framelist size, and irq threshold */ - writel (ehci->command, &ehci->regs->command); + ehci_writel(ehci, ehci->command, &ehci->regs->command); /* manually resume the ports we suspended during bus_suspend() */ i = HCS_N_PORTS (ehci->hcs_params); while (i--) { - temp = readl (&ehci->regs->port_status [i]); + temp = ehci_readl(ehci, &ehci->regs->port_status [i]); temp &= ~(PORT_RWC_BITS | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E); if (test_bit(i, &ehci->bus_suspended) && @@ -145,20 +145,20 @@ static int ehci_bus_resume (struct usb_hcd *hcd) ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); temp |= PORT_RESUME; } - writel (temp, &ehci->regs->port_status [i]); + ehci_writel(ehci, temp, &ehci->regs->port_status [i]); } i = HCS_N_PORTS (ehci->hcs_params); mdelay (20); while (i--) { - temp = readl (&ehci->regs->port_status [i]); + temp = ehci_readl(ehci, &ehci->regs->port_status [i]); if (test_bit(i, &ehci->bus_suspended) && (temp & PORT_SUSPEND)) { temp &= ~(PORT_RWC_BITS | PORT_RESUME); - writel (temp, &ehci->regs->port_status [i]); + ehci_writel(ehci, temp, &ehci->regs->port_status [i]); ehci_vdbg (ehci, "resumed port %d\n", i + 1); } } - (void) readl (&ehci->regs->command); + (void) ehci_readl(ehci, &ehci->regs->command); /* maybe re-activate the schedule(s) */ temp = 0; @@ -168,14 +168,14 @@ static int ehci_bus_resume (struct usb_hcd *hcd) temp |= CMD_PSE; if (temp) { ehci->command |= temp; - writel (ehci->command, &ehci->regs->command); + ehci_writel(ehci, ehci->command, &ehci->regs->command); } ehci->next_statechange = jiffies + msecs_to_jiffies(5); hcd->state = HC_STATE_RUNNING; /* Now we can safely re-enable irqs */ - writel(INTR_MASK, &ehci->regs->intr_enable); + ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); spin_unlock_irq (&ehci->lock); return 0; @@ -188,11 +188,109 @@ static int ehci_bus_resume (struct usb_hcd *hcd) #endif /* CONFIG_PM */ +/*-------------------------------------------------------------------------*/ + +/* Display the ports dedicated to the companion controller */ +static ssize_t show_companion(struct class_device *class_dev, char *buf) +{ + struct ehci_hcd *ehci; + int nports, index, n; + int count = PAGE_SIZE; + char *ptr = buf; + + ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev))); + nports = HCS_N_PORTS(ehci->hcs_params); + + for (index = 0; index < nports; ++index) { + if (test_bit(index, &ehci->companion_ports)) { + n = scnprintf(ptr, count, "%d\n", index + 1); + ptr += n; + count -= n; + } + } + return ptr - buf; +} + +/* + * Dedicate or undedicate a port to the companion controller. + * Syntax is "[-]portnum", where a leading '-' sign means + * return control of the port to the EHCI controller. + */ +static ssize_t store_companion(struct class_device *class_dev, + const char *buf, size_t count) +{ + struct ehci_hcd *ehci; + int portnum, new_owner, try; + u32 __iomem *status_reg; + u32 port_status; + + ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev))); + new_owner = PORT_OWNER; /* Owned by companion */ + if (sscanf(buf, "%d", &portnum) != 1) + return -EINVAL; + if (portnum < 0) { + portnum = - portnum; + new_owner = 0; /* Owned by EHCI */ + } + if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) + return -ENOENT; + status_reg = &ehci->regs->port_status[--portnum]; + if (new_owner) + set_bit(portnum, &ehci->companion_ports); + else + clear_bit(portnum, &ehci->companion_ports); + + /* + * The controller won't set the OWNER bit if the port is + * enabled, so this loop will sometimes require at least two + * iterations: one to disable the port and one to set OWNER. + */ + + for (try = 4; try > 0; --try) { + spin_lock_irq(&ehci->lock); + port_status = ehci_readl(ehci, status_reg); + if ((port_status & PORT_OWNER) == new_owner + || (port_status & (PORT_OWNER | PORT_CONNECT)) + == 0) + try = 0; + else { + port_status ^= PORT_OWNER; + port_status &= ~(PORT_PE | PORT_RWC_BITS); + ehci_writel(ehci, port_status, status_reg); + } + spin_unlock_irq(&ehci->lock); + if (try > 1) + msleep(5); + } + return count; +} +static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion); + +static inline void create_companion_file(struct ehci_hcd *ehci) +{ + int i; + + /* with integrated TT there is no companion! */ + if (!ehci_is_TDI(ehci)) + i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev, + &class_device_attr_companion); +} + +static inline void remove_companion_file(struct ehci_hcd *ehci) +{ + /* with integrated TT there is no companion! */ + if (!ehci_is_TDI(ehci)) + class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev, + &class_device_attr_companion); +} + + /*-------------------------------------------------------------------------*/ static int check_reset_complete ( struct ehci_hcd *ehci, int index, + u32 __iomem *status_reg, int port_status ) { if (!(port_status & PORT_CONNECT)) { @@ -217,7 +315,7 @@ static int check_reset_complete ( // what happens if HCS_N_CC(params) == 0 ? port_status |= PORT_OWNER; port_status &= ~PORT_RWC_BITS; - writel (port_status, &ehci->regs->port_status [index]); + ehci_writel(ehci, port_status, status_reg); } else ehci_dbg (ehci, "port %d high speed\n", index + 1); @@ -268,22 +366,21 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) /* port N changes (bit N)? */ spin_lock_irqsave (&ehci->lock, flags); for (i = 0; i < ports; i++) { - temp = readl (&ehci->regs->port_status [i]); - if (temp & PORT_OWNER) { - /* don't report this in GetPortStatus */ - if (temp & PORT_CSC) { - temp &= ~PORT_RWC_BITS; - temp |= PORT_CSC; - writel (temp, &ehci->regs->port_status [i]); - } - continue; - } + temp = ehci_readl(ehci, &ehci->regs->port_status [i]); + + /* + * Return status information even for ports with OWNER set. + * Otherwise khubd wouldn't see the disconnect event when a + * high-speed device is switched over to the companion + * controller by the user. + */ + if (!(temp & PORT_CONNECT)) ehci->reset_done [i] = 0; if ((temp & mask) != 0 || ((temp & PORT_RESUME) != 0 - && time_after (jiffies, - ehci->reset_done [i]))) { + && time_after_eq(jiffies, + ehci->reset_done[i]))) { if (i < 7) buf [0] |= 1 << (i + 1); else @@ -345,6 +442,7 @@ static int ehci_hub_control ( ) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); int ports = HCS_N_PORTS (ehci->hcs_params); + u32 __iomem *status_reg = &ehci->regs->port_status[wIndex - 1]; u32 temp, status; unsigned long flags; int retval = 0; @@ -373,18 +471,22 @@ static int ehci_hub_control ( if (!wIndex || wIndex > ports) goto error; wIndex--; - temp = readl (&ehci->regs->port_status [wIndex]); - if (temp & PORT_OWNER) - break; + temp = ehci_readl(ehci, status_reg); + + /* + * Even if OWNER is set, so the port is owned by the + * companion controller, khubd needs to be able to clear + * the port-change status bits (especially + * USB_PORT_FEAT_C_CONNECTION). + */ switch (wValue) { case USB_PORT_FEAT_ENABLE: - writel (temp & ~PORT_PE, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp & ~PORT_PE, status_reg); break; case USB_PORT_FEAT_C_ENABLE: - writel((temp & ~PORT_RWC_BITS) | PORT_PEC, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC, + status_reg); break; case USB_PORT_FEAT_SUSPEND: if (temp & PORT_RESET) @@ -396,8 +498,8 @@ static int ehci_hub_control ( goto error; /* resume signaling for 20 msec */ temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); - writel (temp | PORT_RESUME, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp | PORT_RESUME, + status_reg); ehci->reset_done [wIndex] = jiffies + msecs_to_jiffies (20); } @@ -407,16 +509,17 @@ static int ehci_hub_control ( break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) - writel (temp & ~(PORT_RWC_BITS | PORT_POWER), - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, + temp & ~(PORT_RWC_BITS | PORT_POWER), + status_reg); break; case USB_PORT_FEAT_C_CONNECTION: - writel((temp & ~PORT_RWC_BITS) | PORT_CSC, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC, + status_reg); break; case USB_PORT_FEAT_C_OVER_CURRENT: - writel((temp & ~PORT_RWC_BITS) | PORT_OCC, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC, + status_reg); break; case USB_PORT_FEAT_C_RESET: /* GetPortStatus clears reset */ @@ -424,7 +527,7 @@ static int ehci_hub_control ( default: goto error; } - readl (&ehci->regs->command); /* unblock posted write */ + ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */ break; case GetHubDescriptor: ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *) @@ -440,7 +543,7 @@ static int ehci_hub_control ( goto error; wIndex--; status = 0; - temp = readl (&ehci->regs->port_status [wIndex]); + temp = ehci_readl(ehci, status_reg); // wPortChange bits if (temp & PORT_CSC) @@ -451,42 +554,55 @@ static int ehci_hub_control ( status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT; /* whoever resumes must GetPortStatus to complete it!! */ - if ((temp & PORT_RESUME) - && time_after (jiffies, - ehci->reset_done [wIndex])) { - status |= 1 << USB_PORT_FEAT_C_SUSPEND; - ehci->reset_done [wIndex] = 0; + if (temp & PORT_RESUME) { - /* stop resume signaling */ - temp = readl (&ehci->regs->port_status [wIndex]); - writel (temp & ~(PORT_RWC_BITS | PORT_RESUME), - &ehci->regs->port_status [wIndex]); - retval = handshake ( - &ehci->regs->port_status [wIndex], - PORT_RESUME, 0, 2000 /* 2msec */); - if (retval != 0) { - ehci_err (ehci, "port %d resume error %d\n", - wIndex + 1, retval); - goto error; + /* Remote Wakeup received? */ + if (!ehci->reset_done[wIndex]) { + /* resume signaling for 20 msec */ + ehci->reset_done[wIndex] = jiffies + + msecs_to_jiffies(20); + /* check the port again */ + mod_timer(&ehci_to_hcd(ehci)->rh_timer, + ehci->reset_done[wIndex]); + } + + /* resume completed? */ + else if (time_after_eq(jiffies, + ehci->reset_done[wIndex])) { + status |= 1 << USB_PORT_FEAT_C_SUSPEND; + ehci->reset_done[wIndex] = 0; + + /* stop resume signaling */ + temp = ehci_readl(ehci, status_reg); + ehci_writel(ehci, + temp & ~(PORT_RWC_BITS | PORT_RESUME), + status_reg); + retval = handshake(ehci, status_reg, + PORT_RESUME, 0, 2000 /* 2msec */); + if (retval != 0) { + ehci_err(ehci, + "port %d resume error %d\n", + wIndex + 1, retval); + goto error; + } + temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); } - temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); } /* whoever resets must GetPortStatus to complete it!! */ if ((temp & PORT_RESET) - && time_after (jiffies, - ehci->reset_done [wIndex])) { + && time_after_eq(jiffies, + ehci->reset_done[wIndex])) { status |= 1 << USB_PORT_FEAT_C_RESET; ehci->reset_done [wIndex] = 0; /* force reset to complete */ - writel (temp & ~(PORT_RWC_BITS | PORT_RESET), - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET), + status_reg); /* REVISIT: some hardware needs 550+ usec to clear * this bit; seems too long to spin routinely... */ - retval = handshake ( - &ehci->regs->port_status [wIndex], + retval = handshake(ehci, status_reg, PORT_RESET, 0, 750); if (retval != 0) { ehci_err (ehci, "port %d reset error %d\n", @@ -495,29 +611,42 @@ static int ehci_hub_control ( } /* see what we found out */ - temp = check_reset_complete (ehci, wIndex, - readl (&ehci->regs->port_status [wIndex])); + temp = check_reset_complete (ehci, wIndex, status_reg, + ehci_readl(ehci, status_reg)); } - // don't show wPortStatus if it's owned by a companion hc - if (!(temp & PORT_OWNER)) { - if (temp & PORT_CONNECT) { - status |= 1 << USB_PORT_FEAT_CONNECTION; - // status may be from integrated TT - status |= ehci_port_speed(ehci, temp); - } - if (temp & PORT_PE) - status |= 1 << USB_PORT_FEAT_ENABLE; - if (temp & (PORT_SUSPEND|PORT_RESUME)) - status |= 1 << USB_PORT_FEAT_SUSPEND; - if (temp & PORT_OC) - status |= 1 << USB_PORT_FEAT_OVER_CURRENT; - if (temp & PORT_RESET) - status |= 1 << USB_PORT_FEAT_RESET; - if (temp & PORT_POWER) - status |= 1 << USB_PORT_FEAT_POWER; + /* transfer dedicated ports to the companion hc */ + if ((temp & PORT_CONNECT) && + test_bit(wIndex, &ehci->companion_ports)) { + temp &= ~PORT_RWC_BITS; + temp |= PORT_OWNER; + ehci_writel(ehci, temp, status_reg); + ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1); + temp = ehci_readl(ehci, status_reg); } + /* + * Even if OWNER is set, there's no harm letting khubd + * see the wPortStatus values (they should all be 0 except + * for PORT_POWER anyway). + */ + + if (temp & PORT_CONNECT) { + status |= 1 << USB_PORT_FEAT_CONNECTION; + // status may be from integrated TT + status |= ehci_port_speed(ehci, temp); + } + if (temp & PORT_PE) + status |= 1 << USB_PORT_FEAT_ENABLE; + if (temp & (PORT_SUSPEND|PORT_RESUME)) + status |= 1 << USB_PORT_FEAT_SUSPEND; + if (temp & PORT_OC) + status |= 1 << USB_PORT_FEAT_OVER_CURRENT; + if (temp & PORT_RESET) + status |= 1 << USB_PORT_FEAT_RESET; + if (temp & PORT_POWER) + status |= 1 << USB_PORT_FEAT_POWER; + #ifndef EHCI_VERBOSE_DEBUG if (status & ~0xffff) /* only if wPortChange is interesting */ #endif @@ -541,7 +670,7 @@ static int ehci_hub_control ( if (!wIndex || wIndex > ports) goto error; wIndex--; - temp = readl (&ehci->regs->port_status [wIndex]); + temp = ehci_readl(ehci, status_reg); if (temp & PORT_OWNER) break; @@ -555,13 +684,12 @@ static int ehci_hub_control ( goto error; if (device_may_wakeup(&hcd->self.root_hub->dev)) temp |= PORT_WAKE_BITS; - writel (temp | PORT_SUSPEND, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) - writel (temp | PORT_POWER, - &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp | PORT_POWER, + status_reg); break; case USB_PORT_FEAT_RESET: if (temp & PORT_RESUME) @@ -589,7 +717,7 @@ static int ehci_hub_control ( ehci->reset_done [wIndex] = jiffies + msecs_to_jiffies (50); } - writel (temp, &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp, status_reg); break; /* For downstream facing ports (these): one hub port is put @@ -604,13 +732,13 @@ static int ehci_hub_control ( ehci_quiesce(ehci); ehci_halt(ehci); temp |= selector << 16; - writel (temp, &ehci->regs->port_status [wIndex]); + ehci_writel(ehci, temp, status_reg); break; default: goto error; } - readl (&ehci->regs->command); /* unblock posted writes */ + ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ break; default: diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 4bc7970ba3ef..12edc723ec73 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -38,7 +38,7 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) if ((temp & (3 << 13)) == (1 << 13)) { temp &= 0x1fff; ehci->debug = ehci_to_hcd(ehci)->regs + temp; - temp = readl(&ehci->debug->control); + temp = ehci_readl(ehci, &ehci->debug->control); ehci_info(ehci, "debug port %d%s\n", HCS_DEBUG_PORT(ehci->hcs_params), (temp & DBGP_ENABLED) @@ -71,8 +71,24 @@ static int ehci_pci_setup(struct usb_hcd *hcd) u32 temp; int retval; + switch (pdev->vendor) { + case PCI_VENDOR_ID_TOSHIBA_2: + /* celleb's companion chip */ + if (pdev->device == 0x01b5) { +#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO + ehci->big_endian_mmio = 1; +#else + ehci_warn(ehci, + "unsupported big endian Toshiba quirk\n"); +#endif + } + break; + } + ehci->caps = hcd->regs; - ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase)); + ehci->regs = hcd->regs + + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + dbg_hcs_params(ehci, "reset"); dbg_hcc_params(ehci, "reset"); @@ -101,7 +117,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) } /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = readl(&ehci->caps->hcs_params); + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); retval = ehci_halt(ehci); if (retval) @@ -235,8 +251,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) rc = -EINVAL; goto bail; } - writel (0, &ehci->regs->intr_enable); - (void)readl(&ehci->regs->intr_enable); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); + (void)ehci_readl(ehci, &ehci->regs->intr_enable); /* make sure snapshot being resumed re-enumerates everything */ if (message.event == PM_EVENT_PRETHAW) { @@ -270,13 +286,13 @@ static int ehci_pci_resume(struct usb_hcd *hcd) /* If CF is still set, we maintained PCI Vaux power. * Just undo the effect of ehci_pci_suspend(). */ - if (readl(&ehci->regs->configured_flag) == FLAG_CF) { + if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { int mask = INTR_MASK; if (!device_may_wakeup(&hcd->self.root_hub->dev)) mask &= ~STS_PCD; - writel(mask, &ehci->regs->intr_enable); - readl(&ehci->regs->intr_enable); + ehci_writel(ehci, mask, &ehci->regs->intr_enable); + ehci_readl(ehci, &ehci->regs->intr_enable); return 0; } @@ -300,9 +316,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd) /* here we "know" root ports should always stay powered */ ehci_port_power(ehci, 1); - writel(ehci->command, &ehci->regs->command); - writel(FLAG_CF, &ehci->regs->configured_flag); - readl(&ehci->regs->command); /* unblock posted writes */ + ehci_writel(ehci, ehci->command, &ehci->regs->command); + ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); + ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ hcd->state = HC_STATE_SUSPENDED; return 0; diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c new file mode 100644 index 000000000000..371f194a9d39 --- /dev/null +++ b/drivers/usb/host/ehci-ps3.c @@ -0,0 +1,193 @@ +/* + * PS3 EHCI Host Controller driver + * + * Copyright (C) 2006 Sony Computer Entertainment Inc. + * Copyright 2006 Sony Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +static int ps3_ehci_hc_reset(struct usb_hcd *hcd) +{ + int result; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + ehci->big_endian_mmio = 1; + + ehci->caps = hcd->regs; + ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci, + &ehci->caps->hc_capbase)); + + dbg_hcs_params(ehci, "reset"); + dbg_hcc_params(ehci, "reset"); + + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + result = ehci_halt(ehci); + + if (result) + return result; + + result = ehci_init(hcd); + + if (result) + return result; + + ehci_port_power(ehci, 0); + + return result; +} + +static const struct hc_driver ps3_ehci_hc_driver = { + .description = hcd_name, + .product_desc = "PS3 EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + .reset = ps3_ehci_hc_reset, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .get_frame_number = ehci_get_frame, + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, +#if defined(CONFIG_PM) + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +#endif +}; + +#if !defined(DEBUG) +#undef dev_dbg +static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg( + const struct device *_dev, const char *fmt, ...) {return 0;} +#endif + + +static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev) +{ + int result; + struct usb_hcd *hcd; + unsigned int virq; + static u64 dummy_mask = DMA_32BIT_MASK; + + if (usb_disabled()) { + result = -ENODEV; + goto fail_start; + } + + result = ps3_mmio_region_create(dev->m_region); + + if (result) { + dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n", + __func__, __LINE__); + result = -EPERM; + goto fail_mmio; + } + + dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, + __LINE__, dev->m_region->lpar_addr); + + result = ps3_alloc_io_irq(dev->interrupt_id, &virq); + + if (result) { + dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", + __func__, __LINE__, virq); + result = -EPERM; + goto fail_irq; + } + + dev->core.power.power_state = PMSG_ON; + dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ + + hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id); + + if (!hcd) { + dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__, + __LINE__); + result = -ENOMEM; + goto fail_create_hcd; + } + + hcd->rsrc_start = dev->m_region->lpar_addr; + hcd->rsrc_len = dev->m_region->len; + hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len); + + if (!hcd->regs) { + dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__, + __LINE__); + result = -EPERM; + goto fail_ioremap; + } + + dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__, + (unsigned long)hcd->rsrc_start); + dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__, + (unsigned long)hcd->rsrc_len); + dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__, + (unsigned long)hcd->regs); + dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, + (unsigned long)virq); + + ps3_system_bus_set_driver_data(dev, hcd); + + result = usb_add_hcd(hcd, virq, IRQF_DISABLED); + + if (result) { + dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n", + __func__, __LINE__, result); + goto fail_add_hcd; + } + + return result; + +fail_add_hcd: + iounmap(hcd->regs); +fail_ioremap: + usb_put_hcd(hcd); +fail_create_hcd: + ps3_free_io_irq(virq); +fail_irq: + ps3_free_mmio_region(dev->m_region); +fail_mmio: +fail_start: + return result; +} + +static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev) +{ + struct usb_hcd *hcd = + (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); + + usb_put_hcd(hcd); + ps3_system_bus_set_driver_data(dev, NULL); + + return 0; +} + +MODULE_ALIAS("ps3-ehci"); + +static struct ps3_system_bus_driver ps3_ehci_sb_driver = { + .match_id = PS3_MATCH_ID_EHCI, + .core = { + .name = "ps3-ehci-driver", + }, + .probe = ps3_ehci_sb_probe, + .remove = ps3_ehci_sb_remove, +}; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 62e46dc60e86..e7fbbd00e7cd 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -789,13 +789,14 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) head = ehci->async; timer_action_done (ehci, TIMER_ASYNC_OFF); if (!head->qh_next.qh) { - u32 cmd = readl (&ehci->regs->command); + u32 cmd = ehci_readl(ehci, &ehci->regs->command); if (!(cmd & CMD_ASE)) { /* in case a clear of CMD_ASE didn't take yet */ - (void) handshake (&ehci->regs->status, STS_ASS, 0, 150); + (void)handshake(ehci, &ehci->regs->status, + STS_ASS, 0, 150); cmd |= CMD_ASE | CMD_RUN; - writel (cmd, &ehci->regs->command); + ehci_writel(ehci, cmd, &ehci->regs->command); ehci_to_hcd(ehci)->state = HC_STATE_RUNNING; /* posted write need not be known to HC yet ... */ } @@ -1007,7 +1008,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - int cmd = readl (&ehci->regs->command); + int cmd = ehci_readl(ehci, &ehci->regs->command); struct ehci_qh *prev; #ifdef DEBUG @@ -1025,7 +1026,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) if (ehci_to_hcd(ehci)->state != HC_STATE_HALT && !ehci->reclaim) { /* ... and CMD_IAAD clear */ - writel (cmd & ~CMD_ASE, &ehci->regs->command); + ehci_writel(ehci, cmd & ~CMD_ASE, + &ehci->regs->command); wmb (); // handshake later, if we need to timer_action_done (ehci, TIMER_ASYNC_OFF); @@ -1054,8 +1056,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ehci->reclaim_ready = 0; cmd |= CMD_IAAD; - writel (cmd, &ehci->regs->command); - (void) readl (&ehci->regs->command); + ehci_writel(ehci, cmd, &ehci->regs->command); + (void)ehci_readl(ehci, &ehci->regs->command); timer_action (ehci, TIMER_IAA_WATCHDOG); } diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 65c402a0fa7a..7b5ae7111f23 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -433,20 +433,20 @@ static int enable_periodic (struct ehci_hcd *ehci) /* did clearing PSE did take effect yet? * takes effect only at frame boundaries... */ - status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125); + status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125); if (status != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return status; } - cmd = readl (&ehci->regs->command) | CMD_PSE; - writel (cmd, &ehci->regs->command); + cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE; + ehci_writel(ehci, cmd, &ehci->regs->command); /* posted write ... PSS happens later */ ehci_to_hcd(ehci)->state = HC_STATE_RUNNING; /* make sure ehci_work scans these */ - ehci->next_uframe = readl (&ehci->regs->frame_index) - % (ehci->periodic_size << 3); + ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index) + % (ehci->periodic_size << 3); return 0; } @@ -458,14 +458,14 @@ static int disable_periodic (struct ehci_hcd *ehci) /* did setting PSE not take effect yet? * takes effect only at frame boundaries... */ - status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125); + status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125); if (status != 0) { ehci_to_hcd(ehci)->state = HC_STATE_HALT; return status; } - cmd = readl (&ehci->regs->command) & ~CMD_PSE; - writel (cmd, &ehci->regs->command); + cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE; + ehci_writel(ehci, cmd, &ehci->regs->command); /* posted write ... */ ehci->next_uframe = -1; @@ -1336,7 +1336,7 @@ iso_stream_schedule ( goto fail; } - now = readl (&ehci->regs->frame_index) % mod; + now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; /* when's the last uframe this urb could start? */ max = now + mod; @@ -2088,7 +2088,7 @@ scan_periodic (struct ehci_hcd *ehci) */ now_uframe = ehci->next_uframe; if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) - clock = readl (&ehci->regs->frame_index); + clock = ehci_readl(ehci, &ehci->regs->frame_index); else clock = now_uframe + mod - 1; clock %= mod; @@ -2213,7 +2213,7 @@ restart: if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) break; ehci->next_uframe = now_uframe; - now = readl (&ehci->regs->frame_index) % mod; + now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; if (now_uframe == now) break; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 74dbc6c8228f..ec0da0343be4 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -74,7 +74,11 @@ struct ehci_hcd { /* one per controller */ /* per root hub port */ unsigned long reset_done [EHCI_MAX_ROOT_PORTS]; - unsigned long bus_suspended; + /* bit vectors (one bit per port) */ + unsigned long bus_suspended; /* which ports were + already suspended at the start of a bus suspend */ + unsigned long companion_ports; /* which ports are + dedicated to the companion controller */ /* per-HC memory pools (could be per-bus, but ...) */ struct dma_pool *qh_pool; /* qh per active urb */ @@ -92,6 +96,7 @@ struct ehci_hcd { /* one per controller */ unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */ unsigned no_selective_suspend:1; unsigned has_fsl_port_bug:1; /* FreeScale */ + unsigned big_endian_mmio:1; u8 sbrn; /* packed release number */ @@ -651,6 +656,45 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) #define ehci_has_fsl_portno_bug(e) (0) #endif +/* + * While most USB host controllers implement their registers in + * little-endian format, a minority (celleb companion chip) implement + * them in big endian format. + * + * This attempts to support either format at compile time without a + * runtime penalty, or both formats with the additional overhead + * of checking a flag bit. + */ + +#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO +#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio) +#else +#define ehci_big_endian_mmio(e) 0 +#endif + +static inline unsigned int ehci_readl (const struct ehci_hcd *ehci, + __u32 __iomem * regs) +{ +#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO + return ehci_big_endian_mmio(ehci) ? + readl_be((__force u32 *)regs) : + readl((__force u32 *)regs); +#else + return readl((__force u32 *)regs); +#endif +} + +static inline void ehci_writel (const struct ehci_hcd *ehci, + const unsigned int val, __u32 __iomem *regs) +{ +#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO + ehci_big_endian_mmio(ehci) ? + writel_be(val, (__force u32 *)regs) : + writel(val, (__force u32 *)regs); +#else + writel(val, (__force u32 *)regs); +#endif +} /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index cc405512fa1c..930346487278 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -170,7 +170,6 @@ static int usb_hcd_at91_remove(struct usb_hcd *hcd, at91_stop_hc(pdev); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - disable_irq_wake(hcd->irq); clk_put(fclk); clk_put(iclk); @@ -271,8 +270,6 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg) if (device_may_wakeup(&pdev->dev)) enable_irq_wake(hcd->irq); - else - disable_irq_wake(hcd->irq); /* * The integrated transceivers seem unable to notice disconnect, @@ -293,6 +290,11 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg) static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) { + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(hcd->irq); + if (!clocked) { clk_enable(iclk); clk_enable(fclk); @@ -320,18 +322,3 @@ static struct platform_driver ohci_hcd_at91_driver = { }, }; -static int __init ohci_hcd_at91_init (void) -{ - if (usb_disabled()) - return -ENODEV; - - return platform_driver_register(&ohci_hcd_at91_driver); -} - -static void __exit ohci_hcd_at91_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_at91_driver); -} - -module_init (ohci_hcd_at91_init); -module_exit (ohci_hcd_at91_cleanup); diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index e70b2430e2a9..663a0600b6e7 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -345,19 +345,3 @@ static struct platform_driver ohci_hcd_au1xxx_driver = { }, }; -static int __init ohci_hcd_au1xxx_init (void) -{ - pr_debug (DRIVER_INFO " (Au1xxx)"); - pr_debug ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_au1xxx_driver); -} - -static void __exit ohci_hcd_au1xxx_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_au1xxx_driver); -} - -module_init (ohci_hcd_au1xxx_init); -module_exit (ohci_hcd_au1xxx_cleanup); diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index 3348b07f0fe5..44c60fba76e1 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -214,15 +214,3 @@ static struct platform_driver ohci_hcd_ep93xx_driver = { }, }; -static int __init ohci_hcd_ep93xx_init(void) -{ - return platform_driver_register(&ohci_hcd_ep93xx_driver); -} - -static void __exit ohci_hcd_ep93xx_cleanup(void) -{ - platform_driver_unregister(&ohci_hcd_ep93xx_driver); -} - -module_init(ohci_hcd_ep93xx_init); -module_exit(ohci_hcd_ep93xx_cleanup); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index c1c1d871aba4..fa6a7ceaa0db 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -855,63 +855,167 @@ MODULE_LICENSE ("GPL"); #ifdef CONFIG_PCI #include "ohci-pci.c" +#define PCI_DRIVER ohci_pci_driver #endif #ifdef CONFIG_SA1111 #include "ohci-sa1111.c" +#define SA1111_DRIVER ohci_hcd_sa1111_driver #endif #ifdef CONFIG_ARCH_S3C2410 #include "ohci-s3c2410.c" +#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver #endif #ifdef CONFIG_ARCH_OMAP #include "ohci-omap.c" +#define PLATFORM_DRIVER ohci_hcd_omap_driver #endif #ifdef CONFIG_ARCH_LH7A404 #include "ohci-lh7a404.c" +#define PLATFORM_DRIVER ohci_hcd_lh7a404_driver #endif #ifdef CONFIG_PXA27x #include "ohci-pxa27x.c" +#define PLATFORM_DRIVER ohci_hcd_pxa27x_driver #endif #ifdef CONFIG_ARCH_EP93XX #include "ohci-ep93xx.c" +#define PLATFORM_DRIVER ohci_hcd_ep93xx_driver #endif #ifdef CONFIG_SOC_AU1X00 #include "ohci-au1xxx.c" +#define PLATFORM_DRIVER ohci_hcd_au1xxx_driver #endif #ifdef CONFIG_PNX8550 #include "ohci-pnx8550.c" +#define PLATFORM_DRIVER ohci_hcd_pnx8550_driver #endif #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC #include "ohci-ppc-soc.c" +#define PLATFORM_DRIVER ohci_hcd_ppc_soc_driver #endif #ifdef CONFIG_ARCH_AT91 #include "ohci-at91.c" +#define PLATFORM_DRIVER ohci_hcd_at91_driver #endif #ifdef CONFIG_ARCH_PNX4008 #include "ohci-pnx4008.c" +#define PLATFORM_DRIVER usb_hcd_pnx4008_driver #endif -#if !(defined(CONFIG_PCI) \ - || defined(CONFIG_SA1111) \ - || defined(CONFIG_ARCH_S3C2410) \ - || defined(CONFIG_ARCH_OMAP) \ - || defined (CONFIG_ARCH_LH7A404) \ - || defined (CONFIG_PXA27x) \ - || defined (CONFIG_ARCH_EP93XX) \ - || defined (CONFIG_SOC_AU1X00) \ - || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \ - || defined (CONFIG_ARCH_AT91) \ - || defined (CONFIG_ARCH_PNX4008) \ - ) + +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF +#include "ohci-ppc-of.c" +#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver +#endif + +#ifdef CONFIG_PPC_PS3 +#include "ohci-ps3.c" +#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_driver +#endif + +#if !defined(PCI_DRIVER) && \ + !defined(PLATFORM_DRIVER) && \ + !defined(OF_PLATFORM_DRIVER) && \ + !defined(SA1111_DRIVER) && \ + !defined(PS3_SYSTEM_BUS_DRIVER) #error "missing bus glue for ohci-hcd" #endif + +static int __init ohci_hcd_mod_init(void) +{ + int retval = 0; + + if (usb_disabled()) + return -ENODEV; + + printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name); + pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, + sizeof (struct ed), sizeof (struct td)); + +#ifdef PS3_SYSTEM_BUS_DRIVER + retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER); + if (retval < 0) + goto error_ps3; +#endif + +#ifdef PLATFORM_DRIVER + retval = platform_driver_register(&PLATFORM_DRIVER); + if (retval < 0) + goto error_platform; +#endif + +#ifdef OF_PLATFORM_DRIVER + retval = of_register_platform_driver(&OF_PLATFORM_DRIVER); + if (retval < 0) + goto error_of_platform; +#endif + +#ifdef SA1111_DRIVER + retval = sa1111_driver_register(&SA1111_DRIVER); + if (retval < 0) + goto error_sa1111; +#endif + +#ifdef PCI_DRIVER + retval = pci_register_driver(&PCI_DRIVER); + if (retval < 0) + goto error_pci; +#endif + + return retval; + + /* Error path */ +#ifdef PCI_DRIVER + error_pci: +#endif +#ifdef SA1111_DRIVER + sa1111_driver_unregister(&SA1111_DRIVER); + error_sa1111: +#endif +#ifdef OF_PLATFORM_DRIVER + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); + error_of_platform: +#endif +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); + error_platform: +#endif +#ifdef PS3_SYSTEM_BUS_DRIVER + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); + error_ps3: +#endif + return retval; +} +module_init(ohci_hcd_mod_init); + +static void __exit ohci_hcd_mod_exit(void) +{ +#ifdef PCI_DRIVER + pci_unregister_driver(&PCI_DRIVER); +#endif +#ifdef SA1111_DRIVER + sa1111_driver_unregister(&SA1111_DRIVER); +#endif +#ifdef OF_PLATFORM_DRIVER + of_unregister_platform_driver(&OF_PLATFORM_DRIVER); +#endif +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); +#endif +#ifdef PS3_SYSTEM_BUS_DRIVER + ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); +#endif +} +module_exit(ohci_hcd_mod_exit); + diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index e9807cf73a2f..4a043abd85ea 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -251,19 +251,3 @@ static struct platform_driver ohci_hcd_lh7a404_driver = { }, }; -static int __init ohci_hcd_lh7a404_init (void) -{ - pr_debug (DRIVER_INFO " (LH7A404)"); - pr_debug ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_lh7a404_driver); -} - -static void __exit ohci_hcd_lh7a404_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_lh7a404_driver); -} - -module_init (ohci_hcd_lh7a404_init); -module_exit (ohci_hcd_lh7a404_cleanup); diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 27be1f936885..5cfa3d1c4413 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -544,22 +544,3 @@ static struct platform_driver ohci_hcd_omap_driver = { }, }; -static int __init ohci_hcd_omap_init (void) -{ - printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name); - if (usb_disabled()) - return -ENODEV; - - pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name, - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_omap_driver); -} - -static void __exit ohci_hcd_omap_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_omap_driver); -} - -module_init (ohci_hcd_omap_init); -module_exit (ohci_hcd_omap_cleanup); diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 596e0b41e606..b331ac4d0d62 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -20,80 +20,155 @@ /*-------------------------------------------------------------------------*/ -static int -ohci_pci_reset (struct usb_hcd *hcd) +/* AMD 756, for most chips (early revs), corrupts register + * values on read ... so enable the vendor workaround. + */ +static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); - ohci_hcd_init (ohci); - return ohci_init (ohci); + ohci->flags = OHCI_QUIRK_AMD756; + ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); + + /* also erratum 10 (suspend/resume issues) */ + device_init_wakeup(&hcd->self.root_hub->dev, 0); + + return 0; } -static int __devinit -ohci_pci_start (struct usb_hcd *hcd) +/* Apple's OHCI driver has a lot of bizarre workarounds + * for this chip. Evidently control and bulk lists + * can get confused. (B&W G3 models, and ...) + */ +static int __devinit ohci_quirk_opti(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n"); + + return 0; +} + +/* Check for NSC87560. We have to look at the bridge (fn1) to + * identify the USB (fn2). This quirk might apply to more or + * even all NSC stuff. + */ +static int __devinit ohci_quirk_ns(struct usb_hcd *hcd) +{ + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + struct pci_dev *b; + + b = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1)); + if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO + && b->vendor == PCI_VENDOR_ID_NS) { + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + ohci->flags |= OHCI_QUIRK_SUPERIO; + ohci_dbg (ohci, "Using NSC SuperIO setup\n"); + } + pci_dev_put(b); + + return 0; +} + +/* Check for Compaq's ZFMicro chipset, which needs short + * delays before control or bulk queues get re-activated + * in finish_unlinks() + */ +static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + ohci->flags |= OHCI_QUIRK_ZFMICRO; + ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n"); + + return 0; +} + +/* Check for Toshiba SCC OHCI which has big endian registers + * and little endian in memory data structures + */ +static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + + /* That chip is only present in the southbridge of some + * cell based platforms which are supposed to select + * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if + * that was the case though. + */ +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO + ohci->flags |= OHCI_QUIRK_BE_MMIO; + ohci_dbg (ohci, "enabled big endian Toshiba quirk\n"); + return 0; +#else + ohci_err (ohci, "unsupported big endian Toshiba quirk\n"); + return -ENXIO; +#endif +} + +/* List of quirks for OHCI */ +static const struct pci_device_id ohci_pci_quirks[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c), + .driver_data = (unsigned long)ohci_quirk_amd756, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861), + .driver_data = (unsigned long)ohci_quirk_opti, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID), + .driver_data = (unsigned long)ohci_quirk_ns, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8), + .driver_data = (unsigned long)ohci_quirk_zfmicro, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6), + .driver_data = (unsigned long)ohci_quirk_toshiba_scc, + }, + /* FIXME for some of the early AMD 760 southbridges, OHCI + * won't work at all. blacklist them. + */ + + {}, +}; + +static int ohci_pci_reset (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret = 0; + + if (hcd->self.controller) { + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + const struct pci_device_id *quirk_id; + + quirk_id = pci_match_id(ohci_pci_quirks, pdev); + if (quirk_id != NULL) { + int (*quirk)(struct usb_hcd *ohci); + quirk = (void *)quirk_id->driver_data; + ret = quirk(hcd); + } + } + if (ret == 0) { + ohci_hcd_init (ohci); + return ohci_init (ohci); + } + return ret; +} + + +static int __devinit ohci_pci_start (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ret; - /* REVISIT this whole block should move to reset(), which handles - * all the other one-time init. - */ +#ifdef CONFIG_PM /* avoid warnings about unused pdev */ if (hcd->self.controller) { struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - /* AMD 756, for most chips (early revs), corrupts register - * values on read ... so enable the vendor workaround. - */ - if (pdev->vendor == PCI_VENDOR_ID_AMD - && pdev->device == 0x740c) { - ohci->flags = OHCI_QUIRK_AMD756; - ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); - /* also erratum 10 (suspend/resume issues) */ - device_init_wakeup(&hcd->self.root_hub->dev, 0); - } - - /* FIXME for some of the early AMD 760 southbridges, OHCI - * won't work at all. blacklist them. - */ - - /* Apple's OHCI driver has a lot of bizarre workarounds - * for this chip. Evidently control and bulk lists - * can get confused. (B&W G3 models, and ...) - */ - else if (pdev->vendor == PCI_VENDOR_ID_OPTI - && pdev->device == 0xc861) { - ohci_dbg (ohci, - "WARNING: OPTi workarounds unavailable\n"); - } - - /* Check for NSC87560. We have to look at the bridge (fn1) to - * identify the USB (fn2). This quirk might apply to more or - * even all NSC stuff. - */ - else if (pdev->vendor == PCI_VENDOR_ID_NS) { - struct pci_dev *b; - - b = pci_get_slot (pdev->bus, - PCI_DEVFN (PCI_SLOT (pdev->devfn), 1)); - if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO - && b->vendor == PCI_VENDOR_ID_NS) { - ohci->flags |= OHCI_QUIRK_SUPERIO; - ohci_dbg (ohci, "Using NSC SuperIO setup\n"); - } - pci_dev_put(b); - } - - /* Check for Compaq's ZFMicro chipset, which needs short - * delays before control or bulk queues get re-activated - * in finish_unlinks() - */ - else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ - && pdev->device == 0xa0f8) { - ohci->flags |= OHCI_QUIRK_ZFMICRO; - ohci_dbg (ohci, - "enabled Compaq ZFMicro chipset quirk\n"); - } - /* RWC may not be set for add-in PCI cards, since boot * firmware probably ignored them. This transfers PCI * PM wakeup capabilities (once the PCI layer is fixed). @@ -101,16 +176,14 @@ ohci_pci_start (struct usb_hcd *hcd) if (device_may_wakeup(&pdev->dev)) ohci->hc_control |= OHCI_CTRL_RWC; } +#endif /* CONFIG_PM */ - /* NOTE: there may have already been a first reset, to - * keep bios/smm irqs from making trouble - */ - if ((ret = ohci_run (ohci)) < 0) { + ret = ohci_run (ohci); + if (ret < 0) { ohci_err (ohci, "can't start\n"); ohci_stop (hcd); - return ret; } - return 0; + return ret; } #ifdef CONFIG_PM @@ -238,23 +311,3 @@ static struct pci_driver ohci_pci_driver = { .shutdown = usb_hcd_pci_shutdown, }; - -static int __init ohci_hcd_pci_init (void) -{ - printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name); - if (usb_disabled()) - return -ENODEV; - - pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, - sizeof (struct ed), sizeof (struct td)); - return pci_register_driver (&ohci_pci_driver); -} -module_init (ohci_hcd_pci_init); - -/*-------------------------------------------------------------------------*/ - -static void __exit ohci_hcd_pci_cleanup (void) -{ - pci_unregister_driver (&ohci_pci_driver); -} -module_exit (ohci_hcd_pci_cleanup); diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c index 3a8cbfb69054..893b172384da 100644 --- a/drivers/usb/host/ohci-pnx4008.c +++ b/drivers/usb/host/ohci-pnx4008.c @@ -465,15 +465,3 @@ static struct platform_driver usb_hcd_pnx4008_driver = { .remove = usb_hcd_pnx4008_remove, }; -static int __init usb_hcd_pnx4008_init(void) -{ - return platform_driver_register(&usb_hcd_pnx4008_driver); -} - -static void __exit usb_hcd_pnx4008_cleanup(void) -{ - return platform_driver_unregister(&usb_hcd_pnx4008_driver); -} - -module_init(usb_hcd_pnx4008_init); -module_exit(usb_hcd_pnx4008_cleanup); diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c index 6922b91b1704..de45eb0051a7 100644 --- a/drivers/usb/host/ohci-pnx8550.c +++ b/drivers/usb/host/ohci-pnx8550.c @@ -240,19 +240,3 @@ static struct platform_driver ohci_hcd_pnx8550_driver = { .remove = ohci_hcd_pnx8550_drv_remove, }; -static int __init ohci_hcd_pnx8550_init (void) -{ - pr_debug (DRIVER_INFO " (pnx8550)"); - pr_debug ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_pnx8550_driver); -} - -static void __exit ohci_hcd_pnx8550_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_pnx8550_driver); -} - -module_init (ohci_hcd_pnx8550_init); -module_exit (ohci_hcd_pnx8550_cleanup); diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c new file mode 100644 index 000000000000..08e237c7bc43 --- /dev/null +++ b/drivers/usb/host/ohci-ppc-of.c @@ -0,0 +1,232 @@ +/* + * OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * (C) Copyright 2002 Hewlett-Packard Company + * (C) Copyright 2006 Sylvain Munaut + * + * Bus glue for OHCI HC on the of_platform bus + * + * Modified for of_platform bus from ohci-sa1111.c + * + * This file is licenced under the GPL. + */ + +#include + +#include +#include + + +static int __devinit +ohci_ppc_of_start(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int ret; + + if ((ret = ohci_init(ohci)) < 0) + return ret; + + if ((ret = ohci_run(ohci)) < 0) { + err("can't start %s", ohci_to_hcd(ohci)->self.bus_name); + ohci_stop(hcd); + return ret; + } + + return 0; +} + +static const struct hc_driver ohci_ppc_of_hc_driver = { + .description = hcd_name, + .product_desc = "OF OHCI", + .hcd_priv_size = sizeof(struct ohci_hcd), + + /* + * generic hardware linkage + */ + .irq = ohci_irq, + .flags = HCD_USB11 | HCD_MEMORY, + + /* + * basic lifecycle operations + */ + .start = ohci_ppc_of_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + + /* + * scheduling support + */ + .get_frame_number = ohci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif + .start_port_reset = ohci_start_port_reset, +}; + + +static int __devinit +ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match) +{ + struct device_node *dn = op->node; + struct usb_hcd *hcd; + struct ohci_hcd *ohci; + struct resource res; + int irq; + + int rv; + int is_bigendian; + + if (usb_disabled()) + return -ENODEV; + + is_bigendian = + device_is_compatible(dn, "ohci-bigendian") || + device_is_compatible(dn, "ohci-be"); + + dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n"); + + rv = of_address_to_resource(dn, 0, &res); + if (rv) + return rv; + + hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB"); + if (!hcd) + return -ENOMEM; + + hcd->rsrc_start = res.start; + hcd->rsrc_len = res.end - res.start + 1; + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + printk(KERN_ERR __FILE__ ": request_mem_region failed\n"); + rv = -EBUSY; + goto err_rmr; + } + + irq = irq_of_parse_and_map(dn, 0); + if (irq == NO_IRQ) { + printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n"); + rv = -EBUSY; + goto err_irq; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + printk(KERN_ERR __FILE__ ": ioremap failed\n"); + rv = -ENOMEM; + goto err_ioremap; + } + + ohci = hcd_to_ohci(hcd); + if (is_bigendian) + ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + + ohci_hcd_init(ohci); + + rv = usb_add_hcd(hcd, irq, 0); + if (rv == 0) + return 0; + + iounmap(hcd->regs); +err_ioremap: + irq_dispose_mapping(irq); +err_irq: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err_rmr: + usb_put_hcd(hcd); + + return rv; +} + +static int ohci_hcd_ppc_of_remove(struct of_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + dev_set_drvdata(&op->dev, NULL); + + dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); + + usb_remove_hcd(hcd); + + iounmap(hcd->regs); + irq_dispose_mapping(hcd->irq); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + + usb_put_hcd(hcd); + + return 0; +} + +static int ohci_hcd_ppc_of_shutdown(struct of_device *op) +{ + struct usb_hcd *hcd = dev_get_drvdata(&op->dev); + + if (hcd->driver->shutdown) + hcd->driver->shutdown(hcd); + + return 0; +} + + +static struct of_device_id ohci_hcd_ppc_of_match[] = { +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE + { + .name = "usb", + .compatible = "ohci-bigendian", + }, + { + .name = "usb", + .compatible = "ohci-be", + }, +#endif +#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE + { + .name = "usb", + .compatible = "ohci-littledian", + }, + { + .name = "usb", + .compatible = "ohci-le", + }, +#endif + {}, +}; +MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); + +#if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \ + !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE) +#error "No endianess selected for ppc-of-ohci" +#endif + + +static struct of_platform_driver ohci_hcd_ppc_of_driver = { + .name = "ppc-of-ohci", + .match_table = ohci_hcd_ppc_of_match, + .probe = ohci_hcd_ppc_of_probe, + .remove = ohci_hcd_ppc_of_remove, + .shutdown = ohci_hcd_ppc_of_shutdown, +#ifdef CONFIG_PM + /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ + /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ +#endif + .driver = { + .name = "ppc-of-ohci", + .owner = THIS_MODULE, + }, +}; + diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index e1a7eb817313..1a2e1777ca61 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -72,7 +72,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, } ohci = hcd_to_ohci(hcd); - ohci->flags |= OHCI_BIG_ENDIAN; + ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; ohci_hcd_init(ohci); retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); @@ -208,19 +208,3 @@ static struct platform_driver ohci_hcd_ppc_soc_driver = { }, }; -static int __init ohci_hcd_ppc_soc_init(void) -{ - pr_debug(DRIVER_INFO " (PPC SOC)\n"); - pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed), - sizeof(struct td)); - - return platform_driver_register(&ohci_hcd_ppc_soc_driver); -} - -static void __exit ohci_hcd_ppc_soc_cleanup(void) -{ - platform_driver_unregister(&ohci_hcd_ppc_soc_driver); -} - -module_init(ohci_hcd_ppc_soc_init); -module_exit(ohci_hcd_ppc_soc_cleanup); diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c new file mode 100644 index 000000000000..69d948b4a701 --- /dev/null +++ b/drivers/usb/host/ohci-ps3.c @@ -0,0 +1,196 @@ +/* + * PS3 OHCI Host Controller driver + * + * Copyright (C) 2006 Sony Computer Entertainment Inc. + * Copyright 2006 Sony Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +static int ps3_ohci_hc_reset(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + ohci->flags |= OHCI_QUIRK_BE_MMIO; + ohci_hcd_init(ohci); + return ohci_init(ohci); +} + +static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd) +{ + int result; + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + + /* Handle root hub init quirk in spider south bridge. */ + /* Also set PwrOn2PwrGood to 0x7f (254ms). */ + + ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM, + &ohci->regs->roothub.a); + ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b); + + result = ohci_run(ohci); + + if (result < 0) { + err("can't start %s", hcd->self.bus_name); + ohci_stop(hcd); + } + + return result; +} + +static const struct hc_driver ps3_ohci_hc_driver = { + .description = hcd_name, + .product_desc = "PS3 OHCI Host Controller", + .hcd_priv_size = sizeof(struct ohci_hcd), + .irq = ohci_irq, + .flags = HCD_MEMORY | HCD_USB11, + .reset = ps3_ohci_hc_reset, + .start = ps3_ohci_hc_start, + .stop = ohci_stop, + .shutdown = ohci_shutdown, + .urb_enqueue = ohci_urb_enqueue, + .urb_dequeue = ohci_urb_dequeue, + .endpoint_disable = ohci_endpoint_disable, + .get_frame_number = ohci_get_frame, + .hub_status_data = ohci_hub_status_data, + .hub_control = ohci_hub_control, + .hub_irq_enable = ohci_rhsc_enable, + .start_port_reset = ohci_start_port_reset, +#if defined(CONFIG_PM) + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif +}; + +/* redefine dev_dbg to do a syntax check */ + +#if !defined(DEBUG) +#undef dev_dbg +static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg( + const struct device *_dev, const char *fmt, ...) {return 0;} +#endif + +static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev) +{ + int result; + struct usb_hcd *hcd; + unsigned int virq; + static u64 dummy_mask = DMA_32BIT_MASK; + + if (usb_disabled()) { + result = -ENODEV; + goto fail_start; + } + + result = ps3_mmio_region_create(dev->m_region); + + if (result) { + dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n", + __func__, __LINE__); + result = -EPERM; + goto fail_mmio; + } + + dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, + __LINE__, dev->m_region->lpar_addr); + + result = ps3_alloc_io_irq(dev->interrupt_id, &virq); + + if (result) { + dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", + __func__, __LINE__, virq); + result = -EPERM; + goto fail_irq; + } + + dev->core.power.power_state = PMSG_ON; + dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ + + hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id); + + if (!hcd) { + dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__, + __LINE__); + result = -ENOMEM; + goto fail_create_hcd; + } + + hcd->rsrc_start = dev->m_region->lpar_addr; + hcd->rsrc_len = dev->m_region->len; + hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len); + + if (!hcd->regs) { + dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__, + __LINE__); + result = -EPERM; + goto fail_ioremap; + } + + dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__, + (unsigned long)hcd->rsrc_start); + dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__, + (unsigned long)hcd->rsrc_len); + dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__, + (unsigned long)hcd->regs); + dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, + (unsigned long)virq); + + ps3_system_bus_set_driver_data(dev, hcd); + + result = usb_add_hcd(hcd, virq, IRQF_DISABLED); + + if (result) { + dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n", + __func__, __LINE__, result); + goto fail_add_hcd; + } + + return result; + +fail_add_hcd: + iounmap(hcd->regs); +fail_ioremap: + usb_put_hcd(hcd); +fail_create_hcd: + ps3_free_io_irq(virq); +fail_irq: + ps3_free_mmio_region(dev->m_region); +fail_mmio: +fail_start: + return result; +} + +static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev) +{ + struct usb_hcd *hcd = + (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); + + usb_put_hcd(hcd); + ps3_system_bus_set_driver_data(dev, NULL); + + return 0; +} + +MODULE_ALIAS("ps3-ohci"); + +static struct ps3_system_bus_driver ps3_ohci_sb_driver = { + .match_id = PS3_MATCH_ID_OHCI, + .core = { + .name = "ps3-ohci-driver", + }, + .probe = ps3_ohci_sb_probe, + .remove = ps3_ohci_sb_remove, +}; diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 3bbea844a9e3..f1563dc319d3 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -369,19 +369,3 @@ static struct platform_driver ohci_hcd_pxa27x_driver = { }, }; -static int __init ohci_hcd_pxa27x_init (void) -{ - pr_debug (DRIVER_INFO " (pxa27x)"); - pr_debug ("block sizes: ed %d td %d\n", - sizeof (struct ed), sizeof (struct td)); - - return platform_driver_register(&ohci_hcd_pxa27x_driver); -} - -static void __exit ohci_hcd_pxa27x_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_pxa27x_driver); -} - -module_init (ohci_hcd_pxa27x_init); -module_exit (ohci_hcd_pxa27x_cleanup); diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index b350d45033e7..6829814b7aaf 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -501,15 +501,3 @@ static struct platform_driver ohci_hcd_s3c2410_driver = { }, }; -static int __init ohci_hcd_s3c2410_init (void) -{ - return platform_driver_register(&ohci_hcd_s3c2410_driver); -} - -static void __exit ohci_hcd_s3c2410_cleanup (void) -{ - platform_driver_unregister(&ohci_hcd_s3c2410_driver); -} - -module_init (ohci_hcd_s3c2410_init); -module_exit (ohci_hcd_s3c2410_cleanup); diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index fe0090e33675..0f48f2d99226 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -269,19 +269,3 @@ static struct sa1111_driver ohci_hcd_sa1111_driver = { .remove = ohci_hcd_sa1111_drv_remove, }; -static int __init ohci_hcd_sa1111_init (void) -{ - dbg (DRIVER_INFO " (SA-1111)"); - dbg ("block sizes: ed %d td %d", - sizeof (struct ed), sizeof (struct td)); - - return sa1111_driver_register(&ohci_hcd_sa1111_driver); -} - -static void __exit ohci_hcd_sa1111_cleanup (void) -{ - sa1111_driver_unregister(&ohci_hcd_sa1111_driver); -} - -module_init (ohci_hcd_sa1111_init); -module_exit (ohci_hcd_sa1111_cleanup); diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 405257f3e853..0dafcda37291 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -394,8 +394,9 @@ struct ohci_hcd { #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ #define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */ #define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */ -#define OHCI_BIG_ENDIAN 0x08 /* big endian HC */ -#define OHCI_QUIRK_ZFMICRO 0x10 /* Compaq ZFMicro chipset*/ +#define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */ +#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */ +#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ // there are also chip quirks/bugs in init logic }; @@ -439,117 +440,164 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci) * a minority (notably the IBM STB04XXX and the Motorola MPC5200 * processors) implement them in big endian format. * + * In addition some more exotic implementations like the Toshiba + * Spider (aka SCC) cell southbridge are "mixed" endian, that is, + * they have a different endianness for registers vs. in-memory + * descriptors. + * * This attempts to support either format at compile time without a * runtime penalty, or both formats with the additional overhead * of checking a flag bit. + * + * That leads to some tricky Kconfig rules howevber. There are + * different defaults based on some arch/ppc platforms, though + * the basic rules are: + * + * Controller type Kconfig options needed + * --------------- ---------------------- + * little endian CONFIG_USB_OHCI_LITTLE_ENDIAN + * + * fully big endian CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_ + * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO + * + * mixed endian CONFIG_USB_OHCI_LITTLE_ENDIAN _and_ + * CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC} + * + * (If you have a mixed endian controller, you -must- also define + * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building + * both your mixed endian and a fully big endian controller support in + * the same kernel image). */ -#ifdef CONFIG_USB_OHCI_BIG_ENDIAN - +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC #ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN -#define big_endian(ohci) (ohci->flags & OHCI_BIG_ENDIAN) /* either */ +#define big_endian_desc(ohci) (ohci->flags & OHCI_QUIRK_BE_DESC) #else -#define big_endian(ohci) 1 /* only big endian */ +#define big_endian_desc(ohci) 1 /* only big endian */ +#endif +#else +#define big_endian_desc(ohci) 0 /* only little endian */ +#endif + +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO +#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN +#define big_endian_mmio(ohci) (ohci->flags & OHCI_QUIRK_BE_MMIO) +#else +#define big_endian_mmio(ohci) 1 /* only big endian */ +#endif +#else +#define big_endian_mmio(ohci) 0 /* only little endian */ #endif /* * Big-endian read/write functions are arch-specific. * Other arches can be added if/when they're needed. + * + * REVISIT: arch/powerpc now has readl/writel_be, so the + * definition below can die once the STB04xxx support is + * finally ported over. */ -#if defined(CONFIG_PPC) +#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE) #define readl_be(addr) in_be32((__force unsigned *)addr) #define writel_be(val, addr) out_be32((__force unsigned *)addr, val) #endif -static inline unsigned int ohci_readl (const struct ohci_hcd *ohci, - __hc32 __iomem * regs) +static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci, + __hc32 __iomem * regs) { - return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs); +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO + return big_endian_mmio(ohci) ? + readl_be ((__force u32 *)regs) : + readl ((__force u32 *)regs); +#else + return readl ((__force u32 *)regs); +#endif } -static inline void ohci_writel (const struct ohci_hcd *ohci, - const unsigned int val, __hc32 __iomem *regs) +static inline void _ohci_writel (const struct ohci_hcd *ohci, + const unsigned int val, __hc32 __iomem *regs) { - big_endian(ohci) ? writel_be (val, regs) : - writel (val, (__force u32 *)regs); +#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO + big_endian_mmio(ohci) ? + writel_be (val, (__force u32 *)regs) : + writel (val, (__force u32 *)regs); +#else + writel (val, (__force u32 *)regs); +#endif } -#else /* !CONFIG_USB_OHCI_BIG_ENDIAN */ - -#define big_endian(ohci) 0 /* only little endian */ - #ifdef CONFIG_ARCH_LH7A404 - /* Marc Singer: at the time this code was written, the LH7A404 - * had a problem reading the USB host registers. This - * implementation of the ohci_readl function performs the read - * twice as a work-around. - */ -static inline unsigned int -ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs) -{ - *(volatile __force unsigned int*) regs; - return *(volatile __force unsigned int*) regs; -} +/* Marc Singer: at the time this code was written, the LH7A404 + * had a problem reading the USB host registers. This + * implementation of the ohci_readl function performs the read + * twice as a work-around. + */ +#define ohci_readl(o,r) (_ohci_readl(o,r),_ohci_readl(o,r)) +#define ohci_writel(o,v,r) _ohci_writel(o,v,r) #else - /* Standard version of ohci_readl uses standard, platform - * specific implementation. */ -static inline unsigned int -ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs) -{ - return readl(regs); -} +#define ohci_readl(o,r) _ohci_readl(o,r) +#define ohci_writel(o,v,r) _ohci_writel(o,v,r) #endif -static inline void ohci_writel (const struct ohci_hcd *ohci, - const unsigned int val, __hc32 __iomem *regs) -{ - writel (val, regs); -} - -#endif /* !CONFIG_USB_OHCI_BIG_ENDIAN */ /*-------------------------------------------------------------------------*/ /* cpu to ohci */ static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x) { - return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x); + return big_endian_desc(ohci) ? + (__force __hc16)cpu_to_be16(x) : + (__force __hc16)cpu_to_le16(x); } static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x) { - return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x); + return big_endian_desc(ohci) ? + cpu_to_be16p(x) : + cpu_to_le16p(x); } static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x) { - return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x); + return big_endian_desc(ohci) ? + (__force __hc32)cpu_to_be32(x) : + (__force __hc32)cpu_to_le32(x); } static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x) { - return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x); + return big_endian_desc(ohci) ? + cpu_to_be32p(x) : + cpu_to_le32p(x); } /* ohci to cpu */ static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x) { - return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x); + return big_endian_desc(ohci) ? + be16_to_cpu((__force __be16)x) : + le16_to_cpu((__force __le16)x); } static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x) { - return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x); + return big_endian_desc(ohci) ? + be16_to_cpup((__force __be16 *)x) : + le16_to_cpup((__force __le16 *)x); } static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x) { - return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x); + return big_endian_desc(ohci) ? + be32_to_cpu((__force __be32)x) : + le32_to_cpu((__force __le32)x); } static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) { - return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x); + return big_endian_desc(ohci) ? + be32_to_cpup((__force __be32 *)x) : + le32_to_cpup((__force __le32 *)x); } /*-------------------------------------------------------------------------*/ @@ -557,6 +605,9 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all * hardware handles 16 bit reads. That creates a different confusion on * some big-endian SOC implementations. Same thing happens with PSW access. + * + * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over + * to arch/powerpc */ #ifdef CONFIG_STB03xxx @@ -568,7 +619,7 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) { u32 tmp; - if (big_endian(ohci)) { + if (big_endian_desc(ohci)) { tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no); tmp >>= OHCI_BE_FRAME_NO_SHIFT; } else @@ -580,7 +631,7 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci, const struct td *td, int index) { - return (__hc16 *)(big_endian(ohci) ? + return (__hc16 *)(big_endian_desc(ohci) ? &td->hwPSW[index ^ 1] : &td->hwPSW[index]); } diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index e345f15b7d87..5d6c06bc4524 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -168,9 +168,13 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) space, "", qh, qtype, le32_to_cpu(qh->link), le32_to_cpu(element)); if (qh->type == USB_ENDPOINT_XFER_ISOC) - out += sprintf(out, "%*s period %d frame %x desc [%p]\n", - space, "", qh->period, qh->iso_frame, - qh->iso_packet_desc); + out += sprintf(out, "%*s period %d phase %d load %d us, " + "frame %x desc [%p]\n", + space, "", qh->period, qh->phase, qh->load, + qh->iso_frame, qh->iso_packet_desc); + else if (qh->type == USB_ENDPOINT_XFER_INT) + out += sprintf(out, "%*s period %d phase %d load %d us\n", + space, "", qh->period, qh->phase, qh->load); if (element & UHCI_PTR_QH) out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); @@ -208,7 +212,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) space, "", nurbs); } - if (qh->udev) { + if (qh->dummy_td) { out += sprintf(out, "%*s Dummy TD\n", space, ""); out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0); } @@ -347,31 +351,80 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) struct uhci_qh *qh; struct uhci_td *td; struct list_head *tmp, *head; + int nframes, nerrs; out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); out += sprintf(out, "HC status\n"); out += uhci_show_status(uhci, out, len - (out - buf)); + + out += sprintf(out, "Periodic load table\n"); + for (i = 0; i < MAX_PHASE; ++i) { + out += sprintf(out, "\t%d", uhci->load[i]); + if (i % 8 == 7) + *out++ = '\n'; + } + out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n", + uhci->total_load, + uhci_to_hcd(uhci)->self.bandwidth_int_reqs, + uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs); if (debug <= 1) return out - buf; out += sprintf(out, "Frame List\n"); + nframes = 10; + nerrs = 0; for (i = 0; i < UHCI_NUMFRAMES; ++i) { - td = uhci->frame_cpu[i]; - if (!td) - continue; + __le32 link, qh_dma; - out += sprintf(out, "- Frame %d\n", i); \ - if (td->dma_handle != (dma_addr_t)uhci->frame[i]) - out += sprintf(out, " frame list does not match td->dma_handle!\n"); + j = 0; + td = uhci->frame_cpu[i]; + link = uhci->frame[i]; + if (!td) + goto check_link; + + if (nframes > 0) { + out += sprintf(out, "- Frame %d -> (%08x)\n", + i, le32_to_cpu(link)); + j = 1; + } head = &td->fl_list; tmp = head; do { td = list_entry(tmp, struct uhci_td, fl_list); tmp = tmp->next; - out += uhci_show_td(td, out, len - (out - buf), 4); + if (cpu_to_le32(td->dma_handle) != link) { + if (nframes > 0) + out += sprintf(out, " link does " + "not match list entry!\n"); + else + ++nerrs; + } + if (nframes > 0) + out += uhci_show_td(td, out, + len - (out - buf), 4); + link = td->link; } while (tmp != head); + +check_link: + qh_dma = uhci_frame_skel_link(uhci, i); + if (link != qh_dma) { + if (nframes > 0) { + if (!j) { + out += sprintf(out, + "- Frame %d -> (%08x)\n", + i, le32_to_cpu(link)); + j = 1; + } + out += sprintf(out, " link does not match " + "QH (%08x)!\n", le32_to_cpu(qh_dma)); + } else + ++nerrs; + } + nframes -= j; } + if (nerrs > 0) + out += sprintf(out, "Skipped %d bad links\n", nerrs); out += sprintf(out, "Skeleton QHs\n"); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index e0d4c2358b39..49b9d390b95f 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -92,6 +92,34 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state); static void wakeup_rh(struct uhci_hcd *uhci); static void uhci_get_current_frame_number(struct uhci_hcd *uhci); +/* + * Calculate the link pointer DMA value for the first Skeleton QH in a frame. + */ +static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame) +{ + int skelnum; + + /* + * The interrupt queues will be interleaved as evenly as possible. + * There's not much to be done about period-1 interrupts; they have + * to occur in every frame. But we can schedule period-2 interrupts + * in odd-numbered frames, period-4 interrupts in frames congruent + * to 2 (mod 4), and so on. This way each frame only has two + * interrupt QHs, which will help spread out bandwidth utilization. + * + * ffs (Find First bit Set) does exactly what we need: + * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8], + * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc. + * ffs >= 7 => not on any high-period queue, so use + * skel_int1_qh = skelqh[9]. + * Add in UHCI_NUMFRAMES to insure at least one bit is set. + */ + skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES); + if (skelnum <= 1) + skelnum = 9; + return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle); +} + #include "uhci-debug.c" #include "uhci-q.c" #include "uhci-hub.c" @@ -631,32 +659,11 @@ static int uhci_start(struct usb_hcd *hcd) /* * Fill the frame list: make all entries point to the proper * interrupt queue. - * - * The interrupt queues will be interleaved as evenly as possible. - * There's not much to be done about period-1 interrupts; they have - * to occur in every frame. But we can schedule period-2 interrupts - * in odd-numbered frames, period-4 interrupts in frames congruent - * to 2 (mod 4), and so on. This way each frame only has two - * interrupt QHs, which will help spread out bandwidth utilization. */ for (i = 0; i < UHCI_NUMFRAMES; i++) { - int irq; - - /* - * ffs (Find First bit Set) does exactly what we need: - * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8], - * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc. - * ffs >= 7 => not on any high-period queue, so use - * skel_int1_qh = skelqh[9]. - * Add UHCI_NUMFRAMES to insure at least one bit is set. - */ - irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES); - if (irq <= 1) - irq = 9; /* Only place we don't use the frame list routines */ - uhci->frame[i] = UHCI_PTR_QH | - cpu_to_le32(uhci->skelqh[irq]->dma_handle); + uhci->frame[i] = uhci_frame_skel_link(uhci, i); } /* diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 108e3de2dc26..74469b5bcb61 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -83,6 +83,7 @@ #define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */ #define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames * can be scheduled */ +#define MAX_PHASE 32 /* Periodic scheduling length */ /* When no queues need Full-Speed Bandwidth Reclamation, * delay this long before turning FSBR off */ @@ -141,6 +142,8 @@ struct uhci_qh { unsigned long advance_jiffies; /* Time of last queue advance */ unsigned int unlink_frame; /* When the QH was unlinked */ unsigned int period; /* For Interrupt and Isochronous QHs */ + short phase; /* Between 0 and period-1 */ + short load; /* Periodic time requirement, in us */ unsigned int iso_frame; /* Frame # for iso_packet_desc */ int iso_status; /* Status for Isochronous URBs */ @@ -153,6 +156,8 @@ struct uhci_qh { unsigned int needs_fixup:1; /* Must fix the TD toggle values */ unsigned int is_stopped:1; /* Queue was stopped by error/unlink */ unsigned int wait_expired:1; /* QH_WAIT_TIMEOUT has expired */ + unsigned int bandwidth_reserved:1; /* Periodic bandwidth has + * been allocated */ } __attribute__((aligned(16))); /* @@ -414,6 +419,9 @@ struct uhci_hcd { wait_queue_head_t waitqh; /* endpoint_disable waiters */ int num_waiting; /* Number of waiters */ + + int total_load; /* Sum of array values */ + short load[MAX_PHASE]; /* Periodic allocations */ }; /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 30b88459ac7d..2cbb239e63f8 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -248,16 +248,26 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, INIT_LIST_HEAD(&qh->node); if (udev) { /* Normal QH */ - qh->dummy_td = uhci_alloc_td(uhci); - if (!qh->dummy_td) { - dma_pool_free(uhci->qh_pool, qh, dma_handle); - return NULL; + qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + if (qh->type != USB_ENDPOINT_XFER_ISOC) { + qh->dummy_td = uhci_alloc_td(uhci); + if (!qh->dummy_td) { + dma_pool_free(uhci->qh_pool, qh, dma_handle); + return NULL; + } } qh->state = QH_STATE_IDLE; qh->hep = hep; qh->udev = udev; hep->hcpriv = qh; - qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + + if (qh->type == USB_ENDPOINT_XFER_INT || + qh->type == USB_ENDPOINT_XFER_ISOC) + qh->load = usb_calc_bus_time(udev->speed, + usb_endpoint_dir_in(&hep->desc), + qh->type == USB_ENDPOINT_XFER_ISOC, + le16_to_cpu(hep->desc.wMaxPacketSize)) + / 1000 + 1; } else { /* Skeleton QH */ qh->state = QH_STATE_ACTIVE; @@ -275,7 +285,8 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) list_del(&qh->node); if (qh->udev) { qh->hep->hcpriv = NULL; - uhci_free_td(uhci, qh->dummy_td); + if (qh->dummy_td) + uhci_free_td(uhci, qh->dummy_td); } dma_pool_free(uhci->qh_pool, qh, qh->dma_handle); } @@ -327,7 +338,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh, goto done; qh->element = UHCI_PTR_TERM; - /* Control pipes have to worry about toggles */ + /* Control pipes don't have to worry about toggles */ if (qh->type == USB_ENDPOINT_XFER_CONTROL) goto done; @@ -493,6 +504,121 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh) wake_up_all(&uhci->waitqh); } +/* + * Find the highest existing bandwidth load for a given phase and period. + */ +static int uhci_highest_load(struct uhci_hcd *uhci, int phase, int period) +{ + int highest_load = uhci->load[phase]; + + for (phase += period; phase < MAX_PHASE; phase += period) + highest_load = max_t(int, highest_load, uhci->load[phase]); + return highest_load; +} + +/* + * Set qh->phase to the optimal phase for a periodic transfer and + * check whether the bandwidth requirement is acceptable. + */ +static int uhci_check_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + int minimax_load; + + /* Find the optimal phase (unless it is already set) and get + * its load value. */ + if (qh->phase >= 0) + minimax_load = uhci_highest_load(uhci, qh->phase, qh->period); + else { + int phase, load; + int max_phase = min_t(int, MAX_PHASE, qh->period); + + qh->phase = 0; + minimax_load = uhci_highest_load(uhci, qh->phase, qh->period); + for (phase = 1; phase < max_phase; ++phase) { + load = uhci_highest_load(uhci, phase, qh->period); + if (load < minimax_load) { + minimax_load = load; + qh->phase = phase; + } + } + } + + /* Maximum allowable periodic bandwidth is 90%, or 900 us per frame */ + if (minimax_load + qh->load > 900) { + dev_dbg(uhci_dev(uhci), "bandwidth allocation failed: " + "period %d, phase %d, %d + %d us\n", + qh->period, qh->phase, minimax_load, qh->load); + return -ENOSPC; + } + return 0; +} + +/* + * Reserve a periodic QH's bandwidth in the schedule + */ +static void uhci_reserve_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + int i; + int load = qh->load; + char *p = "??"; + + for (i = qh->phase; i < MAX_PHASE; i += qh->period) { + uhci->load[i] += load; + uhci->total_load += load; + } + uhci_to_hcd(uhci)->self.bandwidth_allocated = + uhci->total_load / MAX_PHASE; + switch (qh->type) { + case USB_ENDPOINT_XFER_INT: + ++uhci_to_hcd(uhci)->self.bandwidth_int_reqs; + p = "INT"; + break; + case USB_ENDPOINT_XFER_ISOC: + ++uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs; + p = "ISO"; + break; + } + qh->bandwidth_reserved = 1; + dev_dbg(uhci_dev(uhci), + "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n", + "reserve", qh->udev->devnum, + qh->hep->desc.bEndpointAddress, p, + qh->period, qh->phase, load); +} + +/* + * Release a periodic QH's bandwidth reservation + */ +static void uhci_release_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + int i; + int load = qh->load; + char *p = "??"; + + for (i = qh->phase; i < MAX_PHASE; i += qh->period) { + uhci->load[i] -= load; + uhci->total_load -= load; + } + uhci_to_hcd(uhci)->self.bandwidth_allocated = + uhci->total_load / MAX_PHASE; + switch (qh->type) { + case USB_ENDPOINT_XFER_INT: + --uhci_to_hcd(uhci)->self.bandwidth_int_reqs; + p = "INT"; + break; + case USB_ENDPOINT_XFER_ISOC: + --uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs; + p = "ISO"; + break; + } + qh->bandwidth_reserved = 0; + dev_dbg(uhci_dev(uhci), + "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n", + "release", qh->udev->devnum, + qh->hep->desc.bEndpointAddress, p, + qh->period, qh->phase, load); +} + static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb) { @@ -796,7 +922,6 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, wmb(); qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE); qh->dummy_td = td; - qh->period = urb->interval; usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle); @@ -827,28 +952,42 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct uhci_qh *qh) { - int exponent; + int ret; /* USB 1.1 interrupt transfers only involve one packet per interval. * Drivers can submit URBs of any length, but longer ones will need * multiple intervals to complete. */ - /* Figure out which power-of-two queue to use */ - for (exponent = 7; exponent >= 0; --exponent) { - if ((1 << exponent) <= urb->interval) - break; - } - if (exponent < 0) - return -EINVAL; - urb->interval = 1 << exponent; + if (!qh->bandwidth_reserved) { + int exponent; - if (qh->period == 0) + /* Figure out which power-of-two queue to use */ + for (exponent = 7; exponent >= 0; --exponent) { + if ((1 << exponent) <= urb->interval) + break; + } + if (exponent < 0) + return -EINVAL; + qh->period = 1 << exponent; qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)]; - else if (qh->period != urb->interval) - return -EINVAL; /* Can't change the period */ - return uhci_submit_common(uhci, urb, qh); + /* For now, interrupt phase is fixed by the layout + * of the QH lists. */ + qh->phase = (qh->period / 2) & (MAX_PHASE - 1); + ret = uhci_check_bandwidth(uhci, qh); + if (ret) + return ret; + } else if (qh->period > urb->interval) + return -EINVAL; /* Can't decrease the period */ + + ret = uhci_submit_common(uhci, urb, qh); + if (ret == 0) { + urb->interval = qh->period; + if (!qh->bandwidth_reserved) + uhci_reserve_bandwidth(uhci, qh); + } + return ret; } /* @@ -995,15 +1134,32 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, return -EFBIG; /* Check the period and figure out the starting frame number */ - if (qh->period == 0) { + if (!qh->bandwidth_reserved) { + qh->period = urb->interval; if (urb->transfer_flags & URB_ISO_ASAP) { + qh->phase = -1; /* Find the best phase */ + i = uhci_check_bandwidth(uhci, qh); + if (i) + return i; + + /* Allow a little time to allocate the TDs */ uhci_get_current_frame_number(uhci); - urb->start_frame = uhci->frame_number + 10; + frame = uhci->frame_number + 10; + + /* Move forward to the first frame having the + * correct phase */ + urb->start_frame = frame + ((qh->phase - frame) & + (qh->period - 1)); } else { i = urb->start_frame - uhci->last_iso_frame; if (i <= 0 || i >= UHCI_NUMFRAMES) return -EINVAL; + qh->phase = urb->start_frame & (qh->period - 1); + i = uhci_check_bandwidth(uhci, qh); + if (i) + return i; } + } else if (qh->period != urb->interval) { return -EINVAL; /* Can't change the period */ @@ -1049,9 +1205,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, /* Set the interrupt-on-completion flag on the last packet. */ td->status |= __constant_cpu_to_le32(TD_CTRL_IOC); - qh->skel = uhci->skel_iso_qh; - qh->period = urb->interval; - /* Add the TDs to the frame list */ frame = urb->start_frame; list_for_each_entry(td, &urbp->td_list, list) { @@ -1065,6 +1218,9 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, qh->iso_status = 0; } + qh->skel = uhci->skel_iso_qh; + if (!qh->bandwidth_reserved) + uhci_reserve_bandwidth(uhci, qh); return 0; } @@ -1119,7 +1275,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, unsigned long flags; struct urb_priv *urbp; struct uhci_qh *qh; - int bustime; spin_lock_irqsave(&uhci->lock, flags); @@ -1149,35 +1304,11 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, ret = uhci_submit_bulk(uhci, urb, qh); break; case USB_ENDPOINT_XFER_INT: - if (list_empty(&qh->queue)) { - bustime = usb_check_bandwidth(urb->dev, urb); - if (bustime < 0) - ret = bustime; - else { - ret = uhci_submit_interrupt(uhci, urb, qh); - if (ret == 0) - usb_claim_bandwidth(urb->dev, urb, bustime, 0); - } - } else { /* inherit from parent */ - struct urb_priv *eurbp; - - eurbp = list_entry(qh->queue.prev, struct urb_priv, - node); - urb->bandwidth = eurbp->urb->bandwidth; - ret = uhci_submit_interrupt(uhci, urb, qh); - } + ret = uhci_submit_interrupt(uhci, urb, qh); break; case USB_ENDPOINT_XFER_ISOC: urb->error_count = 0; - bustime = usb_check_bandwidth(urb->dev, urb); - if (bustime < 0) { - ret = bustime; - break; - } - ret = uhci_submit_isochronous(uhci, urb, qh); - if (ret == 0) - usb_claim_bandwidth(urb->dev, urb, bustime, 1); break; } if (ret != 0) @@ -1274,24 +1405,6 @@ __acquires(uhci->lock) uhci_free_urb_priv(uhci, urbp); - switch (qh->type) { - case USB_ENDPOINT_XFER_ISOC: - /* Release bandwidth for Interrupt or Isoc. transfers */ - if (urb->bandwidth) - usb_release_bandwidth(urb->dev, urb, 1); - break; - case USB_ENDPOINT_XFER_INT: - /* Release bandwidth for Interrupt or Isoc. transfers */ - /* Make sure we don't release if we have a queued URB */ - if (list_empty(&qh->queue) && urb->bandwidth) - usb_release_bandwidth(urb->dev, urb, 0); - else - /* bandwidth was passed on to queued URB, */ - /* so don't let usb_unlink_urb() release it */ - urb->bandwidth = 0; - break; - } - spin_unlock(&uhci->lock); usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb); spin_lock(&uhci->lock); @@ -1300,9 +1413,8 @@ __acquires(uhci->lock) * reserved bandwidth. */ if (list_empty(&qh->queue)) { uhci_unlink_qh(uhci, qh); - - /* Bandwidth stuff not yet implemented */ - qh->period = 0; + if (qh->bandwidth_reserved) + uhci_release_bandwidth(uhci, qh); } } diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index 63a84bbc310d..d308afd06935 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -565,11 +565,15 @@ static void mdc800_usb_disconnect (struct usb_interface *intf) usb_deregister_dev(intf, &mdc800_class); + /* must be under lock to make sure no URB + is submitted after usb_kill_urb() */ + mutex_lock(&mdc800->io_lock); mdc800->state=NOT_CONNECTED; usb_kill_urb(mdc800->irq_urb); usb_kill_urb(mdc800->write_urb); usb_kill_urb(mdc800->download_urb); + mutex_unlock(&mdc800->io_lock); mdc800->dev = NULL; usb_set_intfdata(intf, NULL); diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index c7d887540d8d..2e71d3cca198 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 @@ -344,3 +352,15 @@ config USB_APPLETOUCH To compile this driver as a module, choose M here: the module will be called appletouch. + +config USB_GTCO + tristate "GTCO CalComp/InterWrite USB Support" + depends on USB && INPUT + ---help--- + Say Y here if you want to use the USB version of the GTCO + CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + To compile this driver as a module, choose M here: the + module will be called gtco. diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 1a24b5bfa05f..a9d206c945e9 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 @@ -45,6 +48,7 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o obj-$(CONFIG_USB_YEALINK) += yealink.o obj-$(CONFIG_USB_XPAD) += xpad.o obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o +obj-$(CONFIG_USB_GTCO) += gtco.o ifeq ($(CONFIG_USB_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/usb/input/gtco.c b/drivers/usb/input/gtco.c new file mode 100644 index 000000000000..203cdc1bbba4 --- /dev/null +++ b/drivers/usb/input/gtco.c @@ -0,0 +1,1104 @@ +/* -*- linux-c -*- + +GTCO digitizer USB driver + +Use the err(), dbg() and info() macros from usb.h for system logging + +TO CHECK: Is pressure done right on report 5? + +Copyright (C) 2006 GTCO CalComp + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation, and that the name of GTCO-CalComp not be used in advertising +or publicity pertaining to distribution of the software without specific, +written prior permission. GTCO-CalComp makes no representations about the +suitability of this software for any purpose. It is provided "as is" +without express or implied warranty. + +GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +GTCO CalComp, Inc. +7125 Riverwood Drive +Columbia, MD 21046 + +Jeremy Roberson jroberson@gtcocalcomp.com +Scott Hill shill@gtcocalcomp.com +*/ + + + +/*#define DEBUG*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +/* Version with a Major number of 2 is for kernel inclusion only. */ +#define GTCO_VERSION "2.00.0006" + + +/* MACROS */ + +#define VENDOR_ID_GTCO 0x078C +#define PID_400 0x400 +#define PID_401 0x401 +#define PID_1000 0x1000 +#define PID_1001 0x1001 +#define PID_1002 0x1002 + +/* Max size of a single report */ +#define REPORT_MAX_SIZE 10 + + +/* Bitmask whether pen is in range */ +#define MASK_INRANGE 0x20 +#define MASK_BUTTON 0x01F + +#define PATHLENGTH 64 + +/* DATA STRUCTURES */ + +/* Device table */ +static struct usb_device_id gtco_usbid_table [] = { + { USB_DEVICE(VENDOR_ID_GTCO, PID_400) }, + { USB_DEVICE(VENDOR_ID_GTCO, PID_401) }, + { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) }, + { USB_DEVICE(VENDOR_ID_GTCO, PID_1001) }, + { USB_DEVICE(VENDOR_ID_GTCO, PID_1002) }, + { } +}; +MODULE_DEVICE_TABLE (usb, gtco_usbid_table); + + +/* Structure to hold all of our device specific stuff */ +struct gtco { + + struct input_dev *inputdevice; /* input device struct pointer */ + struct usb_device *usbdev; /* the usb device for this device */ + struct urb *urbinfo; /* urb for incoming reports */ + dma_addr_t buf_dma; /* dma addr of the data buffer*/ + unsigned char * buffer; /* databuffer for reports */ + + char usbpath[PATHLENGTH]; + int openCount; + + /* Information pulled from Report Descriptor */ + u32 usage; + u32 min_X; + u32 max_X; + u32 min_Y; + u32 max_Y; + s8 mintilt_X; + s8 maxtilt_X; + s8 mintilt_Y; + s8 maxtilt_Y; + u32 maxpressure; + u32 minpressure; +}; + + + +/* Code for parsing the HID REPORT DESCRIPTOR */ + +/* From HID1.11 spec */ +struct hid_descriptor +{ + struct usb_descriptor_header header; + __le16 bcdHID; + u8 bCountryCode; + u8 bNumDescriptors; + u8 bDescriptorType; + __le16 wDescriptorLength; +} __attribute__ ((packed)); + + +#define HID_DESCRIPTOR_SIZE 9 +#define HID_DEVICE_TYPE 33 +#define REPORT_DEVICE_TYPE 34 + + +#define PREF_TAG(x) ((x)>>4) +#define PREF_TYPE(x) ((x>>2)&0x03) +#define PREF_SIZE(x) ((x)&0x03) + +#define TYPE_MAIN 0 +#define TYPE_GLOBAL 1 +#define TYPE_LOCAL 2 +#define TYPE_RESERVED 3 + +#define TAG_MAIN_INPUT 0x8 +#define TAG_MAIN_OUTPUT 0x9 +#define TAG_MAIN_FEATURE 0xB +#define TAG_MAIN_COL_START 0xA +#define TAG_MAIN_COL_END 0xC + +#define TAG_GLOB_USAGE 0 +#define TAG_GLOB_LOG_MIN 1 +#define TAG_GLOB_LOG_MAX 2 +#define TAG_GLOB_PHYS_MIN 3 +#define TAG_GLOB_PHYS_MAX 4 +#define TAG_GLOB_UNIT_EXP 5 +#define TAG_GLOB_UNIT 6 +#define TAG_GLOB_REPORT_SZ 7 +#define TAG_GLOB_REPORT_ID 8 +#define TAG_GLOB_REPORT_CNT 9 +#define TAG_GLOB_PUSH 10 +#define TAG_GLOB_POP 11 + +#define TAG_GLOB_MAX 12 + +#define DIGITIZER_USAGE_TIP_PRESSURE 0x30 +#define DIGITIZER_USAGE_TILT_X 0x3D +#define DIGITIZER_USAGE_TILT_Y 0x3E + + +/* + * + * This is an abbreviated parser for the HID Report Descriptor. We + * know what devices we are talking to, so this is by no means meant + * to be generic. We can make some safe assumptions: + * + * - We know there are no LONG tags, all short + * - We know that we have no MAIN Feature and MAIN Output items + * - We know what the IRQ reports are supposed to look like. + * + * The main purpose of this is to use the HID report desc to figure + * out the mins and maxs of the fields in the IRQ reports. The IRQ + * reports for 400/401 change slightly if the max X is bigger than 64K. + * + */ +static void parse_hid_report_descriptor(struct gtco *device, char * report, + int length) +{ + int x,i=0; + + /* Tag primitive vars */ + __u8 prefix; + __u8 size; + __u8 tag; + __u8 type; + __u8 data = 0; + __u16 data16 = 0; + __u32 data32 = 0; + + + /* For parsing logic */ + int inputnum = 0; + __u32 usage = 0; + + /* Global Values, indexed by TAG */ + __u32 globalval[TAG_GLOB_MAX]; + __u32 oldval[TAG_GLOB_MAX]; + + /* Debug stuff */ + char maintype='x'; + char globtype[12]; + int indent=0; + char indentstr[10]=""; + + + + dbg("======>>>>>>PARSE<<<<<<======"); + + /* Walk this report and pull out the info we need */ + while (imax_X == 0){ + device->max_X = globalval[TAG_GLOB_LOG_MAX]; + device->min_X = globalval[TAG_GLOB_LOG_MIN]; + } + + break; + case 1: /* Y coord */ + dbg("GER: Y Usage: 0x%x",usage); + if (device->max_Y == 0){ + device->max_Y = globalval[TAG_GLOB_LOG_MAX]; + device->min_Y = globalval[TAG_GLOB_LOG_MIN]; + } + break; + default: + /* Tilt X */ + if (usage == DIGITIZER_USAGE_TILT_X){ + if (device->maxtilt_X == 0){ + device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX]; + device->mintilt_X = globalval[TAG_GLOB_LOG_MIN]; + } + } + + /* Tilt Y */ + if (usage == DIGITIZER_USAGE_TILT_Y){ + if (device->maxtilt_Y == 0){ + device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX]; + device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN]; + } + } + + + /* Pressure */ + if (usage == DIGITIZER_USAGE_TIP_PRESSURE){ + if (device->maxpressure == 0){ + device->maxpressure = globalval[TAG_GLOB_LOG_MAX]; + device->minpressure = globalval[TAG_GLOB_LOG_MIN]; + } + } + + break; + } + + inputnum++; + + + break; + case TAG_MAIN_OUTPUT: + maintype='O'; + break; + case TAG_MAIN_FEATURE: + maintype='F'; + break; + case TAG_MAIN_COL_START: + maintype='S'; + + if (data==0){ + dbg("======>>>>>> Physical"); + strcpy(globtype,"Physical"); + }else{ + dbg("======>>>>>>"); + } + + /* Indent the debug output */ + indent++; + for (x=0;xusage == 0){ + device->usage = data; + } + strcpy(globtype,"USAGE"); + break; + case TAG_GLOB_LOG_MIN : + strcpy(globtype,"LOG_MIN"); + break; + case TAG_GLOB_LOG_MAX : + strcpy(globtype,"LOG_MAX"); + break; + case TAG_GLOB_PHYS_MIN : + strcpy(globtype,"PHYS_MIN"); + break; + case TAG_GLOB_PHYS_MAX : + strcpy(globtype,"PHYS_MAX"); + break; + case TAG_GLOB_UNIT_EXP : + strcpy(globtype,"EXP"); + break; + case TAG_GLOB_UNIT : + strcpy(globtype,"UNIT"); + break; + case TAG_GLOB_REPORT_SZ : + strcpy(globtype,"REPORT_SZ"); + break; + case TAG_GLOB_REPORT_ID : + strcpy(globtype,"REPORT_ID"); + /* New report, restart numbering */ + inputnum=0; + break; + case TAG_GLOB_REPORT_CNT: + strcpy(globtype,"REPORT_CNT"); + break; + case TAG_GLOB_PUSH : + strcpy(globtype,"PUSH"); + break; + case TAG_GLOB_POP: + strcpy(globtype,"POP"); + break; + } + + + /* Check to make sure we have a good tag number + so we don't overflow array */ + if (tag < TAG_GLOB_MAX){ + switch (size){ + case 1: + dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data); + globalval[tag]=data; + break; + case 2: + dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16); + globalval[tag]=data16; + break; + case 4: + dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32); + globalval[tag]=data32; + break; + } + }else{ + dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ", + indentstr,tag,size); + } + + + break; + + case TYPE_LOCAL: + switch(tag){ + case TAG_GLOB_USAGE: + strcpy(globtype,"USAGE"); + /* Always 1 byte */ + usage = data; + break; + case TAG_GLOB_LOG_MIN : + strcpy(globtype,"MIN"); + break; + case TAG_GLOB_LOG_MAX : + strcpy(globtype,"MAX"); + break; + default: + strcpy(globtype,"UNKNOWN"); + } + + switch (size){ + case 1: + dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", + indentstr,tag,globtype,size,data); + break; + case 2: + dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", + indentstr,tag,globtype,size,data16); + break; + case 4: + dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x", + indentstr,tag,globtype,size,data32); + break; + } + + break; + } + + } + +} + + + +/* INPUT DRIVER Routines */ + + +/* + * Called when opening the input device. This will submit the URB to + * the usb system so we start getting reports + */ +static int gtco_input_open(struct input_dev *inputdev) +{ + struct gtco *device; + device = inputdev->private; + + device->urbinfo->dev = device->usbdev; + if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) { + return -EIO; + } + return 0; +} + +/** + Called when closing the input device. This will unlink the URB +*/ +static void gtco_input_close(struct input_dev *inputdev) +{ + struct gtco *device = inputdev->private; + + usb_kill_urb(device->urbinfo); + +} + + +/* + * Setup input device capabilities. Tell the input system what this + * device is capable of generating. + * + * This information is based on what is read from the HID report and + * placed in the struct gtco structure + * + */ +static void gtco_setup_caps(struct input_dev *inputdev) +{ + struct gtco *device = inputdev->private; + + + /* Which events */ + inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC); + + + /* Misc event menu block */ + inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ; + + + /* Absolute values based on HID report info */ + input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X, + 0, 0); + input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y, + 0, 0); + + /* Proximity */ + input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0); + + /* Tilt & pressure */ + input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X, + device->maxtilt_X, 0, 0); + input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y, + device->maxtilt_Y, 0, 0); + input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure, + device->maxpressure, 0, 0); + + + /* Transducer */ + input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0); + +} + + + +/* USB Routines */ + + +/* + * URB callback routine. Called when we get IRQ reports from the + * digitizer. + * + * This bridges the USB and input device worlds. It generates events + * on the input device based on the USB reports. + */ +static void gtco_urb_callback(struct urb *urbinfo) +{ + + + struct gtco *device = urbinfo->context; + struct input_dev *inputdev; + int rc; + u32 val = 0; + s8 valsigned = 0; + char le_buffer[2]; + + inputdev = device->inputdevice; + + + /* Was callback OK? */ + if ((urbinfo->status == -ECONNRESET ) || + (urbinfo->status == -ENOENT ) || + (urbinfo->status == -ESHUTDOWN )){ + + /* Shutdown is occurring. Return and don't queue up any more */ + return; + } + + if (urbinfo->status != 0 ) { + /* Some unknown error. Hopefully temporary. Just go and */ + /* requeue an URB */ + goto resubmit; + } + + /* + * Good URB, now process + */ + + /* PID dependent when we interpret the report */ + if ((inputdev->id.product == PID_1000 )|| + (inputdev->id.product == PID_1001 )|| + (inputdev->id.product == PID_1002 )) + { + + /* + * Switch on the report ID + * Conveniently, the reports have more information, the higher + * the report number. We can just fall through the case + * statements if we start with the highest number report + */ + switch(device->buffer[0]){ + case 5: + /* Pressure is 9 bits */ + val = ((u16)(device->buffer[8]) << 1); + val |= (u16)(device->buffer[7] >> 7); + input_report_abs(inputdev, ABS_PRESSURE, + device->buffer[8]); + + /* Mask out the Y tilt value used for pressure */ + device->buffer[7] = (u8)((device->buffer[7]) & 0x7F); + + + /* Fall thru */ + case 4: + /* Tilt */ + + /* Sign extend these 7 bit numbers. */ + if (device->buffer[6] & 0x40) + device->buffer[6] |= 0x80; + + if (device->buffer[7] & 0x40) + device->buffer[7] |= 0x80; + + + valsigned = (device->buffer[6]); + input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned); + + valsigned = (device->buffer[7]); + input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned); + + /* Fall thru */ + + case 2: + case 3: + /* Convert buttons, only 5 bits possible */ + val = (device->buffer[5])&MASK_BUTTON; + + /* We don't apply any meaning to the bitmask, + just report */ + input_event(inputdev, EV_MSC, MSC_SERIAL, val); + + /* Fall thru */ + case 1: + + /* All reports have X and Y coords in the same place */ + val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1]))); + input_report_abs(inputdev, ABS_X, val); + + val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3]))); + input_report_abs(inputdev, ABS_Y, val); + + + /* Ditto for proximity bit */ + if (device->buffer[5]& MASK_INRANGE){ + val = 1; + }else{ + val=0; + } + input_report_abs(inputdev, ABS_DISTANCE, val); + + + /* Report 1 is an exception to how we handle buttons */ + /* Buttons are an index, not a bitmask */ + if (device->buffer[0] == 1){ + + /* Convert buttons, 5 bit index */ + /* Report value of index set as one, + the rest as 0 */ + val = device->buffer[5]& MASK_BUTTON; + dbg("======>>>>>>REPORT 1: val 0x%X(%d)", + val,val); + + /* + * We don't apply any meaning to the button + * index, just report it + */ + input_event(inputdev, EV_MSC, MSC_SERIAL, val); + + + } + + break; + case 7: + /* Menu blocks */ + input_event(inputdev, EV_MSC, MSC_SCAN, + device->buffer[1]); + + + break; + + } + + + } + /* Other pid class */ + if ((inputdev->id.product == PID_400 )|| + (inputdev->id.product == PID_401 )) + { + + /* Report 2 */ + if (device->buffer[0] == 2){ + /* Menu blocks */ + input_event(inputdev, EV_MSC, MSC_SCAN, + device->buffer[1]); + } + + /* Report 1 */ + if (device->buffer[0] == 1){ + char buttonbyte; + + + /* IF X max > 64K, we still a bit from the y report */ + if (device->max_X > 0x10000){ + + val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1]))); + val |= (u32)(((u8)device->buffer[3]&0x1)<< 16); + + input_report_abs(inputdev, ABS_X, val); + + le_buffer[0] = (u8)((u8)(device->buffer[3])>>1); + le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7); + + le_buffer[1] = (u8)(device->buffer[4]>>1); + le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7); + + val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer))); + + input_report_abs(inputdev, ABS_Y, val); + + + /* + * Shift the button byte right by one to + * make it look like the standard report + */ + buttonbyte = (device->buffer[5])>>1; + }else{ + + val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1])))); + input_report_abs(inputdev, ABS_X, val); + + val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3])))); + input_report_abs(inputdev, ABS_Y, val); + + buttonbyte = device->buffer[5]; + + } + + + /* BUTTONS and PROXIMITY */ + if (buttonbyte& MASK_INRANGE){ + val = 1; + }else{ + val=0; + } + input_report_abs(inputdev, ABS_DISTANCE, val); + + /* Convert buttons, only 4 bits possible */ + val = buttonbyte&0x0F; +#ifdef USE_BUTTONS + for ( i=0;i<5;i++){ + input_report_key(inputdev, BTN_DIGI+i,val&(1<buffer[6]); + + } + } + + /* Everybody gets report ID's */ + input_event(inputdev, EV_MSC, MSC_RAW, device->buffer[0]); + + /* Sync it up */ + input_sync(inputdev); + + resubmit: + rc = usb_submit_urb(urbinfo, GFP_ATOMIC); + if (rc != 0) { + err("usb_submit_urb failed rc=0x%x",rc); + } + +} + +/* + * The probe routine. This is called when the kernel find the matching USB + * vendor/product. We do the following: + * + * - Allocate mem for a local structure to manage the device + * - Request a HID Report Descriptor from the device and parse it to + * find out the device parameters + * - Create an input device and assign it attributes + * - Allocate an URB so the device can talk to us when the input + * queue is open + */ +static int gtco_probe(struct usb_interface *usbinterface, + const struct usb_device_id *id) +{ + + struct gtco *device = NULL; + char path[PATHLENGTH]; + struct input_dev *inputdev; + struct hid_descriptor *hid_desc; + char *report; + int result=0, retry; + struct usb_endpoint_descriptor *endpoint; + + /* Allocate memory for device structure */ + device = kzalloc(sizeof(struct gtco), GFP_KERNEL); + if (device == NULL) { + err("No more memory"); + return -ENOMEM; + } + + + device->inputdevice = input_allocate_device(); + if (!device->inputdevice){ + kfree(device); + err("No more memory"); + return -ENOMEM; + } + + /* Get pointer to the input device */ + inputdev = device->inputdevice; + + /* Save interface information */ + device->usbdev = usb_get_dev(interface_to_usbdev(usbinterface)); + + + /* Allocate some data for incoming reports */ + device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE, + GFP_KERNEL, &(device->buf_dma)); + if (!device->buffer){ + input_free_device(device->inputdevice); + kfree(device); + err("No more memory"); + return -ENOMEM; + } + + /* Allocate URB for reports */ + device->urbinfo = usb_alloc_urb(0, GFP_KERNEL); + if (!device->urbinfo) { + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + input_free_device(device->inputdevice); + kfree(device); + err("No more memory"); + return -ENOMEM; + } + + + /* + * The endpoint is always altsetting 0, we know this since we know + * this device only has one interrupt endpoint + */ + endpoint = &usbinterface->altsetting[0].endpoint[0].desc; + + /* Some debug */ + dbg("gtco # interfaces: %d",usbinterface->num_altsetting); + dbg("num endpoints: %d",usbinterface->cur_altsetting->desc.bNumEndpoints); + dbg("interface class: %d",usbinterface->cur_altsetting->desc.bInterfaceClass); + dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType); + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + dbg("endpoint: we have interrupt endpoint\n"); + + dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen); + + + + /* + * Find the HID descriptor so we can find out the size of the + * HID report descriptor + */ + if (usb_get_extra_descriptor(usbinterface->cur_altsetting, + HID_DEVICE_TYPE,&hid_desc) != 0){ + err("Can't retrieve exta USB descriptor to get hid report descriptor length"); + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + input_free_device(device->inputdevice); + kfree(device); + return -EIO; + } + + dbg("Extra descriptor success: type:%d len:%d", + hid_desc->bDescriptorType, hid_desc->wDescriptorLength); + + if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) { + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + + input_free_device(device->inputdevice); + kfree(device); + err("No more memory"); + return -ENOMEM; + } + + /* Couple of tries to get reply */ + for (retry=0;retry<3;retry++) { + result = usb_control_msg(device->usbdev, + usb_rcvctrlpipe(device->usbdev, 0), + USB_REQ_GET_DESCRIPTOR, + USB_RECIP_INTERFACE | USB_DIR_IN, + (REPORT_DEVICE_TYPE << 8), + 0, /* interface */ + report, + hid_desc->wDescriptorLength, + 5000); /* 5 secs */ + + if (result == hid_desc->wDescriptorLength) + break; + } + + /* If we didn't get the report, fail */ + dbg("usb_control_msg result: :%d", result); + if (result != hid_desc->wDescriptorLength){ + kfree(report); + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + input_free_device(device->inputdevice); + kfree(device); + err("Failed to get HID Report Descriptor of size: %d", + hid_desc->wDescriptorLength); + return -EIO; + } + + + /* Now we parse the report */ + parse_hid_report_descriptor(device,report,result); + + /* Now we delete it */ + kfree(report); + + /* Create a device file node */ + usb_make_path(device->usbdev, path, PATHLENGTH); + sprintf(device->usbpath, "%s/input0", path); + + + /* Set Input device functions */ + inputdev->open = gtco_input_open; + inputdev->close = gtco_input_close; + + /* Set input device information */ + inputdev->name = "GTCO_CalComp"; + inputdev->phys = device->usbpath; + inputdev->private = device; + + + /* Now set up all the input device capabilities */ + gtco_setup_caps(inputdev); + + /* Set input device required ID information */ + usb_to_input_id(device->usbdev, &device->inputdevice->id); + inputdev->cdev.dev = &usbinterface->dev; + + /* Setup the URB, it will be posted later on open of input device */ + endpoint = &usbinterface->altsetting[0].endpoint[0].desc; + + usb_fill_int_urb(device->urbinfo, + device->usbdev, + usb_rcvintpipe(device->usbdev, + endpoint->bEndpointAddress), + device->buffer, + REPORT_MAX_SIZE, + gtco_urb_callback, + device, + endpoint->bInterval); + + device->urbinfo->transfer_dma = device->buf_dma; + device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + + /* Save device pointer in USB interface device */ + usb_set_intfdata(usbinterface, device); + + /* All done, now register the input device */ + input_register_device(inputdev); + + info( "gtco driver created usb: %s\n", path); + return 0; + +} + +/* + * This function is a standard USB function called when the USB device + * is disconnected. We will get rid of the URV, de-register the input + * device, and free up allocated memory + */ +static void gtco_disconnect(struct usb_interface *interface) +{ + + /* Grab private device ptr */ + struct gtco *device = usb_get_intfdata (interface); + struct input_dev *inputdev; + + inputdev = device->inputdevice; + + /* Now reverse all the registration stuff */ + if (device) { + input_unregister_device(inputdev); + usb_kill_urb(device->urbinfo); + usb_free_urb(device->urbinfo); + usb_buffer_free(device->usbdev, REPORT_MAX_SIZE, + device->buffer, device->buf_dma); + kfree(device); + } + + info("gtco driver disconnected"); +} + + +/* STANDARD MODULE LOAD ROUTINES */ + +static struct usb_driver gtco_driverinfo_table = { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)) + .owner = THIS_MODULE, +#endif + .name = "gtco", + .id_table = gtco_usbid_table, + .probe = gtco_probe, + .disconnect = gtco_disconnect, +}; +/* + * Register this module with the USB subsystem + */ +static int __init gtco_init(void) +{ + int rc; + rc = usb_register(>co_driverinfo_table); + if (rc) { + err("usb_register() failed rc=0x%x", rc); + } + printk("GTCO usb driver version: %s",GTCO_VERSION); + return rc; +} + +/* + * Deregister this module with the USB subsystem + */ +static void __exit gtco_exit(void) +{ + usb_deregister(>co_driverinfo_table); +} + +module_init (gtco_init); +module_exit (gtco_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index c6c9e72e5fd9..84983d1b7164 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" /* @@ -220,23 +221,6 @@ static void hid_irq_in(struct urb *urb) } } -/* - * Find a report field with a specified HID usage. - */ -#if 0 -struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type) -{ - struct hid_report *report; - int i; - - list_for_each_entry(report, &hid->report_enum[type].report_list, list) - for (i = 0; i < report->maxfield; i++) - if (report->field[i]->logical == wanted_usage) - return report->field[i]; - return NULL; -} -#endif /* 0 */ - static int hid_submit_out(struct hid_device *hid) { struct hid_report *report; @@ -501,7 +485,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, { int result, retries = 4; - memset(buf,0,size); // Make sure we parse really received data + memset(buf, 0, size); do { result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), @@ -528,18 +512,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 @@ -770,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 @@ -792,6 +765,12 @@ 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 + +#define USB_VENDOR_ID_SONY 0x054c +#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 + /* * Alphabetically sorted blacklist by quirk type. */ @@ -946,19 +925,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 }, @@ -969,6 +950,10 @@ 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 }, + + { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER }, + { 0, 0 } }; @@ -1033,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; @@ -1064,6 +1075,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))) { @@ -1235,8 +1251,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; @@ -1315,13 +1331,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) return -ENODEV; } - /* This only gets called when we are a single-input (most of the - * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is - * only useful in this case, and not for multi-input quirks. */ - if ((hid->claimed & HID_CLAIMED_INPUT) && - !(hid->quirks & HID_QUIRK_MULTI_INPUT)) + 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/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-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/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/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index c9418535bef8..15c70bd048c4 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -269,7 +269,7 @@ static int idmouse_release(struct inode *inode, struct file *file) /* prevent a race condition with open() */ mutex_lock(&disconnect_mutex); - dev = (struct usb_idmouse *) file->private_data; + dev = file->private_data; if (dev == NULL) { mutex_unlock(&disconnect_mutex); @@ -304,17 +304,15 @@ static int idmouse_release(struct inode *inode, struct file *file) static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos) { - struct usb_idmouse *dev; + struct usb_idmouse *dev = file->private_data; int result; - dev = (struct usb_idmouse *) file->private_data; - /* lock this object */ - down (&dev->sem); + down(&dev->sem); /* verify that the device wasn't unplugged */ if (!dev->present) { - up (&dev->sem); + up(&dev->sem); return -ENODEV; } diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index 384fa3769805..fdf68479a166 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -69,7 +69,7 @@ struct rio_usb_data { char *obuf, *ibuf; /* transfer buffers */ char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */ wait_queue_head_t wait_q; /* for timeouts */ - struct semaphore lock; /* general race avoidance */ + struct mutex lock; /* general race avoidance */ }; static struct rio_usb_data rio_instance; @@ -78,17 +78,17 @@ static int open_rio(struct inode *inode, struct file *file) { struct rio_usb_data *rio = &rio_instance; - down(&(rio->lock)); + mutex_lock(&(rio->lock)); if (rio->isopen || !rio->present) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -EBUSY; } rio->isopen = 1; init_waitqueue_head(&rio->wait_q); - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); info("Rio opened."); @@ -117,7 +117,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd, int retries; int retval=0; - down(&(rio->lock)); + mutex_lock(&(rio->lock)); /* Sanity check to make sure rio is connected, powered, etc */ if ( rio == NULL || rio->present == 0 || @@ -257,7 +257,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd, err_out: - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return retval; } @@ -275,14 +275,17 @@ write_rio(struct file *file, const char __user *buffer, int result = 0; int maxretry; int errn = 0; + int intr; - down(&(rio->lock)); + intr = mutex_lock_interruptible(&(rio->lock)); + if (intr) + return -EINTR; /* Sanity check to make sure rio is connected, powered, etc */ if ( rio == NULL || rio->present == 0 || rio->rio_dev == NULL ) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -ENODEV; } @@ -305,7 +308,7 @@ write_rio(struct file *file, const char __user *buffer, goto error; } if (signal_pending(current)) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return bytes_written ? bytes_written : -EINTR; } @@ -341,12 +344,12 @@ write_rio(struct file *file, const char __user *buffer, buffer += copy_size; } while (count > 0); - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return bytes_written ? bytes_written : -EIO; error: - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return errn; } @@ -361,14 +364,17 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) int result; int maxretry = 10; char *ibuf; + int intr; - down(&(rio->lock)); + intr = mutex_lock_interruptible(&(rio->lock)); + if (intr) + return -EINTR; /* Sanity check to make sure rio is connected, powered, etc */ if ( rio == NULL || rio->present == 0 || rio->rio_dev == NULL ) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -ENODEV; } @@ -379,11 +385,11 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) while (count > 0) { if (signal_pending(current)) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return read_count ? read_count : -EINTR; } if (!rio->rio_dev) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -ENODEV; } this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count; @@ -400,7 +406,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) count = this_read = partial; } else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */ if (!maxretry--) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); err("read_rio: maxretry timeout"); return -ETIME; } @@ -409,18 +415,18 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) finish_wait(&rio->wait_q, &wait); continue; } else if (result != -EREMOTEIO) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); err("Read Whoops - result:%u partial:%u this_read:%u", result, partial, this_read); return -EIO; } else { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return (0); } if (this_read) { if (copy_to_user(buffer, ibuf, this_read)) { - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return -EFAULT; } count -= this_read; @@ -428,7 +434,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) buffer += this_read; } } - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return read_count; } @@ -480,7 +486,7 @@ static int probe_rio(struct usb_interface *intf, } dbg("probe_rio: ibuf address:%p", rio->ibuf); - init_MUTEX(&(rio->lock)); + mutex_init(&(rio->lock)); usb_set_intfdata (intf, rio); rio->present = 1; @@ -496,12 +502,12 @@ static void disconnect_rio(struct usb_interface *intf) if (rio) { usb_deregister_dev(intf, &usb_rio_class); - down(&(rio->lock)); + mutex_lock(&(rio->lock)); if (rio->isopen) { rio->isopen = 0; /* better let it finish - the release will do whats needed */ rio->rio_dev = NULL; - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); return; } kfree(rio->ibuf); @@ -510,7 +516,7 @@ static void disconnect_rio(struct usb_interface *intf) info("USB Rio disconnected."); rio->present = 0; - up(&(rio->lock)); + mutex_unlock(&(rio->lock)); } } diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile index 3cf3ea3a88ed..90c59535778d 100644 --- a/drivers/usb/mon/Makefile +++ b/drivers/usb/mon/Makefile @@ -2,7 +2,7 @@ # Makefile for USB Core files and filesystem # -usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_dma.o +usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o # This does not use CONFIG_USB_MON because we want this to use a tristate. obj-$(CONFIG_USB) += usbmon.o diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c new file mode 100644 index 000000000000..c01dfe603672 --- /dev/null +++ b/drivers/usb/mon/mon_bin.c @@ -0,0 +1,1172 @@ +/* + * The USB Monitor, inspired by Dave Harding's USBMon. + * + * This is a binary format reader. + * + * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it) + * Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "usb_mon.h" + +/* + * Defined by USB 2.0 clause 9.3, table 9.2. + */ +#define SETUP_LEN 8 + +/* ioctl macros */ +#define MON_IOC_MAGIC 0x92 + +#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1) +/* #2 used to be MON_IOCX_URB, removed before it got into Linus tree */ +#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) +#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4) +#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5) +#define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get) +#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch) +#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8) +#ifdef CONFIG_COMPAT +#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32) +#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32) +#endif + +/* + * Some architectures have enormous basic pages (16KB for ia64, 64KB for ppc). + * But it's all right. Just use a simple way to make sure the chunk is never + * smaller than a page. + * + * N.B. An application does not know our chunk size. + * + * Woops, get_zeroed_page() returns a single page. I guess we're stuck with + * page-sized chunks for the time being. + */ +#define CHUNK_SIZE PAGE_SIZE +#define CHUNK_ALIGN(x) (((x)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1)) + +/* + * The magic limit was calculated so that it allows the monitoring + * application to pick data once in two ticks. This way, another application, + * which presumably drives the bus, gets to hog CPU, yet we collect our data. + * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an + * enormous overhead built into the bus protocol, so we need about 1000 KB. + * + * This is still too much for most cases, where we just snoop a few + * descriptor fetches for enumeration. So, the default is a "reasonable" + * amount for systems with HZ=250 and incomplete bus saturation. + * + * XXX What about multi-megabyte URBs which take minutes to transfer? + */ +#define BUFF_MAX CHUNK_ALIGN(1200*1024) +#define BUFF_DFL CHUNK_ALIGN(300*1024) +#define BUFF_MIN CHUNK_ALIGN(8*1024) + +/* + * The per-event API header (2 per URB). + * + * This structure is seen in userland as defined by the documentation. + */ +struct mon_bin_hdr { + u64 id; /* URB ID - from submission to callback */ + unsigned char type; /* Same as in text API; extensible. */ + unsigned char xfer_type; /* ISO, Intr, Control, Bulk */ + unsigned char epnum; /* Endpoint number and transfer direction */ + unsigned char devnum; /* Device address */ + unsigned short busnum; /* Bus number */ + char flag_setup; + char flag_data; + s64 ts_sec; /* gettimeofday */ + s32 ts_usec; /* gettimeofday */ + int status; + unsigned int len_urb; /* Length of data (submitted or actual) */ + unsigned int len_cap; /* Delivered length */ + unsigned char setup[SETUP_LEN]; /* Only for Control S-type */ +}; + +/* per file statistic */ +struct mon_bin_stats { + u32 queued; + u32 dropped; +}; + +struct mon_bin_get { + struct mon_bin_hdr __user *hdr; /* Only 48 bytes, not 64. */ + void __user *data; + size_t alloc; /* Length of data (can be zero) */ +}; + +struct mon_bin_mfetch { + u32 __user *offvec; /* Vector of events fetched */ + u32 nfetch; /* Number of events to fetch (out: fetched) */ + u32 nflush; /* Number of events to flush */ +}; + +#ifdef CONFIG_COMPAT +struct mon_bin_get32 { + u32 hdr32; + u32 data32; + u32 alloc32; +}; + +struct mon_bin_mfetch32 { + u32 offvec32; + u32 nfetch32; + u32 nflush32; +}; +#endif + +/* Having these two values same prevents wrapping of the mon_bin_hdr */ +#define PKT_ALIGN 64 +#define PKT_SIZE 64 + +/* max number of USB bus supported */ +#define MON_BIN_MAX_MINOR 128 + +/* + * The buffer: map of used pages. + */ +struct mon_pgmap { + struct page *pg; + unsigned char *ptr; /* XXX just use page_to_virt everywhere? */ +}; + +/* + * This gets associated with an open file struct. + */ +struct mon_reader_bin { + /* The buffer: one per open. */ + spinlock_t b_lock; /* Protect b_cnt, b_in */ + unsigned int b_size; /* Current size of the buffer - bytes */ + unsigned int b_cnt; /* Bytes used */ + unsigned int b_in, b_out; /* Offsets into buffer - bytes */ + unsigned int b_read; /* Amount of read data in curr. pkt. */ + struct mon_pgmap *b_vec; /* The map array */ + wait_queue_head_t b_wait; /* Wait for data here */ + + struct mutex fetch_lock; /* Protect b_read, b_out */ + int mmap_active; + + /* A list of these is needed for "bus 0". Some time later. */ + struct mon_reader r; + + /* Stats */ + unsigned int cnt_lost; +}; + +static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp, + unsigned int offset) +{ + return (struct mon_bin_hdr *) + (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE); +} + +#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0) + +static dev_t mon_bin_dev0; +static struct cdev mon_bin_cdev; + +static void mon_buff_area_fill(const struct mon_reader_bin *rp, + unsigned int offset, unsigned int size); +static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp); +static int mon_alloc_buff(struct mon_pgmap *map, int npages); +static void mon_free_buff(struct mon_pgmap *map, int npages); + +/* + * This is a "chunked memcpy". It does not manipulate any counters. + * But it returns the new offset for repeated application. + */ +unsigned int mon_copy_to_buff(const struct mon_reader_bin *this, + unsigned int off, const unsigned char *from, unsigned int length) +{ + unsigned int step_len; + unsigned char *buf; + unsigned int in_page; + + while (length) { + /* + * Determine step_len. + */ + step_len = length; + in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1)); + if (in_page < step_len) + step_len = in_page; + + /* + * Copy data and advance pointers. + */ + buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE; + memcpy(buf, from, step_len); + if ((off += step_len) >= this->b_size) off = 0; + from += step_len; + length -= step_len; + } + return off; +} + +/* + * This is a little worse than the above because it's "chunked copy_to_user". + * The return value is an error code, not an offset. + */ +static int copy_from_buf(const struct mon_reader_bin *this, unsigned int off, + char __user *to, int length) +{ + unsigned int step_len; + unsigned char *buf; + unsigned int in_page; + + while (length) { + /* + * Determine step_len. + */ + step_len = length; + in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1)); + if (in_page < step_len) + step_len = in_page; + + /* + * Copy data and advance pointers. + */ + buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE; + if (copy_to_user(to, buf, step_len)) + return -EINVAL; + if ((off += step_len) >= this->b_size) off = 0; + to += step_len; + length -= step_len; + } + return 0; +} + +/* + * Allocate an (aligned) area in the buffer. + * This is called under b_lock. + * Returns ~0 on failure. + */ +static unsigned int mon_buff_area_alloc(struct mon_reader_bin *rp, + unsigned int size) +{ + unsigned int offset; + + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + if (rp->b_cnt + size > rp->b_size) + return ~0; + offset = rp->b_in; + rp->b_cnt += size; + if ((rp->b_in += size) >= rp->b_size) + rp->b_in -= rp->b_size; + return offset; +} + +/* + * This is the same thing as mon_buff_area_alloc, only it does not allow + * buffers to wrap. This is needed by applications which pass references + * into mmap-ed buffers up their stacks (libpcap can do that). + * + * Currently, we always have the header stuck with the data, although + * it is not strictly speaking necessary. + * + * When a buffer would wrap, we place a filler packet to mark the space. + */ +static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp, + unsigned int size) +{ + unsigned int offset; + unsigned int fill_size; + + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + if (rp->b_cnt + size > rp->b_size) + return ~0; + if (rp->b_in + size > rp->b_size) { + /* + * This would wrap. Find if we still have space after + * skipping to the end of the buffer. If we do, place + * a filler packet and allocate a new packet. + */ + fill_size = rp->b_size - rp->b_in; + if (rp->b_cnt + size + fill_size > rp->b_size) + return ~0; + mon_buff_area_fill(rp, rp->b_in, fill_size); + + offset = 0; + rp->b_in = size; + rp->b_cnt += size + fill_size; + } else if (rp->b_in + size == rp->b_size) { + offset = rp->b_in; + rp->b_in = 0; + rp->b_cnt += size; + } else { + offset = rp->b_in; + rp->b_in += size; + rp->b_cnt += size; + } + return offset; +} + +/* + * Return a few (kilo-)bytes to the head of the buffer. + * This is used if a DMA fetch fails. + */ +static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size) +{ + + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + rp->b_cnt -= size; + if (rp->b_in < size) + rp->b_in += rp->b_size; + rp->b_in -= size; +} + +/* + * This has to be called under both b_lock and fetch_lock, because + * it accesses both b_cnt and b_out. + */ +static void mon_buff_area_free(struct mon_reader_bin *rp, unsigned int size) +{ + + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + rp->b_cnt -= size; + if ((rp->b_out += size) >= rp->b_size) + rp->b_out -= rp->b_size; +} + +static void mon_buff_area_fill(const struct mon_reader_bin *rp, + unsigned int offset, unsigned int size) +{ + struct mon_bin_hdr *ep; + + ep = MON_OFF2HDR(rp, offset); + memset(ep, 0, PKT_SIZE); + ep->type = '@'; + ep->len_cap = size - PKT_SIZE; +} + +static inline char mon_bin_get_setup(unsigned char *setupb, + const struct urb *urb, char ev_type) +{ + + if (!usb_pipecontrol(urb->pipe) || ev_type != 'S') + return '-'; + + if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP) + return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN); + if (urb->setup_packet == NULL) + return 'Z'; + + memcpy(setupb, urb->setup_packet, SETUP_LEN); + return 0; +} + +static char mon_bin_get_data(const struct mon_reader_bin *rp, + unsigned int offset, struct urb *urb, unsigned int length) +{ + + if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) { + mon_dmapeek_vec(rp, offset, urb->transfer_dma, length); + return 0; + } + + if (urb->transfer_buffer == NULL) + return 'Z'; + + mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); + return 0; +} + +static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, + char ev_type) +{ + unsigned long flags; + struct timeval ts; + unsigned int urb_length; + unsigned int offset; + unsigned int length; + struct mon_bin_hdr *ep; + char data_tag = 0; + + do_gettimeofday(&ts); + + spin_lock_irqsave(&rp->b_lock, flags); + + /* + * Find the maximum allowable length, then allocate space. + */ + urb_length = (ev_type == 'S') ? + urb->transfer_buffer_length : urb->actual_length; + length = urb_length; + + if (length >= rp->b_size/5) + length = rp->b_size/5; + + if (usb_pipein(urb->pipe)) { + if (ev_type == 'S') { + length = 0; + data_tag = '<'; + } + } else { + if (ev_type == 'C') { + length = 0; + data_tag = '>'; + } + } + + if (rp->mmap_active) + offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE); + else + offset = mon_buff_area_alloc(rp, length + PKT_SIZE); + if (offset == ~0) { + rp->cnt_lost++; + spin_unlock_irqrestore(&rp->b_lock, flags); + return; + } + + ep = MON_OFF2HDR(rp, offset); + if ((offset += PKT_SIZE) >= rp->b_size) offset = 0; + + /* + * Fill the allocated area. + */ + memset(ep, 0, PKT_SIZE); + ep->type = ev_type; + ep->xfer_type = usb_pipetype(urb->pipe); + /* We use the fact that usb_pipein() returns 0x80 */ + ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); + ep->devnum = usb_pipedevice(urb->pipe); + ep->busnum = rp->r.m_bus->u_bus->busnum; + ep->id = (unsigned long) urb; + ep->ts_sec = ts.tv_sec; + ep->ts_usec = ts.tv_usec; + ep->status = urb->status; + ep->len_urb = urb_length; + ep->len_cap = length; + + ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type); + if (length != 0) { + ep->flag_data = mon_bin_get_data(rp, offset, urb, length); + if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */ + ep->len_cap = 0; + mon_buff_area_shrink(rp, length); + } + } else { + ep->flag_data = data_tag; + } + + spin_unlock_irqrestore(&rp->b_lock, flags); + + wake_up(&rp->b_wait); +} + +static void mon_bin_submit(void *data, struct urb *urb) +{ + struct mon_reader_bin *rp = data; + mon_bin_event(rp, urb, 'S'); +} + +static void mon_bin_complete(void *data, struct urb *urb) +{ + struct mon_reader_bin *rp = data; + mon_bin_event(rp, urb, 'C'); +} + +static void mon_bin_error(void *data, struct urb *urb, int error) +{ + struct mon_reader_bin *rp = data; + unsigned long flags; + unsigned int offset; + struct mon_bin_hdr *ep; + + spin_lock_irqsave(&rp->b_lock, flags); + + offset = mon_buff_area_alloc(rp, PKT_SIZE); + if (offset == ~0) { + /* Not incrementing cnt_lost. Just because. */ + spin_unlock_irqrestore(&rp->b_lock, flags); + return; + } + + ep = MON_OFF2HDR(rp, offset); + + memset(ep, 0, PKT_SIZE); + ep->type = 'E'; + ep->xfer_type = usb_pipetype(urb->pipe); + /* We use the fact that usb_pipein() returns 0x80 */ + ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe); + ep->devnum = usb_pipedevice(urb->pipe); + ep->busnum = rp->r.m_bus->u_bus->busnum; + ep->id = (unsigned long) urb; + ep->status = error; + + ep->flag_setup = '-'; + ep->flag_data = 'E'; + + spin_unlock_irqrestore(&rp->b_lock, flags); + + wake_up(&rp->b_wait); +} + +static int mon_bin_open(struct inode *inode, struct file *file) +{ + struct mon_bus *mbus; + struct usb_bus *ubus; + struct mon_reader_bin *rp; + size_t size; + int rc; + + mutex_lock(&mon_lock); + if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) { + mutex_unlock(&mon_lock); + return -ENODEV; + } + if ((ubus = mbus->u_bus) == NULL) { + printk(KERN_ERR TAG ": consistency error on open\n"); + mutex_unlock(&mon_lock); + return -ENODEV; + } + + rp = kzalloc(sizeof(struct mon_reader_bin), GFP_KERNEL); + if (rp == NULL) { + rc = -ENOMEM; + goto err_alloc; + } + spin_lock_init(&rp->b_lock); + init_waitqueue_head(&rp->b_wait); + mutex_init(&rp->fetch_lock); + + rp->b_size = BUFF_DFL; + + size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE); + if ((rp->b_vec = kzalloc(size, GFP_KERNEL)) == NULL) { + rc = -ENOMEM; + goto err_allocvec; + } + + if ((rc = mon_alloc_buff(rp->b_vec, rp->b_size/CHUNK_SIZE)) < 0) + goto err_allocbuff; + + rp->r.m_bus = mbus; + rp->r.r_data = rp; + rp->r.rnf_submit = mon_bin_submit; + rp->r.rnf_error = mon_bin_error; + rp->r.rnf_complete = mon_bin_complete; + + mon_reader_add(mbus, &rp->r); + + file->private_data = rp; + mutex_unlock(&mon_lock); + return 0; + +err_allocbuff: + kfree(rp->b_vec); +err_allocvec: + kfree(rp); +err_alloc: + mutex_unlock(&mon_lock); + return rc; +} + +/* + * Extract an event from buffer and copy it to user space. + * Wait if there is no event ready. + * Returns zero or error. + */ +static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp, + struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes) +{ + unsigned long flags; + struct mon_bin_hdr *ep; + size_t step_len; + unsigned int offset; + int rc; + + mutex_lock(&rp->fetch_lock); + + if ((rc = mon_bin_wait_event(file, rp)) < 0) { + mutex_unlock(&rp->fetch_lock); + return rc; + } + + ep = MON_OFF2HDR(rp, rp->b_out); + + if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + + step_len = min(ep->len_cap, nbytes); + if ((offset = rp->b_out + PKT_SIZE) >= rp->b_size) offset = 0; + + if (copy_from_buf(rp, offset, data, step_len)) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + + spin_lock_irqsave(&rp->b_lock, flags); + mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); + spin_unlock_irqrestore(&rp->b_lock, flags); + rp->b_read = 0; + + mutex_unlock(&rp->fetch_lock); + return 0; +} + +static int mon_bin_release(struct inode *inode, struct file *file) +{ + struct mon_reader_bin *rp = file->private_data; + struct mon_bus* mbus = rp->r.m_bus; + + mutex_lock(&mon_lock); + + if (mbus->nreaders <= 0) { + printk(KERN_ERR TAG ": consistency error on close\n"); + mutex_unlock(&mon_lock); + return 0; + } + mon_reader_del(mbus, &rp->r); + + mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE); + kfree(rp->b_vec); + kfree(rp); + + mutex_unlock(&mon_lock); + return 0; +} + +static ssize_t mon_bin_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct mon_reader_bin *rp = file->private_data; + unsigned long flags; + struct mon_bin_hdr *ep; + unsigned int offset; + size_t step_len; + char *ptr; + ssize_t done = 0; + int rc; + + mutex_lock(&rp->fetch_lock); + + if ((rc = mon_bin_wait_event(file, rp)) < 0) { + mutex_unlock(&rp->fetch_lock); + return rc; + } + + ep = MON_OFF2HDR(rp, rp->b_out); + + if (rp->b_read < sizeof(struct mon_bin_hdr)) { + step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read); + ptr = ((char *)ep) + rp->b_read; + if (step_len && copy_to_user(buf, ptr, step_len)) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + nbytes -= step_len; + buf += step_len; + rp->b_read += step_len; + done += step_len; + } + + if (rp->b_read >= sizeof(struct mon_bin_hdr)) { + step_len = min(nbytes, (size_t)ep->len_cap); + offset = rp->b_out + PKT_SIZE; + offset += rp->b_read - sizeof(struct mon_bin_hdr); + if (offset >= rp->b_size) + offset -= rp->b_size; + if (copy_from_buf(rp, offset, buf, step_len)) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + nbytes -= step_len; + buf += step_len; + rp->b_read += step_len; + done += step_len; + } + + /* + * Check if whole packet was read, and if so, jump to the next one. + */ + if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) { + spin_lock_irqsave(&rp->b_lock, flags); + mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); + spin_unlock_irqrestore(&rp->b_lock, flags); + rp->b_read = 0; + } + + mutex_unlock(&rp->fetch_lock); + return done; +} + +/* + * Remove at most nevents from chunked buffer. + * Returns the number of removed events. + */ +static int mon_bin_flush(struct mon_reader_bin *rp, unsigned nevents) +{ + unsigned long flags; + struct mon_bin_hdr *ep; + int i; + + mutex_lock(&rp->fetch_lock); + spin_lock_irqsave(&rp->b_lock, flags); + for (i = 0; i < nevents; ++i) { + if (MON_RING_EMPTY(rp)) + break; + + ep = MON_OFF2HDR(rp, rp->b_out); + mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); + } + spin_unlock_irqrestore(&rp->b_lock, flags); + rp->b_read = 0; + mutex_unlock(&rp->fetch_lock); + return i; +} + +/* + * Fetch at most max event offsets into the buffer and put them into vec. + * The events are usually freed later with mon_bin_flush. + * Return the effective number of events fetched. + */ +static int mon_bin_fetch(struct file *file, struct mon_reader_bin *rp, + u32 __user *vec, unsigned int max) +{ + unsigned int cur_out; + unsigned int bytes, avail; + unsigned int size; + unsigned int nevents; + struct mon_bin_hdr *ep; + unsigned long flags; + int rc; + + mutex_lock(&rp->fetch_lock); + + if ((rc = mon_bin_wait_event(file, rp)) < 0) { + mutex_unlock(&rp->fetch_lock); + return rc; + } + + spin_lock_irqsave(&rp->b_lock, flags); + avail = rp->b_cnt; + spin_unlock_irqrestore(&rp->b_lock, flags); + + cur_out = rp->b_out; + nevents = 0; + bytes = 0; + while (bytes < avail) { + if (nevents >= max) + break; + + ep = MON_OFF2HDR(rp, cur_out); + if (put_user(cur_out, &vec[nevents])) { + mutex_unlock(&rp->fetch_lock); + return -EFAULT; + } + + nevents++; + size = ep->len_cap + PKT_SIZE; + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + if ((cur_out += size) >= rp->b_size) + cur_out -= rp->b_size; + bytes += size; + } + + mutex_unlock(&rp->fetch_lock); + return nevents; +} + +/* + * Count events. This is almost the same as the above mon_bin_fetch, + * only we do not store offsets into user vector, and we have no limit. + */ +static int mon_bin_queued(struct mon_reader_bin *rp) +{ + unsigned int cur_out; + unsigned int bytes, avail; + unsigned int size; + unsigned int nevents; + struct mon_bin_hdr *ep; + unsigned long flags; + + mutex_lock(&rp->fetch_lock); + + spin_lock_irqsave(&rp->b_lock, flags); + avail = rp->b_cnt; + spin_unlock_irqrestore(&rp->b_lock, flags); + + cur_out = rp->b_out; + nevents = 0; + bytes = 0; + while (bytes < avail) { + ep = MON_OFF2HDR(rp, cur_out); + + nevents++; + size = ep->len_cap + PKT_SIZE; + size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); + if ((cur_out += size) >= rp->b_size) + cur_out -= rp->b_size; + bytes += size; + } + + mutex_unlock(&rp->fetch_lock); + return nevents; +} + +/* + */ +static int mon_bin_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct mon_reader_bin *rp = file->private_data; + // struct mon_bus* mbus = rp->r.m_bus; + int ret = 0; + struct mon_bin_hdr *ep; + unsigned long flags; + + switch (cmd) { + + case MON_IOCQ_URB_LEN: + /* + * N.B. This only returns the size of data, without the header. + */ + spin_lock_irqsave(&rp->b_lock, flags); + if (!MON_RING_EMPTY(rp)) { + ep = MON_OFF2HDR(rp, rp->b_out); + ret = ep->len_cap; + } + spin_unlock_irqrestore(&rp->b_lock, flags); + break; + + case MON_IOCQ_RING_SIZE: + ret = rp->b_size; + break; + + case MON_IOCT_RING_SIZE: + /* + * Changing the buffer size will flush it's contents; the new + * buffer is allocated before releasing the old one to be sure + * the device will stay functional also in case of memory + * pressure. + */ + { + int size; + struct mon_pgmap *vec; + + if (arg < BUFF_MIN || arg > BUFF_MAX) + return -EINVAL; + + size = CHUNK_ALIGN(arg); + if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE), + GFP_KERNEL)) == NULL) { + ret = -ENOMEM; + break; + } + + ret = mon_alloc_buff(vec, size/CHUNK_SIZE); + if (ret < 0) { + kfree(vec); + break; + } + + mutex_lock(&rp->fetch_lock); + spin_lock_irqsave(&rp->b_lock, flags); + mon_free_buff(rp->b_vec, size/CHUNK_SIZE); + kfree(rp->b_vec); + rp->b_vec = vec; + rp->b_size = size; + rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0; + rp->cnt_lost = 0; + spin_unlock_irqrestore(&rp->b_lock, flags); + mutex_unlock(&rp->fetch_lock); + } + break; + + case MON_IOCH_MFLUSH: + ret = mon_bin_flush(rp, arg); + break; + + case MON_IOCX_GET: + { + struct mon_bin_get getb; + + if (copy_from_user(&getb, (void __user *)arg, + sizeof(struct mon_bin_get))) + return -EFAULT; + + if (getb.alloc > 0x10000000) /* Want to cast to u32 */ + return -EINVAL; + ret = mon_bin_get_event(file, rp, + getb.hdr, getb.data, (unsigned int)getb.alloc); + } + break; + +#ifdef CONFIG_COMPAT + case MON_IOCX_GET32: { + struct mon_bin_get32 getb; + + if (copy_from_user(&getb, (void __user *)arg, + sizeof(struct mon_bin_get32))) + return -EFAULT; + + ret = mon_bin_get_event(file, rp, + compat_ptr(getb.hdr32), compat_ptr(getb.data32), + getb.alloc32); + } + break; +#endif + + case MON_IOCX_MFETCH: + { + struct mon_bin_mfetch mfetch; + struct mon_bin_mfetch __user *uptr; + + uptr = (struct mon_bin_mfetch __user *)arg; + + if (copy_from_user(&mfetch, uptr, sizeof(mfetch))) + return -EFAULT; + + if (mfetch.nflush) { + ret = mon_bin_flush(rp, mfetch.nflush); + if (ret < 0) + return ret; + if (put_user(ret, &uptr->nflush)) + return -EFAULT; + } + ret = mon_bin_fetch(file, rp, mfetch.offvec, mfetch.nfetch); + if (ret < 0) + return ret; + if (put_user(ret, &uptr->nfetch)) + return -EFAULT; + ret = 0; + } + break; + +#ifdef CONFIG_COMPAT + case MON_IOCX_MFETCH32: + { + struct mon_bin_mfetch32 mfetch; + struct mon_bin_mfetch32 __user *uptr; + + uptr = (struct mon_bin_mfetch32 __user *) compat_ptr(arg); + + if (copy_from_user(&mfetch, uptr, sizeof(mfetch))) + return -EFAULT; + + if (mfetch.nflush32) { + ret = mon_bin_flush(rp, mfetch.nflush32); + if (ret < 0) + return ret; + if (put_user(ret, &uptr->nflush32)) + return -EFAULT; + } + ret = mon_bin_fetch(file, rp, compat_ptr(mfetch.offvec32), + mfetch.nfetch32); + if (ret < 0) + return ret; + if (put_user(ret, &uptr->nfetch32)) + return -EFAULT; + ret = 0; + } + break; +#endif + + case MON_IOCG_STATS: { + struct mon_bin_stats __user *sp; + unsigned int nevents; + unsigned int ndropped; + + spin_lock_irqsave(&rp->b_lock, flags); + ndropped = rp->cnt_lost; + rp->cnt_lost = 0; + spin_unlock_irqrestore(&rp->b_lock, flags); + nevents = mon_bin_queued(rp); + + sp = (struct mon_bin_stats __user *)arg; + if (put_user(rp->cnt_lost, &sp->dropped)) + return -EFAULT; + if (put_user(nevents, &sp->queued)) + return -EFAULT; + + } + break; + + default: + return -ENOTTY; + } + + return ret; +} + +static unsigned int +mon_bin_poll(struct file *file, struct poll_table_struct *wait) +{ + struct mon_reader_bin *rp = file->private_data; + unsigned int mask = 0; + unsigned long flags; + + if (file->f_mode & FMODE_READ) + poll_wait(file, &rp->b_wait, wait); + + spin_lock_irqsave(&rp->b_lock, flags); + if (!MON_RING_EMPTY(rp)) + mask |= POLLIN | POLLRDNORM; /* readable */ + spin_unlock_irqrestore(&rp->b_lock, flags); + return mask; +} + +/* + * open and close: just keep track of how many times the device is + * mapped, to use the proper memory allocation function. + */ +static void mon_bin_vma_open(struct vm_area_struct *vma) +{ + struct mon_reader_bin *rp = vma->vm_private_data; + rp->mmap_active++; +} + +static void mon_bin_vma_close(struct vm_area_struct *vma) +{ + struct mon_reader_bin *rp = vma->vm_private_data; + rp->mmap_active--; +} + +/* + * Map ring pages to user space. + */ +struct page *mon_bin_vma_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + struct mon_reader_bin *rp = vma->vm_private_data; + unsigned long offset, chunk_idx; + struct page *pageptr; + + offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); + if (offset >= rp->b_size) + return NOPAGE_SIGBUS; + chunk_idx = offset / CHUNK_SIZE; + pageptr = rp->b_vec[chunk_idx].pg; + get_page(pageptr); + if (type) + *type = VM_FAULT_MINOR; + return pageptr; +} + +struct vm_operations_struct mon_bin_vm_ops = { + .open = mon_bin_vma_open, + .close = mon_bin_vma_close, + .nopage = mon_bin_vma_nopage, +}; + +int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma) +{ + /* don't do anything here: "nopage" will set up page table entries */ + vma->vm_ops = &mon_bin_vm_ops; + vma->vm_flags |= VM_RESERVED; + vma->vm_private_data = filp->private_data; + mon_bin_vma_open(vma); + return 0; +} + +struct file_operations mon_fops_binary = { + .owner = THIS_MODULE, + .open = mon_bin_open, + .llseek = no_llseek, + .read = mon_bin_read, + /* .write = mon_text_write, */ + .poll = mon_bin_poll, + .ioctl = mon_bin_ioctl, + .release = mon_bin_release, +}; + +static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp) +{ + DECLARE_WAITQUEUE(waita, current); + unsigned long flags; + + add_wait_queue(&rp->b_wait, &waita); + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&rp->b_lock, flags); + while (MON_RING_EMPTY(rp)) { + spin_unlock_irqrestore(&rp->b_lock, flags); + + if (file->f_flags & O_NONBLOCK) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&rp->b_wait, &waita); + return -EWOULDBLOCK; /* Same as EAGAIN in Linux */ + } + schedule(); + if (signal_pending(current)) { + remove_wait_queue(&rp->b_wait, &waita); + return -EINTR; + } + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&rp->b_lock, flags); + } + spin_unlock_irqrestore(&rp->b_lock, flags); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&rp->b_wait, &waita); + return 0; +} + +static int mon_alloc_buff(struct mon_pgmap *map, int npages) +{ + int n; + unsigned long vaddr; + + for (n = 0; n < npages; n++) { + vaddr = get_zeroed_page(GFP_KERNEL); + if (vaddr == 0) { + while (n-- != 0) + free_page((unsigned long) map[n].ptr); + return -ENOMEM; + } + map[n].ptr = (unsigned char *) vaddr; + map[n].pg = virt_to_page(vaddr); + } + return 0; +} + +static void mon_free_buff(struct mon_pgmap *map, int npages) +{ + int n; + + for (n = 0; n < npages; n++) + free_page((unsigned long) map[n].ptr); +} + +int __init mon_bin_init(void) +{ + int rc; + + rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon"); + if (rc < 0) + goto err_dev; + + cdev_init(&mon_bin_cdev, &mon_fops_binary); + mon_bin_cdev.owner = THIS_MODULE; + + rc = cdev_add(&mon_bin_cdev, mon_bin_dev0, MON_BIN_MAX_MINOR); + if (rc < 0) + goto err_add; + + return 0; + +err_add: + unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR); +err_dev: + return rc; +} + +void __exit mon_bin_exit(void) +{ + cdev_del(&mon_bin_cdev); + unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR); +} diff --git a/drivers/usb/mon/mon_dma.c b/drivers/usb/mon/mon_dma.c index ddcfc01e77a0..140cc80bd2b1 100644 --- a/drivers/usb/mon/mon_dma.c +++ b/drivers/usb/mon/mon_dma.c @@ -48,6 +48,36 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len) local_irq_restore(flags); return 0; } + +void mon_dmapeek_vec(const struct mon_reader_bin *rp, + unsigned int offset, dma_addr_t dma_addr, unsigned int length) +{ + unsigned long flags; + unsigned int step_len; + struct page *pg; + unsigned char *map; + unsigned long page_off, page_len; + + local_irq_save(flags); + while (length) { + /* compute number of bytes we are going to copy in this page */ + step_len = length; + page_off = dma_addr & (PAGE_SIZE-1); + page_len = PAGE_SIZE - page_off; + if (page_len < step_len) + step_len = page_len; + + /* copy data and advance pointers */ + pg = phys_to_page(dma_addr); + map = kmap_atomic(pg, KM_IRQ0); + offset = mon_copy_to_buff(rp, offset, map + page_off, step_len); + kunmap_atomic(map, KM_IRQ0); + dma_addr += step_len; + length -= step_len; + } + local_irq_restore(flags); +} + #endif /* __i386__ */ #ifndef MON_HAS_UNMAP @@ -55,4 +85,11 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len) { return 'D'; } -#endif + +void mon_dmapeek_vec(const struct mon_reader_bin *rp, + unsigned int offset, dma_addr_t dma_addr, unsigned int length) +{ + ; +} + +#endif /* MON_HAS_UNMAP */ diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 394bbf2f68d4..c9739e7b35e5 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -22,11 +21,10 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb); static void mon_stop(struct mon_bus *mbus); static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus); static void mon_bus_drop(struct kref *r); -static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus); +static void mon_bus_init(struct usb_bus *ubus); DEFINE_MUTEX(mon_lock); -static struct dentry *mon_dir; /* /dbg/usbmon */ static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */ /* @@ -200,7 +198,7 @@ static void mon_stop(struct mon_bus *mbus) */ static void mon_bus_add(struct usb_bus *ubus) { - mon_bus_init(mon_dir, ubus); + mon_bus_init(ubus); } /* @@ -212,8 +210,8 @@ static void mon_bus_remove(struct usb_bus *ubus) mutex_lock(&mon_lock); list_del(&mbus->bus_link); - debugfs_remove(mbus->dent_t); - debugfs_remove(mbus->dent_s); + if (mbus->text_inited) + mon_text_del(mbus); mon_dissolve(mbus, ubus); kref_put(&mbus->ref, mon_bus_drop); @@ -281,13 +279,9 @@ static void mon_bus_drop(struct kref *r) * - refcount USB bus struct * - link */ -static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus) +static void mon_bus_init(struct usb_bus *ubus) { - struct dentry *d; struct mon_bus *mbus; - enum { NAMESZ = 10 }; - char name[NAMESZ]; - int rc; if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL) goto err_alloc; @@ -303,57 +297,54 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus) ubus->mon_bus = mbus; mbus->uses_dma = ubus->uses_dma; - rc = snprintf(name, NAMESZ, "%dt", ubus->busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_t; - d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text); - if (d == NULL) - goto err_create_t; - mbus->dent_t = d; - - rc = snprintf(name, NAMESZ, "%ds", ubus->busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_s; - d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat); - if (d == NULL) - goto err_create_s; - mbus->dent_s = d; + mbus->text_inited = mon_text_add(mbus, ubus); + // mon_bin_add(...) mutex_lock(&mon_lock); list_add_tail(&mbus->bus_link, &mon_buses); mutex_unlock(&mon_lock); return; -err_create_s: -err_print_s: - debugfs_remove(mbus->dent_t); -err_create_t: -err_print_t: - kfree(mbus); err_alloc: return; } +/* + * Search a USB bus by number. Notice that USB bus numbers start from one, + * which we may later use to identify "all" with zero. + * + * This function must be called with mon_lock held. + * + * This is obviously inefficient and may be revised in the future. + */ +struct mon_bus *mon_bus_lookup(unsigned int num) +{ + struct list_head *p; + struct mon_bus *mbus; + + list_for_each (p, &mon_buses) { + mbus = list_entry(p, struct mon_bus, bus_link); + if (mbus->u_bus->busnum == num) { + return mbus; + } + } + return NULL; +} + static int __init mon_init(void) { struct usb_bus *ubus; - struct dentry *mondir; + int rc; - mondir = debugfs_create_dir("usbmon", NULL); - if (IS_ERR(mondir)) { - printk(KERN_NOTICE TAG ": debugfs is not available\n"); - return -ENODEV; - } - if (mondir == NULL) { - printk(KERN_NOTICE TAG ": unable to create usbmon directory\n"); - return -ENODEV; - } - mon_dir = mondir; + if ((rc = mon_text_init()) != 0) + goto err_text; + if ((rc = mon_bin_init()) != 0) + goto err_bin; if (usb_mon_register(&mon_ops_0) != 0) { printk(KERN_NOTICE TAG ": unable to register with the core\n"); - debugfs_remove(mondir); - return -ENODEV; + rc = -ENODEV; + goto err_reg; } // MOD_INC_USE_COUNT(which_module?); @@ -361,10 +352,17 @@ static int __init mon_init(void) mutex_lock(&usb_bus_list_lock); list_for_each_entry (ubus, &usb_bus_list, bus_list) { - mon_bus_init(mondir, ubus); + mon_bus_init(ubus); } mutex_unlock(&usb_bus_list_lock); return 0; + +err_reg: + mon_bin_exit(); +err_bin: + mon_text_exit(); +err_text: + return rc; } static void __exit mon_exit(void) @@ -381,8 +379,8 @@ static void __exit mon_exit(void) mbus = list_entry(p, struct mon_bus, bus_link); list_del(p); - debugfs_remove(mbus->dent_t); - debugfs_remove(mbus->dent_s); + if (mbus->text_inited) + mon_text_del(mbus); /* * This never happens, because the open/close paths in @@ -401,7 +399,8 @@ static void __exit mon_exit(void) } mutex_unlock(&mon_lock); - debugfs_remove(mon_dir); + mon_text_exit(); + mon_bin_exit(); } module_init(mon_init); diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 05cf2c9a8f84..d38a1279d9d9 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "usb_mon.h" @@ -63,6 +64,8 @@ struct mon_reader_text { char slab_name[SLAB_NAME_SZ]; }; +static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */ + static void mon_text_ctor(void *, struct kmem_cache *, unsigned long); /* @@ -436,7 +439,7 @@ static int mon_text_release(struct inode *inode, struct file *file) return 0; } -const struct file_operations mon_fops_text = { +static const struct file_operations mon_fops_text = { .owner = THIS_MODULE, .open = mon_text_open, .llseek = no_llseek, @@ -447,6 +450,47 @@ const struct file_operations mon_fops_text = { .release = mon_text_release, }; +int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus) +{ + struct dentry *d; + enum { NAMESZ = 10 }; + char name[NAMESZ]; + int rc; + + rc = snprintf(name, NAMESZ, "%dt", ubus->busnum); + if (rc <= 0 || rc >= NAMESZ) + goto err_print_t; + d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text); + if (d == NULL) + goto err_create_t; + mbus->dent_t = d; + + /* XXX The stats do not belong to here (text API), but oh well... */ + rc = snprintf(name, NAMESZ, "%ds", ubus->busnum); + if (rc <= 0 || rc >= NAMESZ) + goto err_print_s; + d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat); + if (d == NULL) + goto err_create_s; + mbus->dent_s = d; + + return 1; + +err_create_s: +err_print_s: + debugfs_remove(mbus->dent_t); + mbus->dent_t = NULL; +err_create_t: +err_print_t: + return 0; +} + +void mon_text_del(struct mon_bus *mbus) +{ + debugfs_remove(mbus->dent_t); + debugfs_remove(mbus->dent_s); +} + /* * Slab interface: constructor. */ @@ -459,3 +503,24 @@ static void mon_text_ctor(void *mem, struct kmem_cache *slab, unsigned long sfla memset(mem, 0xe5, sizeof(struct mon_event_text)); } +int __init mon_text_init(void) +{ + struct dentry *mondir; + + mondir = debugfs_create_dir("usbmon", NULL); + if (IS_ERR(mondir)) { + printk(KERN_NOTICE TAG ": debugfs is not available\n"); + return -ENODEV; + } + if (mondir == NULL) { + printk(KERN_NOTICE TAG ": unable to create usbmon directory\n"); + return -ENODEV; + } + mon_dir = mondir; + return 0; +} + +void __exit mon_text_exit(void) +{ + debugfs_remove(mon_dir); +} diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index ab9d02d5df77..4f949ce8a7f3 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -17,9 +17,11 @@ struct mon_bus { struct list_head bus_link; spinlock_t lock; + struct usb_bus *u_bus; + + int text_inited; struct dentry *dent_s; /* Debugging file */ struct dentry *dent_t; /* Text interface file */ - struct usb_bus *u_bus; int uses_dma; /* Ref */ @@ -48,13 +50,35 @@ struct mon_reader { void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r); void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r); +struct mon_bus *mon_bus_lookup(unsigned int num); + +int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus); +void mon_text_del(struct mon_bus *mbus); +// void mon_bin_add(struct mon_bus *); + +int __init mon_text_init(void); +void __exit mon_text_exit(void); +int __init mon_bin_init(void); +void __exit mon_bin_exit(void); + /* - */ + * DMA interface. + * + * XXX The vectored side needs a serious re-thinking. Abstracting vectors, + * like in Paolo's original patch, produces a double pkmap. We need an idea. +*/ extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len); +struct mon_reader_bin; +extern void mon_dmapeek_vec(const struct mon_reader_bin *rp, + unsigned int offset, dma_addr_t dma_addr, unsigned int len); +extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp, + unsigned int offset, const unsigned char *from, unsigned int len); + +/* + */ extern struct mutex mon_lock; -extern const struct file_operations mon_fops_text; extern const struct file_operations mon_fops_stat; #endif /* __USB_MON_H */ diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index e081836014ac..a2b94ef512bc 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -222,13 +222,15 @@ config USB_NET_MCS7830 adapters marketed under the DeLOCK brand. config USB_NET_RNDIS_HOST - tristate "Host for RNDIS devices (EXPERIMENTAL)" + tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)" depends on USB_USBNET && EXPERIMENTAL select USB_NET_CDCETHER help This option enables hosting "Remote NDIS" USB networking links, as encouraged by Microsoft (instead of CDC Ethernet!) for use in - various devices that may only support this protocol. + various devices that may only support this protocol. A variant + of this protocol (with even less public documentation) seems to + be at the root of Microsoft's "ActiveSync" too. Avoid using this protocol unless you have no better options. The protocol specification is incomplete, and is controlled by diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 896449f0cf85..4206df2d61b7 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -1449,6 +1449,10 @@ static const struct usb_device_id products [] = { // Linksys USB1000 USB_DEVICE (0x1737, 0x0039), .driver_info = (unsigned long) &ax88178_info, +}, { + // IO-DATA ETG-US2 + USB_DEVICE (0x04bb, 0x0930), + .driver_info = (unsigned long) &ax88178_info, }, { }, // END }; diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c index 44a91547146e..e5cdafa258dd 100644 --- a/drivers/usb/net/cdc_ether.c +++ b/drivers/usb/net/cdc_ether.c @@ -1,6 +1,7 @@ /* * CDC Ethernet based networking peripherals * Copyright (C) 2003-2005 by David Brownell + * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,6 +36,29 @@ #include "usbnet.h" +#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) + +static int is_rndis(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_COMM + && desc->bInterfaceSubClass == 2 + && desc->bInterfaceProtocol == 0xff; +} + +static int is_activesync(struct usb_interface_descriptor *desc) +{ + return desc->bInterfaceClass == USB_CLASS_MISC + && desc->bInterfaceSubClass == 1 + && desc->bInterfaceProtocol == 1; +} + +#else + +#define is_rndis(desc) 0 +#define is_activesync(desc) 0 + +#endif + /* * probes control interface, claims data interface, collects the bulk * endpoints, activates data interface (if needed), maybe sets MTU. @@ -71,7 +95,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) /* this assumes that if there's a non-RNDIS vendor variant * of cdc-acm, it'll fail RNDIS requests cleanly. */ - rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff); + rndis = is_rndis(&intf->cur_altsetting->desc) + || is_activesync(&intf->cur_altsetting->desc); memset(info, 0, sizeof *info); info->control = intf; @@ -99,6 +124,23 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) goto bad_desc; } break; + case USB_CDC_ACM_TYPE: + /* paranoia: disambiguate a "real" vendor-specific + * modem interface from an RNDIS non-modem. + */ + if (rndis) { + struct usb_cdc_acm_descriptor *d; + + d = (void *) buf; + if (d->bmCapabilities) { + dev_dbg(&intf->dev, + "ACM capabilities %02x, " + "not really RNDIS?\n", + d->bmCapabilities); + goto bad_desc; + } + } + break; case USB_CDC_UNION_TYPE: if (info->u) { dev_dbg(&intf->dev, "extra CDC union\n"); @@ -171,7 +213,21 @@ next_desc: buf += buf [0]; } - if (!info->header || !info->u || (!rndis && !info->ether)) { + /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors, + * so we'll hard-wire the interfaces and not check for descriptors. + */ + if (is_activesync(&intf->cur_altsetting->desc) && !info->u) { + info->control = usb_ifnum_to_if(dev->udev, 0); + info->data = usb_ifnum_to_if(dev->udev, 1); + if (!info->control || !info->data) { + dev_dbg(&intf->dev, + "activesync: master #0/%p slave #1/%p\n", + info->control, + info->data); + goto bad_desc; + } + + } else if (!info->header || !info->u || (!rndis && !info->ether)) { dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n", info->header ? "" : "header ", info->u ? "" : "union ", diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index fa78326d0bf0..36a989160a68 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = { .suspend = kaweth_suspend, .resume = kaweth_resume, .id_table = usb_klsi_table, + .supports_autosuspend = 1, }; typedef __u8 eth_addr_t[6]; @@ -225,6 +226,7 @@ struct kaweth_device struct delayed_work lowmem_work; struct usb_device *dev; + struct usb_interface *intf; struct net_device *net; wait_queue_head_t term_wait; @@ -662,9 +664,14 @@ static int kaweth_open(struct net_device *net) dbg("Opening network device."); + res = usb_autopm_get_interface(kaweth->intf); + if (res) { + err("Interface cannot be resumed."); + return -EIO; + } res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); if (res) - return -EIO; + goto err_out; usb_fill_int_urb( kaweth->irq_urb, @@ -681,7 +688,7 @@ static int kaweth_open(struct net_device *net) res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL); if (res) { usb_kill_urb(kaweth->rx_urb); - return -EIO; + goto err_out; } kaweth->opened = 1; @@ -689,10 +696,14 @@ static int kaweth_open(struct net_device *net) kaweth_async_set_rx_mode(kaweth); return 0; + +err_out: + usb_autopm_enable(kaweth->intf); + return -EIO; } /**************************************************************** - * kaweth_close + * kaweth_kill_urbs ****************************************************************/ static void kaweth_kill_urbs(struct kaweth_device *kaweth) { @@ -724,17 +735,29 @@ static int kaweth_close(struct net_device *net) kaweth->status &= ~KAWETH_STATUS_CLOSING; + usb_autopm_enable(kaweth->intf); + return 0; } static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { + struct kaweth_device *kaweth = netdev_priv(dev); strlcpy(info->driver, driver_name, sizeof(info->driver)); + usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info)); +} + +static u32 kaweth_get_link(struct net_device *dev) +{ + struct kaweth_device *kaweth = netdev_priv(dev); + + return kaweth->linkstate; } static struct ethtool_ops ops = { - .get_drvinfo = kaweth_get_drvinfo + .get_drvinfo = kaweth_get_drvinfo, + .get_link = kaweth_get_link }; /**************************************************************** @@ -908,6 +931,7 @@ static int kaweth_suspend(struct usb_interface *intf, pm_message_t message) struct kaweth_device *kaweth = usb_get_intfdata(intf); unsigned long flags; + dbg("Suspending device"); spin_lock_irqsave(&kaweth->device_lock, flags); kaweth->status |= KAWETH_STATUS_SUSPENDING; spin_unlock_irqrestore(&kaweth->device_lock, flags); @@ -924,6 +948,7 @@ static int kaweth_resume(struct usb_interface *intf) struct kaweth_device *kaweth = usb_get_intfdata(intf); unsigned long flags; + dbg("Resuming device"); spin_lock_irqsave(&kaweth->device_lock, flags); kaweth->status &= ~KAWETH_STATUS_SUSPENDING; spin_unlock_irqrestore(&kaweth->device_lock, flags); @@ -1086,6 +1111,8 @@ err_fw: dbg("Initializing net device."); + kaweth->intf = intf; + kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!kaweth->tx_urb) goto err_free_netdev; @@ -1265,7 +1292,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, { struct urb *urb; int retv; - int length; + int length = 0; /* shut up GCC */ urb = usb_alloc_urb(0, GFP_NOIO); if (!urb) diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h index 98f6898cae1f..c7467823cd1c 100644 --- a/drivers/usb/net/pegasus.h +++ b/drivers/usb/net/pegasus.h @@ -214,9 +214,9 @@ PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988, DEFAULT_GPIO_RESET ) PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511, DEFAULT_GPIO_RESET | PEGASUS_II ) -PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004, +PEGASUS_DEV( "Corega FEther USB-TX", VENDOR_COREGA, 0x0004, DEFAULT_GPIO_RESET ) -PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d, +PEGASUS_DEV( "Corega FEther USB-TXS", VENDOR_COREGA, 0x000d, DEFAULT_GPIO_RESET | PEGASUS_II ) PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001, DEFAULT_GPIO_RESET ) diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index a322a16d9cf8..be888d2d813c 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -49,6 +49,8 @@ * - In some cases, MS-Windows will emit undocumented requests; this * matters more to peripheral implementations than host ones. * + * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync". + * * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and * currently rare) "Ethernet Emulation Model" (EEM). @@ -61,6 +63,9 @@ * - control-in: GET_ENCAPSULATED * * We'll try to ignore the RESPONSE_AVAILABLE notifications. + * + * REVISIT some RNDIS implementations seem to have curious issues still + * to be resolved. */ struct rndis_msg_hdr { __le32 msg_type; /* RNDIS_MSG_* */ @@ -71,8 +76,14 @@ struct rndis_msg_hdr { // ... and more } __attribute__ ((packed)); -/* RNDIS defines this (absurdly huge) control timeout */ -#define RNDIS_CONTROL_TIMEOUT_MS (10 * 1000) +/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */ +#define CONTROL_BUFFER_SIZE 1025 + +/* RNDIS defines an (absurdly huge) 10 second control timeout, + * but ActiveSync seems to use a more usual 5 second timeout + * (which matches the USB 2.0 spec). + */ +#define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000) #define ccpu2 __constant_cpu_to_le32 @@ -270,6 +281,7 @@ static void rndis_status(struct usbnet *dev, struct urb *urb) static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) { struct cdc_state *info = (void *) &dev->data; + int master_ifnum; int retval; unsigned count; __le32 rsp; @@ -279,7 +291,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) * disconnect(): either serialize, or dispatch responses on xid */ - /* Issue the request; don't bother byteswapping our xid */ + /* Issue the request; xid is unique, don't bother byteswapping it */ if (likely(buf->msg_type != RNDIS_MSG_HALT && buf->msg_type != RNDIS_MSG_RESET)) { xid = dev->xid++; @@ -287,11 +299,12 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) xid = dev->xid++; buf->request_id = (__force __le32) xid; } + master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber; retval = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), USB_CDC_SEND_ENCAPSULATED_COMMAND, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, info->u->bMasterInterface0, + 0, master_ifnum, buf, le32_to_cpu(buf->msg_len), RNDIS_CONTROL_TIMEOUT_MS); if (unlikely(retval < 0 || xid == 0)) @@ -306,13 +319,13 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) */ rsp = buf->msg_type | RNDIS_MSG_COMPLETION; for (count = 0; count < 10; count++) { - memset(buf, 0, 1024); + memset(buf, 0, CONTROL_BUFFER_SIZE); retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), USB_CDC_GET_ENCAPSULATED_RESPONSE, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, info->u->bMasterInterface0, - buf, 1024, + 0, master_ifnum, + buf, CONTROL_BUFFER_SIZE, RNDIS_CONTROL_TIMEOUT_MS); if (likely(retval >= 8)) { msg_len = le32_to_cpu(buf->msg_len); @@ -350,7 +363,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf) usb_sndctrlpipe(dev->udev, 0), USB_CDC_SEND_ENCAPSULATED_COMMAND, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, info->u->bMasterInterface0, + 0, master_ifnum, msg, sizeof *msg, RNDIS_CONTROL_TIMEOUT_MS); if (unlikely(retval < 0)) @@ -393,38 +406,64 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) u32 tmp; /* we can't rely on i/o from stack working, or stack allocation */ - u.buf = kmalloc(1024, GFP_KERNEL); + u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); if (!u.buf) return -ENOMEM; retval = usbnet_generic_cdc_bind(dev, intf); if (retval < 0) goto fail; - net->hard_header_len += sizeof (struct rndis_data_hdr); - - /* initialize; max transfer is 16KB at full speed */ u.init->msg_type = RNDIS_MSG_INIT; u.init->msg_len = ccpu2(sizeof *u.init); u.init->major_version = ccpu2(1); u.init->minor_version = ccpu2(0); - u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len); + /* max transfer (in spec) is 0x4000 at full speed, but for + * TX we'll stick to one Ethernet packet plus RNDIS framing. + * For RX we handle drivers that zero-pad to end-of-packet. + * Don't let userspace change these settings. + */ + net->hard_header_len += sizeof (struct rndis_data_hdr); + dev->hard_mtu = net->mtu + net->hard_header_len; + + dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1); + dev->rx_urb_size &= ~(dev->maxpacket - 1); + u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size); + + net->change_mtu = NULL; retval = rndis_command(dev, u.header); if (unlikely(retval < 0)) { /* it might not even be an RNDIS device!! */ dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); + goto fail_and_release; + } + tmp = le32_to_cpu(u.init_c->max_transfer_size); + if (tmp < dev->hard_mtu) { + dev_err(&intf->dev, + "dev can't take %u byte packets (max %u)\n", + dev->hard_mtu, tmp); goto fail_and_release; } - dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size); + /* REVISIT: peripheral "alignment" request is ignored ... */ - dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu, + dev_dbg(&intf->dev, + "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n", + dev->hard_mtu, tmp, dev->rx_urb_size, 1 << le32_to_cpu(u.init_c->packet_alignment)); - /* get designated host ethernet address */ - memset(u.get, 0, sizeof *u.get); + /* Get designated host ethernet address. + * + * Adding a payload exactly the same size as the expected response + * payload is an evident requirement MSFT added for ActiveSync. + * This undocumented (and nonsensical) issue was found by sniffing + * protocol requests from the ActiveSync 4.1 Windows driver. + */ + memset(u.get, 0, sizeof *u.get + 48); u.get->msg_type = RNDIS_MSG_QUERY; - u.get->msg_len = ccpu2(sizeof *u.get); + u.get->msg_len = ccpu2(sizeof *u.get + 48); u.get->oid = OID_802_3_PERMANENT_ADDRESS; + u.get->len = ccpu2(48); + u.get->offset = ccpu2(20); retval = rndis_command(dev, u.header); if (unlikely(retval < 0)) { @@ -432,7 +471,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) goto fail_and_release; } tmp = le32_to_cpu(u.get_c->offset); - if (unlikely((tmp + 8) > (1024 - ETH_ALEN) + if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN) || u.get_c->len != ccpu2(ETH_ALEN))) { dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n", tmp, le32_to_cpu(u.get_c->len)); @@ -598,6 +637,10 @@ static const struct usb_device_id products [] = { /* RNDIS is MSFT's un-official variant of CDC ACM */ USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), .driver_info = (unsigned long) &rndis_info, +}, { + /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ + USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), + .driver_info = (unsigned long) &rndis_info, }, { }, // END }; diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 86bcf63b6ba5..11dad42c3c60 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -572,8 +572,20 @@ static void aircable_unthrottle(struct usb_serial_port *port) schedule_work(&priv->rx_work); } +static struct usb_driver aircable_driver = { + .name = "aircable", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver aircable_device = { - .description = "aircable", + .driver = { + .owner = THIS_MODULE, + .name = "aircable", + }, + .usb_driver = &aircable_driver, .id_table = id_table, .num_ports = 1, .attach = aircable_attach, @@ -587,13 +599,6 @@ static struct usb_serial_driver aircable_device = { .unthrottle = aircable_unthrottle, }; -static struct usb_driver aircable_driver = { - .name = "aircable", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static int __init aircable_init (void) { int retval; diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index f2ca76a9cbac..0af42e32fa0a 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -277,6 +277,7 @@ static struct usb_serial_driver airprime_device = { .owner = THIS_MODULE, .name = "airprime", }, + .usb_driver = &airprime_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 5261cd22ee6b..edd685791a6b 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -444,6 +444,7 @@ static struct usb_driver ark3116_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table, + .no_dynamic_id = 1, }; static struct usb_serial_driver ark3116_device = { @@ -452,6 +453,7 @@ static struct usb_serial_driver ark3116_device = { .name = "ark3116", }, .id_table = id_table, + .usb_driver = &ark3116_driver, .num_interrupt_in = 1, .num_bulk_in = 1, .num_bulk_out = 1, diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 38b4dae319ee..3b800d277c4b 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -126,6 +126,7 @@ static struct usb_serial_driver belkin_device = { .name = "belkin", }, .description = "Belkin / Peracom / GoHubs USB Serial Adapter", + .usb_driver = &belkin_driver, .id_table = id_table_combined, .num_interrupt_in = 1, .num_bulk_in = 1, 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/cp2101.c b/drivers/usb/serial/cp2101.c index 7ebaffd6ed86..06b4fffc189c 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -89,6 +89,7 @@ static struct usb_serial_driver cp2101_device = { .owner = THIS_MODULE, .name = "cp2101", }, + .usb_driver = &cp2101_driver, .id_table = id_table, .num_interrupt_in = 0, .num_bulk_in = 0, diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index a63c3286caa0..4167753ed31f 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -88,6 +88,7 @@ static struct usb_serial_driver cyberjack_device = { .name = "cyberjack", }, .description = "Reiner SCT Cyberjack USB card reader", + .usb_driver = &cyberjack_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -98,7 +99,7 @@ static struct usb_serial_driver cyberjack_device = { .open = cyberjack_open, .close = cyberjack_close, .write = cyberjack_write, - .write_room = cyberjack_write_room, + .write_room = cyberjack_write_room, .read_int_callback = cyberjack_read_int_callback, .read_bulk_callback = cyberjack_read_bulk_callback, .write_bulk_callback = cyberjack_write_bulk_callback, diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 6bc1f404e186..57b8e27285fc 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -193,6 +193,7 @@ static struct usb_serial_driver cypress_earthmate_device = { .name = "earthmate", }, .description = "DeLorme Earthmate USB", + .usb_driver = &cypress_driver, .id_table = id_table_earthmate, .num_interrupt_in = 1, .num_interrupt_out = 1, @@ -222,6 +223,7 @@ static struct usb_serial_driver cypress_hidcom_device = { .name = "cyphidcom", }, .description = "HID->COM RS232 Adapter", + .usb_driver = &cypress_driver, .id_table = id_table_cyphidcomrs232, .num_interrupt_in = 1, .num_interrupt_out = 1, @@ -251,6 +253,7 @@ static struct usb_serial_driver cypress_ca42v2_device = { .name = "nokiaca42v2", }, .description = "Nokia CA-42 V2 Adapter", + .usb_driver = &cypress_driver, .id_table = id_table_nokiaca42v2, .num_interrupt_in = 1, .num_interrupt_out = 1, diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index efd9ce3f931f..0b0fb51bad3e 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -509,6 +509,7 @@ static struct usb_serial_driver digi_acceleport_2_device = { .name = "digi_2", }, .description = "Digi 2 port USB adapter", + .usb_driver = &digi_driver, .id_table = id_table_2, .num_interrupt_in = 0, .num_bulk_in = 4, @@ -538,6 +539,7 @@ static struct usb_serial_driver digi_acceleport_4_device = { .name = "digi_4", }, .description = "Digi 4 port USB adapter", + .usb_driver = &digi_driver, .id_table = id_table_4, .num_interrupt_in = 0, .num_bulk_in = 5, diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 92beeb19795f..4703c8f85383 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -117,6 +117,7 @@ static struct usb_serial_driver empeg_device = { .name = "empeg", }, .id_table = id_table, + .usb_driver = &empeg_driver, .num_interrupt_in = 0, .num_bulk_in = 1, .num_bulk_out = 1, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 6986e756f7c0..4695952b6470 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -464,7 +464,6 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) }, - { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) }, @@ -615,6 +614,7 @@ static struct usb_serial_driver ftdi_sio_device = { .name = "ftdi_sio", }, .description = "FTDI USB Serial Device", + .usb_driver = &ftdi_driver , .id_table = id_table_combined, .num_interrupt_in = 0, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 40dd394de58d..7eff1c03ba80 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -364,7 +364,6 @@ * USB-TTY activ, USB-TTY passiv. Some PIDs are used by several devices * and I'm not entirely sure which are used by which. */ -#define FTDI_4N_GALAXY_DE_0_PID 0x8372 #define FTDI_4N_GALAXY_DE_1_PID 0xF3C0 #define FTDI_4N_GALAXY_DE_2_PID 0xF3C1 diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 2bebd63d5ed1..4092f6dc9efd 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -58,6 +58,7 @@ static struct usb_serial_driver funsoft_device = { .name = "funsoft", }, .id_table = id_table, + .usb_driver = &funsoft_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 6530d391ebed..74660a3aa670 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1566,6 +1566,7 @@ static struct usb_serial_driver garmin_device = { .name = "garmin_gps", }, .description = "Garmin GPS usb/tty", + .usb_driver = &garmin_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 36042937e77f..601e0648dec6 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -20,6 +20,10 @@ #include #include +static int generic_probe(struct usb_interface *interface, + const struct usb_device_id *id); + + static int debug; #ifdef CONFIG_USB_SERIAL_GENERIC @@ -34,6 +38,21 @@ MODULE_PARM_DESC(product, "User specified USB idProduct"); static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ +/* we want to look at all devices, as the vendor/product id can change + * depending on the command line argument */ +static struct usb_device_id generic_serial_ids[] = { + {.driver_info = 42}, + {} +}; + +static struct usb_driver generic_driver = { + .name = "usbserial_generic", + .probe = generic_probe, + .disconnect = usb_serial_disconnect, + .id_table = generic_serial_ids, + .no_dynamic_id = 1, +}; + /* All of the device info needed for the Generic Serial Converter */ struct usb_serial_driver usb_serial_generic_device = { .driver = { @@ -41,6 +60,7 @@ struct usb_serial_driver usb_serial_generic_device = { .name = "generic", }, .id_table = generic_device_ids, + .usb_driver = &generic_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, @@ -48,13 +68,6 @@ struct usb_serial_driver usb_serial_generic_device = { .shutdown = usb_serial_generic_shutdown, }; -/* we want to look at all devices, as the vendor/product id can change - * depending on the command line argument */ -static struct usb_device_id generic_serial_ids[] = { - {.driver_info = 42}, - {} -}; - static int generic_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -65,14 +78,6 @@ static int generic_probe(struct usb_interface *interface, return usb_serial_probe(interface, id); return -ENODEV; } - -static struct usb_driver generic_driver = { - .name = "usbserial_generic", - .probe = generic_probe, - .disconnect = usb_serial_disconnect, - .id_table = generic_serial_ids, - .no_dynamic_id = 1, -}; #endif int usb_serial_generic_register (int _debug) diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c index ebcac701b069..6c6ebae741c9 100644 --- a/drivers/usb/serial/hp4x.c +++ b/drivers/usb/serial/hp4x.c @@ -49,6 +49,7 @@ static struct usb_serial_driver hp49gp_device = { .name = "hp4X", }, .id_table = id_table, + .usb_driver = &hp49gp_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index f623d58370a4..6a26a2e683a6 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -146,6 +146,8 @@ struct edgeport_serial { struct edge_manuf_descriptor manuf_descriptor; /* the manufacturer descriptor */ struct edge_boot_descriptor boot_descriptor; /* the boot firmware descriptor */ struct edgeport_product_info product_info; /* Product Info */ + struct edge_compatibility_descriptor epic_descriptor; /* Edgeport compatible descriptor */ + int is_epic; /* flag if EPiC device or not */ __u8 interrupt_in_endpoint; /* the interrupt endpoint handle */ unsigned char * interrupt_in_buffer; /* the buffer we use for the interrupt endpoint */ @@ -240,14 +242,6 @@ static void edge_shutdown (struct usb_serial *serial); #include "io_tables.h" /* all of the devices that this driver supports */ -static struct usb_driver io_driver = { - .name = "io_edgeport", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; - /* function prototypes for all of our local functions */ static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength); static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3); @@ -397,6 +391,7 @@ static int get_string (struct usb_device *dev, int Id, char *string, int buflen) unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2); kfree(pStringDesc); + dbg("%s - USB String %s", __FUNCTION__, string); return strlen(string); } @@ -434,6 +429,34 @@ static int get_string_desc (struct usb_device *dev, int Id, struct usb_string_de } #endif +static void dump_product_info(struct edgeport_product_info *product_info) +{ + // Dump Product Info structure + dbg("**Product Information:"); + dbg(" ProductId %x", product_info->ProductId ); + dbg(" NumPorts %d", product_info->NumPorts ); + dbg(" ProdInfoVer %d", product_info->ProdInfoVer ); + dbg(" IsServer %d", product_info->IsServer); + dbg(" IsRS232 %d", product_info->IsRS232 ); + dbg(" IsRS422 %d", product_info->IsRS422 ); + dbg(" IsRS485 %d", product_info->IsRS485 ); + dbg(" RomSize %d", product_info->RomSize ); + dbg(" RamSize %d", product_info->RamSize ); + dbg(" CpuRev %x", product_info->CpuRev ); + dbg(" BoardRev %x", product_info->BoardRev); + dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion, + product_info->BootMinorVersion, + le16_to_cpu(product_info->BootBuildNumber)); + dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion, + product_info->FirmwareMinorVersion, + le16_to_cpu(product_info->FirmwareBuildNumber)); + dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0], + product_info->ManufactureDescDate[1], + product_info->ManufactureDescDate[2]+1900); + dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); + dbg(" EpicVer %d", product_info->EpicVer); +} + static void get_product_info(struct edgeport_serial *edge_serial) { struct edgeport_product_info *product_info = &edge_serial->product_info; @@ -495,30 +518,60 @@ static void get_product_info(struct edgeport_serial *edge_serial) break; } - // Dump Product Info structure - dbg("**Product Information:"); - dbg(" ProductId %x", product_info->ProductId ); - dbg(" NumPorts %d", product_info->NumPorts ); - dbg(" ProdInfoVer %d", product_info->ProdInfoVer ); - dbg(" IsServer %d", product_info->IsServer); - dbg(" IsRS232 %d", product_info->IsRS232 ); - dbg(" IsRS422 %d", product_info->IsRS422 ); - dbg(" IsRS485 %d", product_info->IsRS485 ); - dbg(" RomSize %d", product_info->RomSize ); - dbg(" RamSize %d", product_info->RamSize ); - dbg(" CpuRev %x", product_info->CpuRev ); - dbg(" BoardRev %x", product_info->BoardRev); - dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion, - product_info->BootMinorVersion, - le16_to_cpu(product_info->BootBuildNumber)); - dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion, - product_info->FirmwareMinorVersion, - le16_to_cpu(product_info->FirmwareBuildNumber)); - dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0], - product_info->ManufactureDescDate[1], - product_info->ManufactureDescDate[2]+1900); - dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); + dump_product_info(product_info); +} +static int get_epic_descriptor(struct edgeport_serial *ep) +{ + int result; + struct usb_serial *serial = ep->serial; + struct edgeport_product_info *product_info = &ep->product_info; + struct edge_compatibility_descriptor *epic = &ep->epic_descriptor; + struct edge_compatibility_bits *bits; + + ep->is_epic = 0; + result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + USB_REQUEST_ION_GET_EPIC_DESC, + 0xC0, 0x00, 0x00, + &ep->epic_descriptor, + sizeof(struct edge_compatibility_descriptor), + 300); + + dbg("%s result = %d", __FUNCTION__, result); + + if (result > 0) { + ep->is_epic = 1; + memset(product_info, 0, sizeof(struct edgeport_product_info)); + + product_info->NumPorts = epic->NumPorts; + product_info->ProdInfoVer = 0; + product_info->FirmwareMajorVersion = epic->MajorVersion; + product_info->FirmwareMinorVersion = epic->MinorVersion; + product_info->FirmwareBuildNumber = epic->BuildNumber; + product_info->iDownloadFile = epic->iDownloadFile; + product_info->EpicVer = epic->EpicVer; + product_info->Epic = epic->Supports; + product_info->ProductId = ION_DEVICE_ID_EDGEPORT_COMPATIBLE; + dump_product_info(product_info); + + bits = &ep->epic_descriptor.Supports; + dbg("**EPIC descriptor:"); + dbg(" VendEnableSuspend: %s", bits->VendEnableSuspend ? "TRUE": "FALSE"); + dbg(" IOSPOpen : %s", bits->IOSPOpen ? "TRUE": "FALSE" ); + dbg(" IOSPClose : %s", bits->IOSPClose ? "TRUE": "FALSE" ); + dbg(" IOSPChase : %s", bits->IOSPChase ? "TRUE": "FALSE" ); + dbg(" IOSPSetRxFlow : %s", bits->IOSPSetRxFlow ? "TRUE": "FALSE" ); + dbg(" IOSPSetTxFlow : %s", bits->IOSPSetTxFlow ? "TRUE": "FALSE" ); + dbg(" IOSPSetXChar : %s", bits->IOSPSetXChar ? "TRUE": "FALSE" ); + dbg(" IOSPRxCheck : %s", bits->IOSPRxCheck ? "TRUE": "FALSE" ); + dbg(" IOSPSetClrBreak : %s", bits->IOSPSetClrBreak ? "TRUE": "FALSE" ); + dbg(" IOSPWriteMCR : %s", bits->IOSPWriteMCR ? "TRUE": "FALSE" ); + dbg(" IOSPWriteLCR : %s", bits->IOSPWriteLCR ? "TRUE": "FALSE" ); + dbg(" IOSPSetBaudRate : %s", bits->IOSPSetBaudRate ? "TRUE": "FALSE" ); + dbg(" TrueEdgeport : %s", bits->TrueEdgeport ? "TRUE": "FALSE" ); + } + + return result; } @@ -1017,21 +1070,29 @@ static void edge_close (struct usb_serial_port *port, struct file * filp) edge_port->closePending = TRUE; - /* flush and chase */ - edge_port->chaseResponsePending = TRUE; + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPChase))) { + /* flush and chase */ + edge_port->chaseResponsePending = TRUE; - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); - if (status == 0) { - // block until chase finished - block_until_chase_response(edge_port); - } else { - edge_port->chaseResponsePending = FALSE; + dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); + if (status == 0) { + // block until chase finished + block_until_chase_response(edge_port); + } else { + edge_port->chaseResponsePending = FALSE; + } } - /* close the port */ - dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__); - send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPClose))) { + /* close the port */ + dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__); + send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0); + } //port->close = TRUE; edge_port->closePending = FALSE; @@ -1694,29 +1755,38 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned static void edge_break (struct usb_serial_port *port, int break_state) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); + struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial); int status; - /* flush and chase */ - edge_port->chaseResponsePending = TRUE; + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPChase))) { + /* flush and chase */ + edge_port->chaseResponsePending = TRUE; - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); - if (status == 0) { - // block until chase finished - block_until_chase_response(edge_port); - } else { - edge_port->chaseResponsePending = FALSE; + dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); + if (status == 0) { + // block until chase finished + block_until_chase_response(edge_port); + } else { + edge_port->chaseResponsePending = FALSE; + } } - if (break_state == -1) { - dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0); - } else { - dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__); - status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0); - } - if (status) { - dbg("%s - error sending break set/clear command.", __FUNCTION__); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) { + if (break_state == -1) { + dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0); + } else { + dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__); + status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0); + } + if (status) { + dbg("%s - error sending break set/clear command.", __FUNCTION__); + } } return; @@ -2288,6 +2358,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer *****************************************************************************/ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate) { + struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); unsigned char *cmdBuffer; unsigned char *currCmd; int cmdLen = 0; @@ -2295,6 +2366,14 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa int status; unsigned char number = edge_port->port->number - edge_port->port->serial->minor; + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate))) { + dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d", + edge_port->port->number, baudRate); + return 0; + } + dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate); status = calc_baud_rate_divisor (baudRate, &divisor); @@ -2374,6 +2453,7 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor) *****************************************************************************/ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue) { + struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); unsigned char *cmdBuffer; unsigned char *currCmd; unsigned long cmdLen = 0; @@ -2381,6 +2461,22 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) && + (regNum == MCR))) { + dbg("SendCmdWriteUartReg - Not writting to MCR Register"); + return 0; + } + + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) && + (regNum == LCR))) { + dbg ("SendCmdWriteUartReg - Not writting to LCR Register"); + return 0; + } + // Alloc memory for the string of commands. cmdBuffer = kmalloc (0x10, GFP_ATOMIC); if (cmdBuffer == NULL ) { @@ -2414,6 +2510,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r #endif static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios) { + struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial); struct tty_struct *tty; int baud; unsigned cflag; @@ -2494,8 +2591,12 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi unsigned char stop_char = STOP_CHAR(tty); unsigned char start_char = START_CHAR(tty); - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char); - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetXChar))) { + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XON_CHAR, start_char); + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char); + } /* if we are implementing INBOUND XON/XOFF */ if (I_IXOFF(tty)) { @@ -2515,8 +2616,14 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi } /* Set flow control to the configured value */ - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow); - send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_TX_FLOW, txFlow); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetRxFlow))) + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow); + if ((!edge_serial->is_epic) || + ((edge_serial->is_epic) && + (edge_serial->epic_descriptor.Supports.IOSPSetTxFlow))) + send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow); edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); @@ -2728,6 +2835,13 @@ static int edge_startup (struct usb_serial *serial) struct edgeport_port *edge_port; struct usb_device *dev; int i, j; + int response; + int interrupt_in_found; + int bulk_in_found; + int bulk_out_found; + static __u32 descriptor[3] = { EDGE_COMPATIBILITY_MASK0, + EDGE_COMPATIBILITY_MASK1, + EDGE_COMPATIBILITY_MASK2 }; dev = serial->dev; @@ -2750,38 +2864,50 @@ static int edge_startup (struct usb_serial *serial) dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name); - /* get the manufacturing descriptor for this device */ - get_manufacturing_desc (edge_serial); + /* Read the epic descriptor */ + if (get_epic_descriptor(edge_serial) <= 0) { + /* memcpy descriptor to Supports structures */ + memcpy(&edge_serial->epic_descriptor.Supports, descriptor, + sizeof(struct edge_compatibility_bits)); - /* get the boot descriptor */ - get_boot_desc (edge_serial); + /* get the manufacturing descriptor for this device */ + get_manufacturing_desc (edge_serial); - get_product_info(edge_serial); + /* get the boot descriptor */ + get_boot_desc (edge_serial); + + get_product_info(edge_serial); + } /* set the number of ports from the manufacturing description */ /* serial->num_ports = serial->product_info.NumPorts; */ - if (edge_serial->product_info.NumPorts != serial->num_ports) { - warn("%s - Device Reported %d serial ports vs core " - "thinking we have %d ports, email greg@kroah.com this info.", - __FUNCTION__, edge_serial->product_info.NumPorts, - serial->num_ports); + if ((!edge_serial->is_epic) && + (edge_serial->product_info.NumPorts != serial->num_ports)) { + dev_warn(&serial->dev->dev, "Device Reported %d serial ports " + "vs. core thinking we have %d ports, email " + "greg@kroah.com this information.", + edge_serial->product_info.NumPorts, + serial->num_ports); } dbg("%s - time 1 %ld", __FUNCTION__, jiffies); - /* now load the application firmware into this device */ - load_application_firmware (edge_serial); + /* If not an EPiC device */ + if (!edge_serial->is_epic) { + /* now load the application firmware into this device */ + load_application_firmware (edge_serial); - dbg("%s - time 2 %ld", __FUNCTION__, jiffies); + dbg("%s - time 2 %ld", __FUNCTION__, jiffies); - /* Check current Edgeport EEPROM and update if necessary */ - update_edgeport_E2PROM (edge_serial); - - dbg("%s - time 3 %ld", __FUNCTION__, jiffies); + /* Check current Edgeport EEPROM and update if necessary */ + update_edgeport_E2PROM (edge_serial); - /* set the configuration to use #1 */ -// dbg("set_configuration 1"); -// usb_set_configuration (dev, 1); + dbg("%s - time 3 %ld", __FUNCTION__, jiffies); + + /* set the configuration to use #1 */ +// dbg("set_configuration 1"); +// usb_set_configuration (dev, 1); + } /* we set up the pointers to the endpoints in the edge_open function, * as the structures aren't created yet. */ @@ -2804,8 +2930,101 @@ static int edge_startup (struct usb_serial *serial) edge_port->port = serial->port[i]; usb_set_serial_port_data(serial->port[i], edge_port); } - - return 0; + + response = 0; + + if (edge_serial->is_epic) { + /* EPIC thing, set up our interrupt polling now and our read urb, so + * that the device knows it really is connected. */ + interrupt_in_found = bulk_in_found = bulk_out_found = FALSE; + for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) { + struct usb_endpoint_descriptor *endpoint; + int buffer_size; + + endpoint = &serial->interface->altsetting[0].endpoint[i].desc; + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + if ((!interrupt_in_found) && + (usb_endpoint_is_int_in(endpoint))) { + /* we found a interrupt in endpoint */ + dbg("found interrupt in"); + + /* not set up yet, so do it now */ + edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!edge_serial->interrupt_read_urb) { + err("out of memory"); + return -ENOMEM; + } + edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!edge_serial->interrupt_in_buffer) { + err("out of memory"); + usb_free_urb(edge_serial->interrupt_read_urb); + return -ENOMEM; + } + edge_serial->interrupt_in_endpoint = endpoint->bEndpointAddress; + + /* set up our interrupt urb */ + usb_fill_int_urb(edge_serial->interrupt_read_urb, + dev, + usb_rcvintpipe(dev, endpoint->bEndpointAddress), + edge_serial->interrupt_in_buffer, + buffer_size, + edge_interrupt_callback, + edge_serial, + endpoint->bInterval); + + interrupt_in_found = TRUE; + } + + if ((!bulk_in_found) && + (usb_endpoint_is_bulk_in(endpoint))) { + /* we found a bulk in endpoint */ + dbg("found bulk in"); + + /* not set up yet, so do it now */ + edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!edge_serial->read_urb) { + err("out of memory"); + return -ENOMEM; + } + edge_serial->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!edge_serial->bulk_in_buffer) { + err ("out of memory"); + usb_free_urb(edge_serial->read_urb); + return -ENOMEM; + } + edge_serial->bulk_in_endpoint = endpoint->bEndpointAddress; + + /* set up our bulk in urb */ + usb_fill_bulk_urb(edge_serial->read_urb, dev, + usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), + edge_serial->bulk_in_buffer, + endpoint->wMaxPacketSize, + edge_bulk_in_callback, + edge_serial); + bulk_in_found = TRUE; + } + + if ((!bulk_out_found) && + (usb_endpoint_is_bulk_out(endpoint))) { + /* we found a bulk out endpoint */ + dbg("found bulk out"); + edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress; + bulk_out_found = TRUE; + } + } + + if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) { + err ("Error - the proper endpoints were not found!"); + return -ENODEV; + } + + /* start interrupt read for this edgeport this interrupt will + * continue as long as the edgeport is connected */ + response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL); + if (response) + err("%s - Error %d submitting control urb", __FUNCTION__, response); + } + return response; } @@ -2815,6 +3034,7 @@ static int edge_startup (struct usb_serial *serial) ****************************************************************************/ static void edge_shutdown (struct usb_serial *serial) { + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); int i; dbg("%s", __FUNCTION__); @@ -2824,7 +3044,18 @@ static void edge_shutdown (struct usb_serial *serial) kfree (usb_get_serial_port_data(serial->port[i])); usb_set_serial_port_data(serial->port[i], NULL); } - kfree (usb_get_serial_data(serial)); + /* free up our endpoint stuff */ + if (edge_serial->is_epic) { + usb_unlink_urb(edge_serial->interrupt_read_urb); + usb_free_urb(edge_serial->interrupt_read_urb); + kfree(edge_serial->interrupt_in_buffer); + + usb_unlink_urb(edge_serial->read_urb); + usb_free_urb(edge_serial->read_urb); + kfree(edge_serial->bulk_in_buffer); + } + + kfree(edge_serial); usb_set_serial_data(serial, NULL); } @@ -2846,6 +3077,9 @@ static int __init edgeport_init(void) retval = usb_serial_register(&edgeport_8port_device); if (retval) goto failed_8port_device_register; + retval = usb_serial_register(&epic_device); + if (retval) + goto failed_epic_device_register; retval = usb_register(&io_driver); if (retval) goto failed_usb_register; @@ -2853,6 +3087,8 @@ static int __init edgeport_init(void) return 0; failed_usb_register: + usb_serial_deregister(&epic_device); +failed_epic_device_register: usb_serial_deregister(&edgeport_8port_device); failed_8port_device_register: usb_serial_deregister(&edgeport_4port_device); @@ -2873,6 +3109,7 @@ static void __exit edgeport_exit (void) usb_serial_deregister (&edgeport_2port_device); usb_serial_deregister (&edgeport_4port_device); usb_serial_deregister (&edgeport_8port_device); + usb_serial_deregister (&epic_device); } module_init(edgeport_init); diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h index 123fa8a904e6..29a913a6daca 100644 --- a/drivers/usb/serial/io_edgeport.h +++ b/drivers/usb/serial/io_edgeport.h @@ -111,10 +111,12 @@ struct edgeport_product_info { __le16 FirmwareBuildNumber; /* zzzz (LE format) */ __u8 ManufactureDescDate[3]; /* MM/DD/YY when descriptor template was compiled */ - __u8 Unused1[1]; /* Available */ + __u8 HardwareType; __u8 iDownloadFile; /* What to download to EPiC device */ - __u8 Unused2[2]; /* Available */ + __u8 EpicVer; /* What version of EPiC spec this device supports */ + + struct edge_compatibility_bits Epic; }; /* diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index fad561c04c76..6d3008772540 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -47,6 +47,18 @@ static struct usb_device_id edgeport_8port_id_table [] = { { } }; +static struct usb_device_id Epic_port_id_table [] = { + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, + { } +}; + /* Devices that this driver supports */ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, @@ -70,17 +82,34 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, id_table_combined); +static struct usb_driver io_driver = { + .name = "io_edgeport", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table_combined, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver edgeport_2port_device = { .driver = { .owner = THIS_MODULE, .name = "edgeport_2", }, .description = "Edgeport 2 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_2port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -111,6 +140,7 @@ static struct usb_serial_driver edgeport_4port_device = { .name = "edgeport_4", }, .description = "Edgeport 4 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_4port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -141,6 +171,7 @@ static struct usb_serial_driver edgeport_8port_device = { .name = "edgeport_8", }, .description = "Edgeport 8 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_8port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -165,5 +196,35 @@ static struct usb_serial_driver edgeport_8port_device = { .write_bulk_callback = edge_bulk_out_data_callback, }; +static struct usb_serial_driver epic_device = { + .driver = { + .owner = THIS_MODULE, + .name = "epic", + }, + .description = "EPiC device", + .id_table = Epic_port_id_table, + .num_interrupt_in = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .shutdown = edge_shutdown, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .tiocmget = edge_tiocmget, + .tiocmset = edge_tiocmset, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, + .read_int_callback = edge_interrupt_callback, + .read_bulk_callback = edge_bulk_in_callback, + .write_bulk_callback = edge_bulk_out_data_callback, +}; + #endif diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 980285c0233a..544098d2b775 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2979,6 +2979,7 @@ static struct usb_serial_driver edgeport_1port_device = { .name = "edgeport_ti_1", }, .description = "Edgeport TI 1 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_1port_id_table, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -3009,6 +3010,7 @@ static struct usb_serial_driver edgeport_2port_device = { .name = "edgeport_ti_2", }, .description = "Edgeport TI 2 port adapter", + .usb_driver = &io_driver, .id_table = edgeport_2port_id_table, .num_interrupt_in = 1, .num_bulk_in = 2, diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h index f1804fd5a3dd..e57fa117e486 100644 --- a/drivers/usb/serial/io_usbvend.h +++ b/drivers/usb/serial/io_usbvend.h @@ -30,6 +30,7 @@ #define USB_VENDOR_ID_ION 0x1608 // Our VID #define USB_VENDOR_ID_TI 0x0451 // TI VID +#define USB_VENDOR_ID_AXIOHM 0x05D9 /* Axiohm VID */ // // Definitions of USB product IDs (PID) @@ -334,6 +335,10 @@ struct edge_compatibility_bits }; +#define EDGE_COMPATIBILITY_MASK0 0x0001 +#define EDGE_COMPATIBILITY_MASK1 0x3FFF +#define EDGE_COMPATIBILITY_MASK2 0x0001 + struct edge_compatibility_descriptor { __u8 Length; // Descriptor Length (per USB spec) diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 42f757a5b876..a408184334ea 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -563,6 +563,7 @@ static struct usb_serial_driver ipaq_device = { .name = "ipaq", }, .description = "PocketPC PDA", + .usb_driver = &ipaq_driver, .id_table = ipaq_id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index d3b9a351cef8..1bc586064c77 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -442,6 +442,7 @@ static struct usb_serial_driver ipw_device = { .name = "ipw", }, .description = "IPWireless converter", + .usb_driver = &usb_ipw_driver, .id_table = usb_ipw_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 8fdf486e3465..9d847f69291c 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -138,6 +138,7 @@ static struct usb_serial_driver ir_device = { .name = "ir-usb", }, .description = "IR Dongle", + .usb_driver = &ir_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 9d2fdfd6865f..e6966f12ed5a 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -1275,11 +1275,31 @@ static int keyspan_fake_startup (struct usb_serial *serial) } /* Helper functions used by keyspan_setup_urbs */ +static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial, + int endpoint) +{ + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *ep; + int i; + + iface_desc = serial->interface->cur_altsetting; + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + ep = &iface_desc->endpoint[i].desc; + if (ep->bEndpointAddress == endpoint) + return ep; + } + dev_warn(&serial->interface->dev, "found no endpoint descriptor for " + "endpoint %x\n", endpoint); + return NULL; +} + static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint, int dir, void *ctx, char *buf, int len, void (*callback)(struct urb *)) { struct urb *urb; + struct usb_endpoint_descriptor const *ep_desc; + char const *ep_type_name; if (endpoint == -1) return NULL; /* endpoint not needed */ @@ -1291,11 +1311,32 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint, return NULL; } - /* Fill URB using supplied data. */ - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, endpoint) | dir, - buf, len, callback, ctx); + ep_desc = find_ep(serial, endpoint); + if (!ep_desc) { + /* leak the urb, something's wrong and the callers don't care */ + return urb; + } + if (usb_endpoint_xfer_int(ep_desc)) { + ep_type_name = "INT"; + usb_fill_int_urb(urb, serial->dev, + usb_sndintpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx, + ep_desc->bInterval); + } else if (usb_endpoint_xfer_bulk(ep_desc)) { + ep_type_name = "BULK"; + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx); + } else { + dev_warn(&serial->interface->dev, + "unsupported endpoint type %x\n", + ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); + usb_free_urb(urb); + return NULL; + } + dbg("%s - using urb %p for %s endpoint %x", + __func__, urb, ep_type_name, endpoint); return urb; } diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 6413d73c139c..c6830cbdc6df 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -229,7 +229,6 @@ struct ezusb_hex_record { #define keyspan_usa28_product_id 0x010f #define keyspan_usa28x_product_id 0x0110 #define keyspan_usa28xa_product_id 0x0115 -#define keyspan_usa28xb_product_id 0x0110 #define keyspan_usa49w_product_id 0x010a #define keyspan_usa49wlc_product_id 0x012a @@ -511,7 +510,6 @@ static struct usb_device_id keyspan_ids_combined[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)}, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, { } /* Terminating entry */ @@ -559,7 +557,6 @@ static struct usb_device_id keyspan_2port_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) }, { } /* Terminating entry */ }; @@ -576,6 +573,7 @@ static struct usb_serial_driver keyspan_pre_device = { .name = "keyspan_no_firm", }, .description = "Keyspan - (without firmware)", + .usb_driver = &keyspan_driver, .id_table = keyspan_pre_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -590,6 +588,7 @@ static struct usb_serial_driver keyspan_1port_device = { .name = "keyspan_1", }, .description = "Keyspan 1 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_1port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -617,6 +616,7 @@ static struct usb_serial_driver keyspan_2port_device = { .name = "keyspan_2", }, .description = "Keyspan 2 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_2port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -644,6 +644,7 @@ static struct usb_serial_driver keyspan_4port_device = { .name = "keyspan_4", }, .description = "Keyspan 4 port adapter", + .usb_driver = &keyspan_driver, .id_table = keyspan_4port_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 5, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 126b9703bbaf..da514cb785b3 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -793,6 +793,7 @@ static struct usb_serial_driver keyspan_pda_fake_device = { .name = "keyspan_pda_pre", }, .description = "Keyspan PDA - (prerenumeration)", + .usb_driver = &keyspan_pda_driver, .id_table = id_table_fake, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -809,6 +810,7 @@ static struct usb_serial_driver xircom_pgs_fake_device = { .name = "xircom_no_firm", }, .description = "Xircom / Entregra PGS - (prerenumeration)", + .usb_driver = &keyspan_pda_driver, .id_table = id_table_fake_xircom, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -824,6 +826,7 @@ static struct usb_serial_driver keyspan_pda_device = { .name = "keyspan_pda", }, .description = "Keyspan PDA", + .usb_driver = &keyspan_pda_driver, .id_table = id_table_std, .num_interrupt_in = 1, .num_bulk_in = 0, diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 5c4b06a99ac0..b2097c45a235 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -124,6 +124,7 @@ static struct usb_serial_driver kl5kusb105d_device = { .name = "kl5kusb105d", }, .description = "KL5KUSB105D / PalmConnect", + .usb_driver = &kl5kusb105d_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 62bea0c923bd..0683b51f0932 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -110,6 +110,7 @@ static struct usb_serial_driver kobil_device = { .name = "kobil", }, .description = "KOBIL USB smart card terminal", + .usb_driver = &kobil_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 0, diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 38b1d17e06ef..4cd839b1407f 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -137,6 +137,7 @@ static struct usb_serial_driver mct_u232_device = { .name = "mct_u232", }, .description = "MCT U232", + .usb_driver = &mct_u232_driver, .id_table = id_table_combined, .num_interrupt_in = 2, .num_bulk_in = 0, diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index e55f4ed81d7b..6109c6704a73 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1605,12 +1605,21 @@ static void mos7720_shutdown(struct usb_serial *serial) usb_set_serial_data(serial, NULL); } +static struct usb_driver usb_driver = { + .name = "moschip7720", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = moschip_port_id_table, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver moschip7720_2port_driver = { .driver = { .owner = THIS_MODULE, .name = "moschip7720", }, .description = "Moschip 2 port adapter", + .usb_driver = &usb_driver, .id_table = moschip_port_id_table, .num_interrupt_in = 1, .num_bulk_in = 2, @@ -1631,13 +1640,6 @@ static struct usb_serial_driver moschip7720_2port_driver = { .read_bulk_callback = mos7720_bulk_in_callback, }; -static struct usb_driver usb_driver = { - .name = "moschip7720", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_port_id_table, -}; - static int __init moschip7720_init(void) { int retval; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 83f661403ba1..b2264a87617b 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2834,12 +2834,21 @@ static void mos7840_shutdown(struct usb_serial *serial) } +static struct usb_driver io_driver = { + .name = "mos7840", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = moschip_id_table_combined, + .no_dynamic_id = 1, +}; + static struct usb_serial_driver moschip7840_4port_device = { .driver = { .owner = THIS_MODULE, .name = "mos7840", }, .description = DRIVER_DESC, + .usb_driver = &io_driver, .id_table = moschip_port_id_table, .num_interrupt_in = 1, //NUM_DONT_CARE,//1, #ifdef check @@ -2869,13 +2878,6 @@ static struct usb_serial_driver moschip7840_4port_device = { .read_int_callback = mos7840_interrupt_callback, }; -static struct usb_driver io_driver = { - .name = "mos7840", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_id_table_combined, -}; - /**************************************************************************** * moschip7840_init * This is called by the module subsystem, or on startup to initialize us diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index 054abee81652..90701111d746 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -119,6 +119,7 @@ static struct usb_serial_driver navman_device = { .name = "navman", }, .id_table = id_table, + .usb_driver = &navman_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index bc91d3b726fc..0216ac12a27d 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -93,6 +93,7 @@ static struct usb_serial_driver zyxel_omninet_device = { .name = "omninet", }, .description = "ZyXEL - omni.net lcd plus usb", + .usb_driver = &omninet_driver, .id_table = id_table, .num_interrupt_in = 1, .num_bulk_in = 1, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 0fed43a96871..ced9f32b29d9 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -135,6 +135,7 @@ static struct usb_serial_driver option_1port_device = { .name = "option1", }, .description = "GSM modem (1-port)", + .usb_driver = &option_driver, .id_table = option_ids1, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 5dc2ac9afa90..6c083d4e2c9b 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -1118,6 +1118,7 @@ static struct usb_serial_driver pl2303_device = { .name = "pl2303", }, .id_table = id_table, + .usb_driver = &pl2303_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, .num_bulk_out = 1, diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 30b7ebc8d45d..5a03a3fc9386 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -402,6 +402,7 @@ static struct usb_serial_driver safe_device = { .name = "safe_serial", }, .id_table = id_table, + .usb_driver = &safe_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 6d8e91e00ecf..ecedd833818d 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -13,10 +13,9 @@ Portions based on the option driver by Matthias Urlichs Whom based his on the Keyspan driver by Hugh Blemings - History: */ -#define DRIVER_VERSION "v.1.0.5" +#define DRIVER_VERSION "v.1.0.6" #define DRIVER_AUTHOR "Kevin Lloyd " #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" @@ -31,14 +30,15 @@ static struct usb_device_id id_table [] = { - { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ - { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ + { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ + { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ + { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ @@ -55,14 +55,15 @@ static struct usb_device_id id_table_1port [] = { }; static struct usb_device_id id_table_3port [] = { - { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ - { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ + { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ + { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ + { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ { } @@ -81,7 +82,7 @@ static int debug; /* per port private data */ #define N_IN_URB 4 -#define N_OUT_URB 1 +#define N_OUT_URB 4 #define IN_BUFLEN 4096 #define OUT_BUFLEN 128 @@ -396,6 +397,8 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp) struct usb_serial *serial = port->serial; int i, err; struct urb *urb; + int result; + __u16 set_mode_dzero = 0x0000; portdata = usb_get_serial_port_data(port); @@ -442,6 +445,12 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp) port->tty->low_latency = 1; + /* set mode to D0 */ + result = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 0x00, 0x40, set_mode_dzero, 0, NULL, + 0, USB_CTRL_SET_TIMEOUT); + sierra_send_setup(port); return (0); @@ -614,6 +623,7 @@ static struct usb_serial_driver sierra_1port_device = { }, .description = "Sierra USB modem (1 port)", .id_table = id_table_1port, + .usb_driver = &sierra_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 1, .num_bulk_out = 1, @@ -642,6 +652,7 @@ static struct usb_serial_driver sierra_3port_device = { }, .description = "Sierra USB modem (3 port)", .id_table = id_table_3port, + .usb_driver = &sierra_driver, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 3, .num_bulk_out = 3, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 83189005c6fb..4203e2b1a761 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -262,6 +262,7 @@ static struct usb_serial_driver ti_1port_device = { .name = "ti_usb_3410_5052_1", }, .description = "TI USB 3410 1 port adapter", + .usb_driver = &ti_usb_driver, .id_table = ti_id_table_3410, .num_interrupt_in = 1, .num_bulk_in = 1, @@ -292,6 +293,7 @@ static struct usb_serial_driver ti_2port_device = { .name = "ti_usb_3410_5052_2", }, .description = "TI USB 5052 2 port adapter", + .usb_driver = &ti_usb_driver, .id_table = ti_id_table_5052, .num_interrupt_in = 1, .num_bulk_in = 2, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 716f6806cc89..6bf22a28adb8 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -59,14 +59,19 @@ static struct usb_driver usb_serial_driver = { static int debug; static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */ +static spinlock_t table_lock; static LIST_HEAD(usb_serial_driver_list); struct usb_serial *usb_serial_get_by_index(unsigned index) { - struct usb_serial *serial = serial_table[index]; + struct usb_serial *serial; + + spin_lock(&table_lock); + serial = serial_table[index]; if (serial) kref_get(&serial->kref); + spin_unlock(&table_lock); return serial; } @@ -78,6 +83,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po dbg("%s %d", __FUNCTION__, num_ports); *minor = 0; + spin_lock(&table_lock); for (i = 0; i < SERIAL_TTY_MINORS; ++i) { if (serial_table[i]) continue; @@ -96,8 +102,10 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po dbg("%s - minor base = %d", __FUNCTION__, *minor); for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) serial_table[i] = serial; + spin_unlock(&table_lock); return serial; } + spin_unlock(&table_lock); return NULL; } @@ -110,9 +118,11 @@ static void return_serial(struct usb_serial *serial) if (serial == NULL) return; + spin_lock(&table_lock); for (i = 0; i < serial->num_ports; ++i) { serial_table[serial->minor + i] = NULL; } + spin_unlock(&table_lock); } static void destroy_serial(struct kref *kref) @@ -271,7 +281,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) { struct usb_serial_port *port = tty->driver_data; - int retval = -EINVAL; + int retval = -ENODEV; if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) goto exit; @@ -279,6 +289,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); if (!port->open_count) { + retval = -EINVAL; dbg("%s - port not opened", __FUNCTION__); goto exit; } @@ -559,15 +570,20 @@ static void port_release(struct device *dev) port_free(port); } -static void port_free(struct usb_serial_port *port) +static void kill_traffic(struct usb_serial_port *port) { usb_kill_urb(port->read_urb); - usb_free_urb(port->read_urb); usb_kill_urb(port->write_urb); - usb_free_urb(port->write_urb); usb_kill_urb(port->interrupt_in_urb); - usb_free_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_out_urb); +} + +static void port_free(struct usb_serial_port *port) +{ + kill_traffic(port); + usb_free_urb(port->read_urb); + usb_free_urb(port->write_urb); + usb_free_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_out_urb); kfree(port->bulk_in_buffer); kfree(port->bulk_out_buffer); @@ -596,6 +612,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 +654,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; @@ -639,14 +686,17 @@ int usb_serial_probe(struct usb_interface *interface, int num_ports = 0; int max_endpoints; + lock_kernel(); /* guard against unloading a serial driver module */ type = search_serial_device(interface); if (!type) { + unlock_kernel(); dbg("none matched"); return -ENODEV; } serial = create_serial (dev, interface, type); if (!serial) { + unlock_kernel(); dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } @@ -656,16 +706,18 @@ int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id; if (!try_module_get(type->driver.owner)) { + unlock_kernel(); dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); 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); if (retval) { + unlock_kernel(); dbg ("sub driver rejected device"); kfree (serial); return retval; @@ -735,6 +787,7 @@ int usb_serial_probe(struct usb_interface *interface, * properly during a later invocation of usb_serial_probe */ if (num_bulk_in == 0 || num_bulk_out == 0) { + unlock_kernel(); dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); kfree (serial); return -ENODEV; @@ -750,6 +803,7 @@ int usb_serial_probe(struct usb_interface *interface, if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; if (num_ports == 0) { + unlock_kernel(); dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n"); kfree (serial); return -EIO; @@ -760,6 +814,7 @@ int usb_serial_probe(struct usb_interface *interface, /* if this device type has a calc_num_ports function, call it */ if (type->calc_num_ports) { if (!try_module_get(type->driver.owner)) { + unlock_kernel(); dev_err(&interface->dev, "module get failed, exiting\n"); kfree (serial); return -EIO; @@ -771,12 +826,6 @@ int usb_serial_probe(struct usb_interface *interface, num_ports = type->num_ports; } - if (get_free_serial (serial, num_ports, &minor) == NULL) { - dev_err(&interface->dev, "No more free serial devices\n"); - kfree (serial); - return -ENOMEM; - } - serial->minor = minor; serial->num_ports = num_ports; serial->num_bulk_in = num_bulk_in; @@ -791,6 +840,8 @@ int usb_serial_probe(struct usb_interface *interface, max_endpoints = max(max_endpoints, num_interrupt_out); max_endpoints = max(max_endpoints, (int)serial->num_ports); serial->num_port_pointers = max_endpoints; + unlock_kernel(); + dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints); for (i = 0; i < max_endpoints; ++i) { port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); @@ -925,6 +976,11 @@ int usb_serial_probe(struct usb_interface *interface, } } + if (get_free_serial (serial, num_ports, &minor) == NULL) { + dev_err(&interface->dev, "No more free serial devices\n"); + goto probe_error; + } + /* register all of the individual ports with the driver core */ for (i = 0; i < num_ports; ++i) { port = serial->port[i]; @@ -1002,8 +1058,11 @@ void usb_serial_disconnect(struct usb_interface *interface) if (serial) { for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; - if (port && port->tty) - tty_hangup(port->tty); + if (port) { + if (port->tty) + tty_hangup(port->tty); + kill_traffic(port); + } } /* let the last holder of this object * cause it to be cleaned up */ @@ -1040,6 +1099,7 @@ static int __init usb_serial_init(void) return -ENOMEM; /* Initialize our global data */ + spin_lock_init(&table_lock); for (i = 0; i < SERIAL_TTY_MINORS; ++i) { serial_table[i] = NULL; } @@ -1138,7 +1198,7 @@ static void fixup_generic(struct usb_serial_driver *device) set_to_generic_if_null(device, shutdown); } -int usb_serial_register(struct usb_serial_driver *driver) +int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */ { int retval; @@ -1162,7 +1222,7 @@ int usb_serial_register(struct usb_serial_driver *driver) } -void usb_serial_deregister(struct usb_serial_driver *device) +void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */ { info("USB Serial deregistering driver %s", device->description); list_del(&device->driver_list); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index b09f06096056..2f59ff226e2c 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -90,8 +90,6 @@ static struct usb_device_id id_table [] = { .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID), @@ -151,7 +149,6 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, @@ -189,6 +186,7 @@ static struct usb_serial_driver handspring_device = { .name = "visor", }, .description = "Handspring Visor / Palm OS", + .usb_driver = &visor_driver, .id_table = id_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 2, @@ -219,6 +217,7 @@ static struct usb_serial_driver clie_5_device = { .name = "clie_5", }, .description = "Sony Clie 5.0", + .usb_driver = &visor_driver, .id_table = clie_id_5_table, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = 2, @@ -249,6 +248,7 @@ static struct usb_serial_driver clie_3_5_device = { .name = "clie_3.5", }, .description = "Sony Clie 3.5", + .usb_driver = &visor_driver, .id_table = clie_id_3_5_table, .num_interrupt_in = 0, .num_bulk_in = 1, diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h index 765118d83fb6..4ce6f62a6f39 100644 --- a/drivers/usb/serial/visor.h +++ b/drivers/usb/serial/visor.h @@ -32,7 +32,6 @@ #define PALM_TUNGSTEN_T_ID 0x0060 #define PALM_TREO_650 0x0061 #define PALM_TUNGSTEN_Z_ID 0x0031 -#define PALM_ZIRE31_ID 0x0061 #define PALM_ZIRE_ID 0x0070 #define PALM_M100_ID 0x0080 diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 5483d8564c1b..bf16e9e1d84e 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -161,6 +161,7 @@ static struct usb_serial_driver whiteheat_fake_device = { .name = "whiteheatnofirm", }, .description = "Connect Tech - WhiteHEAT - (prerenumeration)", + .usb_driver = &whiteheat_driver, .id_table = id_table_prerenumeration, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, @@ -176,6 +177,7 @@ static struct usb_serial_driver whiteheat_device = { .name = "whiteheat", }, .description = "Connect Tech - WhiteHEAT", + .usb_driver = &whiteheat_driver, .id_table = id_table_std, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, 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/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index e1072d52d641..70234f5dbeeb 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -110,23 +110,6 @@ static int slave_configure(struct scsi_device *sdev) * the end, scatter-gather buffers follow page boundaries. */ blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); - /* Set the SCSI level to at least 2. We'll leave it at 3 if that's - * what is originally reported. We need this to avoid confusing - * the SCSI layer with devices that report 0 or 1, but need 10-byte - * commands (ala ATAPI devices behind certain bridges, or devices - * which simply have broken INQUIRY data). - * - * NOTE: This means /dev/sg programs (ala cdrecord) will get the - * actual information. This seems to be the preference for - * programs like that. - * - * NOTE: This also means that /proc/scsi/scsi and sysfs may report - * the actual value or the modified one, depending on where the - * data comes from. - */ - if (sdev->scsi_level < SCSI_2) - sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2; - /* Many devices have trouble transfering more than 32KB at a time, * while others have trouble with more than 64K. At this time we * are limiting both to 32K (64 sectores). @@ -176,7 +159,9 @@ static int slave_configure(struct scsi_device *sdev) * a Get-Max-LUN request, we won't lose much by setting the * revision level down to 2. The only devices that would be * affected are those with sparse LUNs. */ - sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2; + if (sdev->scsi_level > SCSI_2) + sdev->sdev_target->scsi_level = + sdev->scsi_level = SCSI_2; /* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable * Hardware Error) when any low-level error occurs, @@ -194,6 +179,16 @@ static int slave_configure(struct scsi_device *sdev) sdev->use_10_for_ms = 1; } + /* The CB and CBI transports have no way to pass LUN values + * other than the bits in the second byte of a CDB. But those + * bits don't get set to the LUN value if the device reports + * scsi_level == 0 (UNKNOWN). Hence such devices must necessarily + * be single-LUN. + */ + if ((us->protocol == US_PR_CB || us->protocol == US_PR_CBI) && + sdev->scsi_level == SCSI_UNKNOWN) + us->max_lun = 0; + /* Some devices choke when they receive a PREVENT-ALLOW MEDIUM * REMOVAL command, so suppress those commands. */ if (us->flags & US_FL_NOT_LOCKABLE) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index b49f2a78189e..f49a62fc32d2 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -573,7 +573,7 @@ UNUSUAL_DEV( 0x054c, 0x002b, 0x0100, 0x0110, #endif /* Submitted by Olaf Hering, SuSE Bugzilla #49049 */ -UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x0501, +UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x2000, "Sony", "USB Floppy Drive", US_SC_DEVICE, US_PR_DEVICE, NULL, @@ -1325,13 +1325,6 @@ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), -/* Reported by Jan Mate */ -UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, - "Sony Ericsson", - "P990i", - US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - /* Reported by Kevin Cernekee * Tested on hardware version 1.10. * Entry is needed only for the initializer function override. diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 70644506651f..7e7ec29782f1 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -731,26 +731,27 @@ static int get_pipes(struct us_data *us) struct usb_endpoint_descriptor *ep_int = NULL; /* - * Find the endpoints we need. + * Find the first endpoint of each type we need. * We are expecting a minimum of 2 endpoints - in and out (bulk). - * An optional interrupt is OK (necessary for CBI protocol). + * An optional interrupt-in is OK (necessary for CBI protocol). * We will ignore any others. */ for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { ep = &altsetting->endpoint[i].desc; - /* Is it a BULK endpoint? */ if (usb_endpoint_xfer_bulk(ep)) { - /* BULK in or out? */ - if (usb_endpoint_dir_in(ep)) - ep_in = ep; - else - ep_out = ep; + if (usb_endpoint_dir_in(ep)) { + if (!ep_in) + ep_in = ep; + } else { + if (!ep_out) + ep_out = ep; + } } - /* Is it an interrupt endpoint? */ - else if (usb_endpoint_xfer_int(ep)) { - ep_int = ep; + else if (usb_endpoint_is_int_in(ep)) { + if (!ep_int) + ep_int = ep; } } diff --git a/drivers/video/output.c b/drivers/video/output.c new file mode 100644 index 000000000000..1473f2c892d2 --- /dev/null +++ b/drivers/video/output.c @@ -0,0 +1,129 @@ +/* + * output.c - Display Output Switch driver + * + * 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. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#include +#include +#include +#include + + +MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Luming Yu "); + +static ssize_t video_output_show_state(struct class_device *dev,char *buf) +{ + ssize_t ret_size = 0; + struct output_device *od = to_output_device(dev); + if (od->props) + ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od)); + return ret_size; +} + +static ssize_t video_output_store_state(struct class_device *dev, + const char *buf,size_t count) +{ + char *endp; + struct output_device *od = to_output_device(dev); + int request_state = simple_strtoul(buf,&endp,0); + size_t size = endp - buf; + + if (*endp && isspace(*endp)) + size++; + if (size != count) + return -EINVAL; + + if (od->props) { + od->request_state = request_state; + od->props->set_state(od); + } + return count; +} + +static void video_output_class_release(struct class_device *dev) +{ + struct output_device *od = to_output_device(dev); + kfree(od); +} + +static struct class_device_attribute video_output_attributes[] = { + __ATTR(state, 0644, video_output_show_state, video_output_store_state), + __ATTR_NULL, +}; + +static struct class video_output_class = { + .name = "video_output", + .release = video_output_class_release, + .class_dev_attrs = video_output_attributes, +}; + +struct output_device *video_output_register(const char *name, + struct device *dev, + void *devdata, + struct output_properties *op) +{ + struct output_device *new_dev; + int ret_code = 0; + + new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL); + if (!new_dev) { + ret_code = -ENOMEM; + goto error_return; + } + new_dev->props = op; + new_dev->class_dev.class = &video_output_class; + new_dev->class_dev.dev = dev; + strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN); + class_set_devdata(&new_dev->class_dev,devdata); + ret_code = class_device_register(&new_dev->class_dev); + if (ret_code) { + kfree(new_dev); + goto error_return; + } + return new_dev; + +error_return: + return ERR_PTR(ret_code); +} +EXPORT_SYMBOL(video_output_register); + +void video_output_unregister(struct output_device *dev) +{ + if (!dev) + return; + class_device_unregister(&dev->class_dev); +} +EXPORT_SYMBOL(video_output_unregister); + +static void __exit video_output_class_exit(void) +{ + class_unregister(&video_output_class); +} + +static int __init video_output_class_init(void) +{ + return class_register(&video_output_class); +} + +postcore_initcall(video_output_class_init); +module_exit(video_output_class_exit); diff --git a/fs/Kconfig b/fs/Kconfig index 8cd2417a14db..5e8e9d9ccb33 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -426,7 +426,6 @@ config OCFS2_FS select CONFIGFS_FS select JBD select CRC32 - select INET help OCFS2 is a general purpose extent based shared disk cluster file system with many similarities to ext3. It supports 64 bit inode diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index d04d2f7448d9..85e3850bf2c9 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,6 +1,8 @@ Version 1.47 ------------ Fix oops in list_del during mount caused by unaligned string. +Seek to SEEK_END forces check for update of file size for non-cached +files. Version 1.46 ------------ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 10c90294cd18..93ef09971d2f 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -511,7 +511,15 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) { /* origin == SEEK_END => we must revalidate the cached file length */ if (origin == SEEK_END) { - int retval = cifs_revalidate(file->f_path.dentry); + int retval; + + /* some applications poll for the file length in this strange + way so we must seek to end on non-oplocked files by + setting the revalidate time to zero */ + if(file->f_path.dentry->d_inode) + CIFS_I(file->f_path.dentry->d_inode)->time = 0; + + retval = cifs_revalidate(file->f_path.dentry); if (retval < 0) return (loff_t)retval; } diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 8a49b2e77d37..e9dcf5ee29a2 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1146,7 +1146,7 @@ static int cifs_writepages(struct address_space *mapping, pgoff_t end; pgoff_t index; int range_whole = 0; - struct kvec iov[32]; + struct kvec * iov; int len; int n_iov = 0; pgoff_t next; @@ -1171,15 +1171,21 @@ static int cifs_writepages(struct address_space *mapping, if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) if(cifs_sb->tcon->ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - if(!experimEnabled) + if(!experimEnabled) return generic_writepages(mapping, wbc); + iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL); + if(iov == NULL) + return generic_writepages(mapping, wbc); + + /* * BB: Is this meaningful for a non-block-device file system? * If it is, we should test it again after we do I/O */ if (wbc->nonblocking && bdi_write_congested(bdi)) { wbc->encountered_congestion = 1; + kfree(iov); return 0; } @@ -1345,7 +1351,7 @@ retry: mapping->writeback_index = index; FreeXid(xid); - + kfree(iov); return rc; } diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 99dfb5337e31..782940be550f 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -156,9 +156,9 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, tmp_inode->i_atime = cnvrtDosUnixTm( le16_to_cpu(pfindData->LastAccessDate), le16_to_cpu(pfindData->LastAccessTime)); - tmp_inode->i_ctime = cnvrtDosUnixTm( - le16_to_cpu(pfindData->LastWriteDate), - le16_to_cpu(pfindData->LastWriteTime)); + tmp_inode->i_ctime = cnvrtDosUnixTm( + le16_to_cpu(pfindData->LastWriteDate), + le16_to_cpu(pfindData->LastWriteTime)); AdjustForTZ(cifs_sb->tcon, tmp_inode); attr = le16_to_cpu(pfindData->Attributes); allocation_size = le32_to_cpu(pfindData->AllocationSize); diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c index 7a1b2b961ec8..1b1daf63f062 100644 --- a/fs/cifs/smbdes.c +++ b/fs/cifs/smbdes.c @@ -196,7 +196,7 @@ dohash(char *out, char *in, char *key, int forw) char c[28]; char d[28]; char *cd; - char ki[16][48]; + char (*ki)[48]; char *pd1; char l[32], r[32]; char *rl; @@ -206,6 +206,12 @@ dohash(char *out, char *in, char *key, int forw) if(pk1 == NULL) return; + ki = kmalloc(16*48, GFP_KERNEL); + if(ki == NULL) { + kfree(pk1); + return; + } + cd = pk1 + 56; pd1= cd + 56; rl = pd1 + 64; @@ -243,6 +249,7 @@ dohash(char *out, char *in, char *key, int forw) er = kmalloc(48+48+32+32+32, GFP_KERNEL); if(er == NULL) { kfree(pk1); + kfree(ki); return; } erk = er+48; @@ -290,6 +297,7 @@ dohash(char *out, char *in, char *key, int forw) permute(out, rl, perm6, 64); kfree(pk1); + kfree(ki); } static void diff --git a/fs/configfs/file.c b/fs/configfs/file.c index 2a7cb086e80c..d98be5e01328 100644 --- a/fs/configfs/file.c +++ b/fs/configfs/file.c @@ -162,14 +162,17 @@ fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size int error; if (!buffer->page) - buffer->page = (char *)get_zeroed_page(GFP_KERNEL); + buffer->page = (char *)__get_free_pages(GFP_KERNEL, 0); if (!buffer->page) return -ENOMEM; - if (count > PAGE_SIZE) - count = PAGE_SIZE; + if (count >= PAGE_SIZE) + count = PAGE_SIZE - 1; error = copy_from_user(buffer->page,buf,count); buffer->needs_read_fill = 1; + /* if buf is assumed to contain a string, terminate it by \0, + * so e.g. sscanf() can scan the string easily */ + buffer->page[count] = 0; return error ? -EFAULT : count; } diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig index b5654a284fef..6fa7b0d5c043 100644 --- a/fs/dlm/Kconfig +++ b/fs/dlm/Kconfig @@ -3,21 +3,21 @@ menu "Distributed Lock Manager" config DLM tristate "Distributed Lock Manager (DLM)" - depends on IPV6 || IPV6=n + depends on SYSFS && (IPV6 || IPV6=n) select CONFIGFS_FS select IP_SCTP if DLM_SCTP help - A general purpose distributed lock manager for kernel or userspace - applications. + A general purpose distributed lock manager for kernel or userspace + applications. choice prompt "Select DLM communications protocol" depends on DLM default DLM_TCP help - The DLM Can use TCP or SCTP for it's network communications. - SCTP supports multi-homed operations whereas TCP doesn't. - However, SCTP seems to have stability problems at the moment. + The DLM Can use TCP or SCTP for it's network communications. + SCTP supports multi-homed operations whereas TCP doesn't. + However, SCTP seems to have stability problems at the moment. config DLM_TCP bool "TCP/IP" @@ -31,8 +31,8 @@ config DLM_DEBUG bool "DLM debugging" depends on DLM help - Under the debugfs mount point, the name of each lockspace will - appear as a file in the "dlm" directory. The output is the - list of resource and locks the local node knows about. + Under the debugfs mount point, the name of each lockspace will + appear as a file in the "dlm" directory. The output is the + list of resource and locks the local node knows about. endmenu diff --git a/fs/dlm/config.c b/fs/dlm/config.c index 88553054bbfa..8665c88e5af2 100644 --- a/fs/dlm/config.c +++ b/fs/dlm/config.c @@ -54,6 +54,11 @@ static struct config_item *make_node(struct config_group *, const char *); static void drop_node(struct config_group *, struct config_item *); static void release_node(struct config_item *); +static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a, + char *buf); +static ssize_t store_cluster(struct config_item *i, + struct configfs_attribute *a, + const char *buf, size_t len); static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a, char *buf); static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a, @@ -73,6 +78,101 @@ static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len); static ssize_t node_weight_read(struct node *nd, char *buf); static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len); +struct cluster { + struct config_group group; + unsigned int cl_tcp_port; + unsigned int cl_buffer_size; + unsigned int cl_rsbtbl_size; + unsigned int cl_lkbtbl_size; + unsigned int cl_dirtbl_size; + unsigned int cl_recover_timer; + unsigned int cl_toss_secs; + unsigned int cl_scan_secs; + unsigned int cl_log_debug; +}; + +enum { + CLUSTER_ATTR_TCP_PORT = 0, + CLUSTER_ATTR_BUFFER_SIZE, + CLUSTER_ATTR_RSBTBL_SIZE, + CLUSTER_ATTR_LKBTBL_SIZE, + CLUSTER_ATTR_DIRTBL_SIZE, + CLUSTER_ATTR_RECOVER_TIMER, + CLUSTER_ATTR_TOSS_SECS, + CLUSTER_ATTR_SCAN_SECS, + CLUSTER_ATTR_LOG_DEBUG, +}; + +struct cluster_attribute { + struct configfs_attribute attr; + ssize_t (*show)(struct cluster *, char *); + ssize_t (*store)(struct cluster *, const char *, size_t); +}; + +static ssize_t cluster_set(struct cluster *cl, unsigned int *cl_field, + unsigned int *info_field, int check_zero, + const char *buf, size_t len) +{ + unsigned int x; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + x = simple_strtoul(buf, NULL, 0); + + if (check_zero && !x) + return -EINVAL; + + *cl_field = x; + *info_field = x; + + return len; +} + +#define __CONFIGFS_ATTR(_name,_mode,_read,_write) { \ + .attr = { .ca_name = __stringify(_name), \ + .ca_mode = _mode, \ + .ca_owner = THIS_MODULE }, \ + .show = _read, \ + .store = _write, \ +} + +#define CLUSTER_ATTR(name, check_zero) \ +static ssize_t name##_write(struct cluster *cl, const char *buf, size_t len) \ +{ \ + return cluster_set(cl, &cl->cl_##name, &dlm_config.ci_##name, \ + check_zero, buf, len); \ +} \ +static ssize_t name##_read(struct cluster *cl, char *buf) \ +{ \ + return snprintf(buf, PAGE_SIZE, "%u\n", cl->cl_##name); \ +} \ +static struct cluster_attribute cluster_attr_##name = \ +__CONFIGFS_ATTR(name, 0644, name##_read, name##_write) + +CLUSTER_ATTR(tcp_port, 1); +CLUSTER_ATTR(buffer_size, 1); +CLUSTER_ATTR(rsbtbl_size, 1); +CLUSTER_ATTR(lkbtbl_size, 1); +CLUSTER_ATTR(dirtbl_size, 1); +CLUSTER_ATTR(recover_timer, 1); +CLUSTER_ATTR(toss_secs, 1); +CLUSTER_ATTR(scan_secs, 1); +CLUSTER_ATTR(log_debug, 0); + +static struct configfs_attribute *cluster_attrs[] = { + [CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr, + [CLUSTER_ATTR_BUFFER_SIZE] = &cluster_attr_buffer_size.attr, + [CLUSTER_ATTR_RSBTBL_SIZE] = &cluster_attr_rsbtbl_size.attr, + [CLUSTER_ATTR_LKBTBL_SIZE] = &cluster_attr_lkbtbl_size.attr, + [CLUSTER_ATTR_DIRTBL_SIZE] = &cluster_attr_dirtbl_size.attr, + [CLUSTER_ATTR_RECOVER_TIMER] = &cluster_attr_recover_timer.attr, + [CLUSTER_ATTR_TOSS_SECS] = &cluster_attr_toss_secs.attr, + [CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs.attr, + [CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr, + NULL, +}; + enum { COMM_ATTR_NODEID = 0, COMM_ATTR_LOCAL, @@ -152,10 +252,6 @@ struct clusters { struct configfs_subsystem subsys; }; -struct cluster { - struct config_group group; -}; - struct spaces { struct config_group ss_group; }; @@ -197,6 +293,8 @@ static struct configfs_group_operations clusters_ops = { static struct configfs_item_operations cluster_ops = { .release = release_cluster, + .show_attribute = show_cluster, + .store_attribute = store_cluster, }; static struct configfs_group_operations spaces_ops = { @@ -237,6 +335,7 @@ static struct config_item_type clusters_type = { static struct config_item_type cluster_type = { .ct_item_ops = &cluster_ops, + .ct_attrs = cluster_attrs, .ct_owner = THIS_MODULE, }; @@ -317,6 +416,16 @@ static struct config_group *make_cluster(struct config_group *g, cl->group.default_groups[1] = &cms->cs_group; cl->group.default_groups[2] = NULL; + cl->cl_tcp_port = dlm_config.ci_tcp_port; + cl->cl_buffer_size = dlm_config.ci_buffer_size; + cl->cl_rsbtbl_size = dlm_config.ci_rsbtbl_size; + cl->cl_lkbtbl_size = dlm_config.ci_lkbtbl_size; + cl->cl_dirtbl_size = dlm_config.ci_dirtbl_size; + cl->cl_recover_timer = dlm_config.ci_recover_timer; + cl->cl_toss_secs = dlm_config.ci_toss_secs; + cl->cl_scan_secs = dlm_config.ci_scan_secs; + cl->cl_log_debug = dlm_config.ci_log_debug; + space_list = &sps->ss_group; comm_list = &cms->cs_group; return &cl->group; @@ -509,6 +618,25 @@ void dlm_config_exit(void) * Functions for user space to read/write attributes */ +static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a, + char *buf) +{ + struct cluster *cl = to_cluster(i); + struct cluster_attribute *cla = + container_of(a, struct cluster_attribute, attr); + return cla->show ? cla->show(cl, buf) : 0; +} + +static ssize_t store_cluster(struct config_item *i, + struct configfs_attribute *a, + const char *buf, size_t len) +{ + struct cluster *cl = to_cluster(i); + struct cluster_attribute *cla = + container_of(a, struct cluster_attribute, attr); + return cla->store ? cla->store(cl, buf, len) : -EINVAL; +} + static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a, char *buf) { @@ -775,15 +903,17 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num) #define DEFAULT_RECOVER_TIMER 5 #define DEFAULT_TOSS_SECS 10 #define DEFAULT_SCAN_SECS 5 +#define DEFAULT_LOG_DEBUG 0 struct dlm_config_info dlm_config = { - .tcp_port = DEFAULT_TCP_PORT, - .buffer_size = DEFAULT_BUFFER_SIZE, - .rsbtbl_size = DEFAULT_RSBTBL_SIZE, - .lkbtbl_size = DEFAULT_LKBTBL_SIZE, - .dirtbl_size = DEFAULT_DIRTBL_SIZE, - .recover_timer = DEFAULT_RECOVER_TIMER, - .toss_secs = DEFAULT_TOSS_SECS, - .scan_secs = DEFAULT_SCAN_SECS + .ci_tcp_port = DEFAULT_TCP_PORT, + .ci_buffer_size = DEFAULT_BUFFER_SIZE, + .ci_rsbtbl_size = DEFAULT_RSBTBL_SIZE, + .ci_lkbtbl_size = DEFAULT_LKBTBL_SIZE, + .ci_dirtbl_size = DEFAULT_DIRTBL_SIZE, + .ci_recover_timer = DEFAULT_RECOVER_TIMER, + .ci_toss_secs = DEFAULT_TOSS_SECS, + .ci_scan_secs = DEFAULT_SCAN_SECS, + .ci_log_debug = DEFAULT_LOG_DEBUG }; diff --git a/fs/dlm/config.h b/fs/dlm/config.h index 9da7839958a9..1e978611a96e 100644 --- a/fs/dlm/config.h +++ b/fs/dlm/config.h @@ -17,14 +17,15 @@ #define DLM_MAX_ADDR_COUNT 3 struct dlm_config_info { - int tcp_port; - int buffer_size; - int rsbtbl_size; - int lkbtbl_size; - int dirtbl_size; - int recover_timer; - int toss_secs; - int scan_secs; + int ci_tcp_port; + int ci_buffer_size; + int ci_rsbtbl_size; + int ci_lkbtbl_size; + int ci_dirtbl_size; + int ci_recover_timer; + int ci_toss_secs; + int ci_scan_secs; + int ci_log_debug; }; extern struct dlm_config_info dlm_config; diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 1ee8195e6fc0..61d93201e1b2 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h @@ -41,6 +41,7 @@ #include #include +#include "config.h" #define DLM_LOCKSPACE_LEN 64 @@ -69,12 +70,12 @@ struct dlm_mhandle; #define log_error(ls, fmt, args...) \ printk(KERN_ERR "dlm: %s: " fmt "\n", (ls)->ls_name , ##args) -#define DLM_LOG_DEBUG -#ifdef DLM_LOG_DEBUG -#define log_debug(ls, fmt, args...) log_error(ls, fmt, ##args) -#else -#define log_debug(ls, fmt, args...) -#endif +#define log_debug(ls, fmt, args...) \ +do { \ + if (dlm_config.ci_log_debug) \ + printk(KERN_DEBUG "dlm: %s: " fmt "\n", \ + (ls)->ls_name , ##args); \ +} while (0) #define DLM_ASSERT(x, do) \ { \ @@ -309,8 +310,8 @@ static inline int rsb_flag(struct dlm_rsb *r, enum rsb_flags flag) /* dlm_header is first element of all structs sent between nodes */ -#define DLM_HEADER_MAJOR 0x00020000 -#define DLM_HEADER_MINOR 0x00000001 +#define DLM_HEADER_MAJOR 0x00030000 +#define DLM_HEADER_MINOR 0x00000000 #define DLM_MSG 1 #define DLM_RCOM 2 @@ -386,6 +387,8 @@ struct dlm_rcom { uint32_t rc_type; /* DLM_RCOM_ */ int rc_result; /* multi-purpose */ uint64_t rc_id; /* match reply with request */ + uint64_t rc_seq; /* sender's ls_recover_seq */ + uint64_t rc_seq_reply; /* remote ls_recover_seq */ char rc_buf[0]; }; @@ -523,6 +526,7 @@ struct dlm_user_proc { spinlock_t asts_spin; struct list_head locks; spinlock_t locks_spin; + struct list_head unlocking; wait_queue_head_t wait; }; diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 30878defaeb6..e725005fafd0 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -754,6 +754,11 @@ static void add_to_waiters(struct dlm_lkb *lkb, int mstype) mutex_unlock(&ls->ls_waiters_mutex); } +/* We clear the RESEND flag because we might be taking an lkb off the waiters + list as part of process_requestqueue (e.g. a lookup that has an optimized + request reply on the requestqueue) between dlm_recover_waiters_pre() which + set RESEND and dlm_recover_waiters_post() */ + static int _remove_from_waiters(struct dlm_lkb *lkb) { int error = 0; @@ -764,6 +769,7 @@ static int _remove_from_waiters(struct dlm_lkb *lkb) goto out; } lkb->lkb_wait_type = 0; + lkb->lkb_flags &= ~DLM_IFL_RESEND; list_del(&lkb->lkb_wait_reply); unhold_lkb(lkb); out: @@ -810,7 +816,7 @@ static int shrink_bucket(struct dlm_ls *ls, int b) list_for_each_entry_reverse(r, &ls->ls_rsbtbl[b].toss, res_hashchain) { if (!time_after_eq(jiffies, r->res_toss_time + - dlm_config.toss_secs * HZ)) + dlm_config.ci_toss_secs * HZ)) continue; found = 1; break; @@ -2144,12 +2150,24 @@ static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb, if (lkb->lkb_astaddr) ms->m_asts |= AST_COMP; - if (ms->m_type == DLM_MSG_REQUEST || ms->m_type == DLM_MSG_LOOKUP) + /* compare with switch in create_message; send_remove() doesn't + use send_args() */ + + switch (ms->m_type) { + case DLM_MSG_REQUEST: + case DLM_MSG_LOOKUP: memcpy(ms->m_extra, r->res_name, r->res_length); - - else if (lkb->lkb_lvbptr) + break; + case DLM_MSG_CONVERT: + case DLM_MSG_UNLOCK: + case DLM_MSG_REQUEST_REPLY: + case DLM_MSG_CONVERT_REPLY: + case DLM_MSG_GRANT: + if (!lkb->lkb_lvbptr) + break; memcpy(ms->m_extra, lkb->lkb_lvbptr, r->res_ls->ls_lvblen); - + break; + } } static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype) @@ -2418,8 +2436,12 @@ static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb, DLM_ASSERT(is_master_copy(lkb), dlm_print_lkb(lkb);); - if (receive_lvb(ls, lkb, ms)) - return -ENOMEM; + if (lkb->lkb_exflags & DLM_LKF_VALBLK) { + /* lkb was just created so there won't be an lvb yet */ + lkb->lkb_lvbptr = allocate_lvb(ls); + if (!lkb->lkb_lvbptr) + return -ENOMEM; + } return 0; } @@ -3002,7 +3024,7 @@ int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery) { struct dlm_message *ms = (struct dlm_message *) hd; struct dlm_ls *ls; - int error; + int error = 0; if (!recovery) dlm_message_in(ms); @@ -3119,7 +3141,7 @@ int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery) out: dlm_put_lockspace(ls); dlm_astd_wake(); - return 0; + return error; } @@ -3132,6 +3154,7 @@ static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb) if (middle_conversion(lkb)) { hold_lkb(lkb); ls->ls_stub_ms.m_result = -EINPROGRESS; + ls->ls_stub_ms.m_flags = lkb->lkb_flags; _remove_from_waiters(lkb); _receive_convert_reply(lkb, &ls->ls_stub_ms); @@ -3205,6 +3228,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls) case DLM_MSG_UNLOCK: hold_lkb(lkb); ls->ls_stub_ms.m_result = -DLM_EUNLOCK; + ls->ls_stub_ms.m_flags = lkb->lkb_flags; _remove_from_waiters(lkb); _receive_unlock_reply(lkb, &ls->ls_stub_ms); dlm_put_lkb(lkb); @@ -3213,6 +3237,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls) case DLM_MSG_CANCEL: hold_lkb(lkb); ls->ls_stub_ms.m_result = -DLM_ECANCEL; + ls->ls_stub_ms.m_flags = lkb->lkb_flags; _remove_from_waiters(lkb); _receive_cancel_reply(lkb, &ls->ls_stub_ms); dlm_put_lkb(lkb); @@ -3571,6 +3596,14 @@ int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc) lock_rsb(r); switch (error) { + case -EBADR: + /* There's a chance the new master received our lock before + dlm_recover_master_reply(), this wouldn't happen if we did + a barrier between recover_masters and recover_locks. */ + log_debug(ls, "master copy not ready %x r %lx %s", lkb->lkb_id, + (unsigned long)r, r->res_name); + dlm_send_rcom_lock(r, lkb); + goto out; case -EEXIST: log_debug(ls, "master copy exists %x", lkb->lkb_id); /* fall through */ @@ -3585,7 +3618,7 @@ int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc) /* an ack for dlm_recover_locks() which waits for replies from all the locks it sends to new masters */ dlm_recovered_lock(r); - + out: unlock_rsb(r); put_rsb(r); dlm_put_lkb(lkb); @@ -3610,7 +3643,7 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, } if (flags & DLM_LKF_VALBLK) { - ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL); + ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_KERNEL); if (!ua->lksb.sb_lvbptr) { kfree(ua); __put_lkb(ls, lkb); @@ -3679,7 +3712,7 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, ua = (struct dlm_user_args *)lkb->lkb_astparam; if (flags & DLM_LKF_VALBLK && !ua->lksb.sb_lvbptr) { - ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL); + ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_KERNEL); if (!ua->lksb.sb_lvbptr) { error = -ENOMEM; goto out_put; @@ -3745,12 +3778,10 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, goto out_put; spin_lock(&ua->proc->locks_spin); - list_del_init(&lkb->lkb_ownqueue); + /* dlm_user_add_ast() may have already taken lkb off the proc list */ + if (!list_empty(&lkb->lkb_ownqueue)) + list_move(&lkb->lkb_ownqueue, &ua->proc->unlocking); spin_unlock(&ua->proc->locks_spin); - - /* this removes the reference for the proc->locks list added by - dlm_user_request */ - unhold_lkb(lkb); out_put: dlm_put_lkb(lkb); out: @@ -3790,9 +3821,8 @@ int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp, /* this lkb was removed from the WAITING queue */ if (lkb->lkb_grmode == DLM_LOCK_IV) { spin_lock(&ua->proc->locks_spin); - list_del_init(&lkb->lkb_ownqueue); + list_move(&lkb->lkb_ownqueue, &ua->proc->unlocking); spin_unlock(&ua->proc->locks_spin); - unhold_lkb(lkb); } out_put: dlm_put_lkb(lkb); @@ -3853,11 +3883,6 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc) mutex_lock(&ls->ls_clear_proc_locks); list_for_each_entry_safe(lkb, safe, &proc->locks, lkb_ownqueue) { - if (lkb->lkb_ast_type) { - list_del(&lkb->lkb_astqueue); - unhold_lkb(lkb); - } - list_del_init(&lkb->lkb_ownqueue); if (lkb->lkb_exflags & DLM_LKF_PERSISTENT) { @@ -3874,6 +3899,20 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc) dlm_put_lkb(lkb); } + + /* in-progress unlocks */ + list_for_each_entry_safe(lkb, safe, &proc->unlocking, lkb_ownqueue) { + list_del_init(&lkb->lkb_ownqueue); + lkb->lkb_flags |= DLM_IFL_DEAD; + dlm_put_lkb(lkb); + } + + list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) { + list_del(&lkb->lkb_astqueue); + dlm_put_lkb(lkb); + } + mutex_unlock(&ls->ls_clear_proc_locks); unlock_recovery(ls); } + diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 59012b089e8d..f40817b53c6f 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -236,7 +236,7 @@ static int dlm_scand(void *data) while (!kthread_should_stop()) { list_for_each_entry(ls, &lslist, ls_list) dlm_scan_rsbs(ls); - schedule_timeout_interruptible(dlm_config.scan_secs * HZ); + schedule_timeout_interruptible(dlm_config.ci_scan_secs * HZ); } return 0; } @@ -422,7 +422,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ls->ls_count = 0; ls->ls_flags = 0; - size = dlm_config.rsbtbl_size; + size = dlm_config.ci_rsbtbl_size; ls->ls_rsbtbl_size = size; ls->ls_rsbtbl = kmalloc(sizeof(struct dlm_rsbtable) * size, GFP_KERNEL); @@ -434,7 +434,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, rwlock_init(&ls->ls_rsbtbl[i].lock); } - size = dlm_config.lkbtbl_size; + size = dlm_config.ci_lkbtbl_size; ls->ls_lkbtbl_size = size; ls->ls_lkbtbl = kmalloc(sizeof(struct dlm_lkbtable) * size, GFP_KERNEL); @@ -446,7 +446,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, ls->ls_lkbtbl[i].counter = 1; } - size = dlm_config.dirtbl_size; + size = dlm_config.ci_dirtbl_size; ls->ls_dirtbl_size = size; ls->ls_dirtbl = kmalloc(sizeof(struct dlm_dirtable) * size, GFP_KERNEL); @@ -489,7 +489,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace, mutex_init(&ls->ls_requestqueue_mutex); mutex_init(&ls->ls_clear_proc_locks); - ls->ls_recover_buf = kmalloc(dlm_config.buffer_size, GFP_KERNEL); + ls->ls_recover_buf = kmalloc(dlm_config.ci_buffer_size, GFP_KERNEL); if (!ls->ls_recover_buf) goto out_dirfree; diff --git a/fs/dlm/lowcomms-sctp.c b/fs/dlm/lowcomms-sctp.c index fe158d7a9285..dc83a9d979b5 100644 --- a/fs/dlm/lowcomms-sctp.c +++ b/fs/dlm/lowcomms-sctp.c @@ -72,6 +72,8 @@ struct nodeinfo { struct list_head writequeue; /* outgoing writequeue_entries */ spinlock_t writequeue_lock; int nodeid; + struct work_struct swork; /* Send workqueue */ + struct work_struct lwork; /* Locking workqueue */ }; static DEFINE_IDR(nodeinfo_idr); @@ -96,6 +98,7 @@ struct connection { atomic_t waiting_requests; struct cbuf cb; int eagain_flag; + struct work_struct work; /* Send workqueue */ }; /* An entry waiting to be sent */ @@ -137,19 +140,23 @@ static void cbuf_eat(struct cbuf *cb, int n) static LIST_HEAD(write_nodes); static DEFINE_SPINLOCK(write_nodes_lock); + /* Maximum number of incoming messages to process before * doing a schedule() */ #define MAX_RX_MSG_COUNT 25 -/* Manage daemons */ -static struct task_struct *recv_task; -static struct task_struct *send_task; -static DECLARE_WAIT_QUEUE_HEAD(lowcomms_recv_wait); +/* Work queues */ +static struct workqueue_struct *recv_workqueue; +static struct workqueue_struct *send_workqueue; +static struct workqueue_struct *lock_workqueue; /* The SCTP connection */ static struct connection sctp_con; +static void process_send_sockets(struct work_struct *work); +static void process_recv_sockets(struct work_struct *work); +static void process_lock_request(struct work_struct *work); static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr) { @@ -222,6 +229,8 @@ static struct nodeinfo *nodeid2nodeinfo(int nodeid, gfp_t alloc) spin_lock_init(&ni->lock); INIT_LIST_HEAD(&ni->writequeue); spin_lock_init(&ni->writequeue_lock); + INIT_WORK(&ni->lwork, process_lock_request); + INIT_WORK(&ni->swork, process_send_sockets); ni->nodeid = nodeid; if (nodeid > max_nodeid) @@ -249,11 +258,8 @@ static struct nodeinfo *assoc2nodeinfo(sctp_assoc_t assoc) /* Data or notification available on socket */ static void lowcomms_data_ready(struct sock *sk, int count_unused) { - atomic_inc(&sctp_con.waiting_requests); if (test_and_set_bit(CF_READ_PENDING, &sctp_con.flags)) - return; - - wake_up_interruptible(&lowcomms_recv_wait); + queue_work(recv_workqueue, &sctp_con.work); } @@ -361,10 +367,10 @@ static void init_failed(void) spin_lock_bh(&write_nodes_lock); list_add_tail(&ni->write_list, &write_nodes); spin_unlock_bh(&write_nodes_lock); + queue_work(send_workqueue, &ni->swork); } } } - wake_up_process(send_task); } /* Something happened to an association */ @@ -446,8 +452,8 @@ static void process_sctp_notification(struct msghdr *msg, char *buf) spin_lock_bh(&write_nodes_lock); list_add_tail(&ni->write_list, &write_nodes); spin_unlock_bh(&write_nodes_lock); + queue_work(send_workqueue, &ni->swork); } - wake_up_process(send_task); } break; @@ -580,8 +586,8 @@ static int receive_from_sock(void) spin_lock_bh(&write_nodes_lock); list_add_tail(&ni->write_list, &write_nodes); spin_unlock_bh(&write_nodes_lock); + queue_work(send_workqueue, &ni->swork); } - wake_up_process(send_task); } } @@ -590,6 +596,7 @@ static int receive_from_sock(void) return 0; cbuf_add(&sctp_con.cb, ret); + // PJC: TODO: Add to node's workqueue....can we ?? ret = dlm_process_incoming_buffer(cpu_to_le32(sinfo->sinfo_ppid), page_address(sctp_con.rx_page), sctp_con.cb.base, sctp_con.cb.len, @@ -635,7 +642,7 @@ static int add_bind_addr(struct sockaddr_storage *addr, int addr_len, int num) if (result < 0) log_print("Can't bind to port %d addr number %d", - dlm_config.tcp_port, num); + dlm_config.ci_tcp_port, num); return result; } @@ -711,7 +718,7 @@ static int init_sock(void) /* Bind to all interfaces. */ for (i = 0; i < dlm_local_count; i++) { memcpy(&localaddr, dlm_local_addr[i], sizeof(localaddr)); - make_sockaddr(&localaddr, dlm_config.tcp_port, &addr_len); + make_sockaddr(&localaddr, dlm_config.ci_tcp_port, &addr_len); result = add_bind_addr(&localaddr, addr_len, num); if (result) @@ -820,7 +827,8 @@ void dlm_lowcomms_commit_buffer(void *arg) spin_lock_bh(&write_nodes_lock); list_add_tail(&ni->write_list, &write_nodes); spin_unlock_bh(&write_nodes_lock); - wake_up_process(send_task); + + queue_work(send_workqueue, &ni->swork); } return; @@ -863,7 +871,7 @@ static void initiate_association(int nodeid) return; } - make_sockaddr(&rem_addr, dlm_config.tcp_port, &addrlen); + make_sockaddr(&rem_addr, dlm_config.ci_tcp_port, &addrlen); outmessage.msg_name = &rem_addr; outmessage.msg_namelen = addrlen; @@ -1088,101 +1096,75 @@ int dlm_lowcomms_close(int nodeid) return 0; } -static int write_list_empty(void) +// PJC: The work queue function for receiving. +static void process_recv_sockets(struct work_struct *work) { - int status; - - spin_lock_bh(&write_nodes_lock); - status = list_empty(&write_nodes); - spin_unlock_bh(&write_nodes_lock); - - return status; -} - -static int dlm_recvd(void *data) -{ - DECLARE_WAITQUEUE(wait, current); - - while (!kthread_should_stop()) { + if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) { + int ret; int count = 0; - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&lowcomms_recv_wait, &wait); - if (!test_bit(CF_READ_PENDING, &sctp_con.flags)) - cond_resched(); - remove_wait_queue(&lowcomms_recv_wait, &wait); - set_current_state(TASK_RUNNING); + do { + ret = receive_from_sock(); - if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) { - int ret; - - do { - ret = receive_from_sock(); - - /* Don't starve out everyone else */ - if (++count >= MAX_RX_MSG_COUNT) { - cond_resched(); - count = 0; - } - } while (!kthread_should_stop() && ret >=0); - } - cond_resched(); + /* Don't starve out everyone else */ + if (++count >= MAX_RX_MSG_COUNT) { + cond_resched(); + count = 0; + } + } while (!kthread_should_stop() && ret >=0); } - - return 0; + cond_resched(); } -static int dlm_sendd(void *data) +// PJC: the work queue function for sending +static void process_send_sockets(struct work_struct *work) { - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(sctp_con.sock->sk->sk_sleep, &wait); - - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - if (write_list_empty()) - cond_resched(); - set_current_state(TASK_RUNNING); - - if (sctp_con.eagain_flag) { - sctp_con.eagain_flag = 0; - refill_write_queue(); - } - process_output_queue(); + if (sctp_con.eagain_flag) { + sctp_con.eagain_flag = 0; + refill_write_queue(); } + process_output_queue(); +} - remove_wait_queue(sctp_con.sock->sk->sk_sleep, &wait); - - return 0; +// PJC: Process lock requests from a particular node. +// TODO: can we optimise this out on UP ?? +static void process_lock_request(struct work_struct *work) +{ } static void daemons_stop(void) { - kthread_stop(recv_task); - kthread_stop(send_task); + destroy_workqueue(recv_workqueue); + destroy_workqueue(send_workqueue); + destroy_workqueue(lock_workqueue); } static int daemons_start(void) { - struct task_struct *p; int error; - - p = kthread_run(dlm_recvd, NULL, "dlm_recvd"); - error = IS_ERR(p); + recv_workqueue = create_workqueue("dlm_recv"); + error = IS_ERR(recv_workqueue); if (error) { - log_print("can't start dlm_recvd %d", error); + log_print("can't start dlm_recv %d", error); return error; } - recv_task = p; - p = kthread_run(dlm_sendd, NULL, "dlm_sendd"); - error = IS_ERR(p); + send_workqueue = create_singlethread_workqueue("dlm_send"); + error = IS_ERR(send_workqueue); if (error) { - log_print("can't start dlm_sendd %d", error); - kthread_stop(recv_task); + log_print("can't start dlm_send %d", error); + destroy_workqueue(recv_workqueue); + return error; + } + + lock_workqueue = create_workqueue("dlm_rlock"); + error = IS_ERR(lock_workqueue); + if (error) { + log_print("can't start dlm_rlock %d", error); + destroy_workqueue(send_workqueue); + destroy_workqueue(recv_workqueue); return error; } - send_task = p; return 0; } @@ -1194,6 +1176,8 @@ int dlm_lowcomms_start(void) { int error; + INIT_WORK(&sctp_con.work, process_recv_sockets); + error = init_sock(); if (error) goto fail_sock; @@ -1224,4 +1208,3 @@ void dlm_lowcomms_stop(void) for (i = 0; i < dlm_local_count; i++) kfree(dlm_local_addr[i]); } - diff --git a/fs/dlm/lowcomms-tcp.c b/fs/dlm/lowcomms-tcp.c index 9be3a440c42a..f1efd17b2614 100644 --- a/fs/dlm/lowcomms-tcp.c +++ b/fs/dlm/lowcomms-tcp.c @@ -2,7 +2,7 @@ ******************************************************************************* ** ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. +** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. ** ** This copyrighted material is made available to anyone wishing to use, ** modify, copy, or redistribute it subject to the terms and conditions @@ -96,10 +96,7 @@ static bool cbuf_empty(struct cbuf *cb) struct connection { struct socket *sock; /* NULL if not connected */ uint32_t nodeid; /* So we know who we are in the list */ - struct rw_semaphore sock_sem; /* Stop connect races */ - struct list_head read_list; /* On this list when ready for reading */ - struct list_head write_list; /* On this list when ready for writing */ - struct list_head state_list; /* On this list when ready to connect */ + struct mutex sock_mutex; unsigned long flags; /* bit 1,2 = We are on the read/write lists */ #define CF_READ_PENDING 1 #define CF_WRITE_PENDING 2 @@ -112,9 +109,10 @@ struct connection { struct page *rx_page; struct cbuf cb; int retries; - atomic_t waiting_requests; #define MAX_CONNECT_RETRIES 3 struct connection *othercon; + struct work_struct rwork; /* Receive workqueue */ + struct work_struct swork; /* Send workqueue */ }; #define sock2con(x) ((struct connection *)(x)->sk_user_data) @@ -131,14 +129,9 @@ struct writequeue_entry { static struct sockaddr_storage dlm_local_addr; -/* Manage daemons */ -static struct task_struct *recv_task; -static struct task_struct *send_task; - -static wait_queue_t lowcomms_send_waitq_head; -static DECLARE_WAIT_QUEUE_HEAD(lowcomms_send_waitq); -static wait_queue_t lowcomms_recv_waitq_head; -static DECLARE_WAIT_QUEUE_HEAD(lowcomms_recv_waitq); +/* Work queues */ +static struct workqueue_struct *recv_workqueue; +static struct workqueue_struct *send_workqueue; /* An array of pointers to connections, indexed by NODEID */ static struct connection **connections; @@ -146,17 +139,8 @@ static DECLARE_MUTEX(connections_lock); static struct kmem_cache *con_cache; static int conn_array_size; -/* List of sockets that have reads pending */ -static LIST_HEAD(read_sockets); -static DEFINE_SPINLOCK(read_sockets_lock); - -/* List of sockets which have writes pending */ -static LIST_HEAD(write_sockets); -static DEFINE_SPINLOCK(write_sockets_lock); - -/* List of sockets which have connects pending */ -static LIST_HEAD(state_sockets); -static DEFINE_SPINLOCK(state_sockets_lock); +static void process_recv_sockets(struct work_struct *work); +static void process_send_sockets(struct work_struct *work); static struct connection *nodeid2con(int nodeid, gfp_t allocation) { @@ -186,9 +170,11 @@ static struct connection *nodeid2con(int nodeid, gfp_t allocation) goto finish; con->nodeid = nodeid; - init_rwsem(&con->sock_sem); + mutex_init(&con->sock_mutex); INIT_LIST_HEAD(&con->writequeue); spin_lock_init(&con->writequeue_lock); + INIT_WORK(&con->swork, process_send_sockets); + INIT_WORK(&con->rwork, process_recv_sockets); connections[nodeid] = con; } @@ -203,41 +189,22 @@ static void lowcomms_data_ready(struct sock *sk, int count_unused) { struct connection *con = sock2con(sk); - atomic_inc(&con->waiting_requests); - if (test_and_set_bit(CF_READ_PENDING, &con->flags)) - return; - - spin_lock_bh(&read_sockets_lock); - list_add_tail(&con->read_list, &read_sockets); - spin_unlock_bh(&read_sockets_lock); - - wake_up_interruptible(&lowcomms_recv_waitq); + if (!test_and_set_bit(CF_READ_PENDING, &con->flags)) + queue_work(recv_workqueue, &con->rwork); } static void lowcomms_write_space(struct sock *sk) { struct connection *con = sock2con(sk); - if (test_and_set_bit(CF_WRITE_PENDING, &con->flags)) - return; - - spin_lock_bh(&write_sockets_lock); - list_add_tail(&con->write_list, &write_sockets); - spin_unlock_bh(&write_sockets_lock); - - wake_up_interruptible(&lowcomms_send_waitq); + if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) + queue_work(send_workqueue, &con->swork); } static inline void lowcomms_connect_sock(struct connection *con) { - if (test_and_set_bit(CF_CONNECT_PENDING, &con->flags)) - return; - - spin_lock_bh(&state_sockets_lock); - list_add_tail(&con->state_list, &state_sockets); - spin_unlock_bh(&state_sockets_lock); - - wake_up_interruptible(&lowcomms_send_waitq); + if (!test_and_set_bit(CF_CONNECT_PENDING, &con->flags)) + queue_work(send_workqueue, &con->swork); } static void lowcomms_state_change(struct sock *sk) @@ -279,7 +246,7 @@ static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port, /* Close a remote connection and tidy up */ static void close_connection(struct connection *con, bool and_other) { - down_write(&con->sock_sem); + mutex_lock(&con->sock_mutex); if (con->sock) { sock_release(con->sock); @@ -294,7 +261,7 @@ static void close_connection(struct connection *con, bool and_other) con->rx_page = NULL; } con->retries = 0; - up_write(&con->sock_sem); + mutex_unlock(&con->sock_mutex); } /* Data received from remote end */ @@ -308,10 +275,13 @@ static int receive_from_sock(struct connection *con) int r; int call_again_soon = 0; - down_read(&con->sock_sem); + mutex_lock(&con->sock_mutex); + + if (con->sock == NULL) { + ret = -EAGAIN; + goto out_close; + } - if (con->sock == NULL) - goto out; if (con->rx_page == NULL) { /* * This doesn't need to be atomic, but I think it should @@ -359,6 +329,9 @@ static int receive_from_sock(struct connection *con) if (ret <= 0) goto out_close; + if (ret == -EAGAIN) + goto out_resched; + if (ret == len) call_again_soon = 1; cbuf_add(&con->cb, ret); @@ -381,24 +354,26 @@ static int receive_from_sock(struct connection *con) con->rx_page = NULL; } -out: if (call_again_soon) goto out_resched; - up_read(&con->sock_sem); + mutex_unlock(&con->sock_mutex); return 0; out_resched: - lowcomms_data_ready(con->sock->sk, 0); - up_read(&con->sock_sem); - cond_resched(); - return 0; + if (!test_and_set_bit(CF_READ_PENDING, &con->flags)) + queue_work(recv_workqueue, &con->rwork); + mutex_unlock(&con->sock_mutex); + return -EAGAIN; out_close: - up_read(&con->sock_sem); + mutex_unlock(&con->sock_mutex); if (ret != -EAGAIN && !test_bit(CF_IS_OTHERCON, &con->flags)) { close_connection(con, false); /* Reconnect when there is something to send */ } + /* Don't return success if we really got EOF */ + if (ret == 0) + ret = -EAGAIN; return ret; } @@ -412,6 +387,7 @@ static int accept_from_sock(struct connection *con) int len; int nodeid; struct connection *newcon; + struct connection *addcon; memset(&peeraddr, 0, sizeof(peeraddr)); result = sock_create_kern(dlm_local_addr.ss_family, SOCK_STREAM, @@ -419,7 +395,7 @@ static int accept_from_sock(struct connection *con) if (result < 0) return -ENOMEM; - down_read(&con->sock_sem); + mutex_lock_nested(&con->sock_mutex, 0); result = -ENOTCONN; if (con->sock == NULL) @@ -445,7 +421,7 @@ static int accept_from_sock(struct connection *con) if (dlm_addr_to_nodeid(&peeraddr, &nodeid)) { printk("dlm: connect from non cluster node\n"); sock_release(newsock); - up_read(&con->sock_sem); + mutex_unlock(&con->sock_mutex); return -1; } @@ -462,7 +438,7 @@ static int accept_from_sock(struct connection *con) result = -ENOMEM; goto accept_err; } - down_write(&newcon->sock_sem); + mutex_lock_nested(&newcon->sock_mutex, 1); if (newcon->sock) { struct connection *othercon = newcon->othercon; @@ -470,41 +446,45 @@ static int accept_from_sock(struct connection *con) othercon = kmem_cache_zalloc(con_cache, GFP_KERNEL); if (!othercon) { printk("dlm: failed to allocate incoming socket\n"); - up_write(&newcon->sock_sem); + mutex_unlock(&newcon->sock_mutex); result = -ENOMEM; goto accept_err; } othercon->nodeid = nodeid; othercon->rx_action = receive_from_sock; - init_rwsem(&othercon->sock_sem); + mutex_init(&othercon->sock_mutex); + INIT_WORK(&othercon->swork, process_send_sockets); + INIT_WORK(&othercon->rwork, process_recv_sockets); set_bit(CF_IS_OTHERCON, &othercon->flags); newcon->othercon = othercon; } othercon->sock = newsock; newsock->sk->sk_user_data = othercon; add_sock(newsock, othercon); + addcon = othercon; } else { newsock->sk->sk_user_data = newcon; newcon->rx_action = receive_from_sock; add_sock(newsock, newcon); - + addcon = newcon; } - up_write(&newcon->sock_sem); + mutex_unlock(&newcon->sock_mutex); /* * Add it to the active queue in case we got data * beween processing the accept adding the socket * to the read_sockets list */ - lowcomms_data_ready(newsock->sk, 0); - up_read(&con->sock_sem); + if (!test_and_set_bit(CF_READ_PENDING, &addcon->flags)) + queue_work(recv_workqueue, &addcon->rwork); + mutex_unlock(&con->sock_mutex); return 0; accept_err: - up_read(&con->sock_sem); + mutex_unlock(&con->sock_mutex); sock_release(newsock); if (result != -EAGAIN) @@ -525,7 +505,7 @@ static void connect_to_sock(struct connection *con) return; } - down_write(&con->sock_sem); + mutex_lock(&con->sock_mutex); if (con->retries++ > MAX_CONNECT_RETRIES) goto out; @@ -548,7 +528,7 @@ static void connect_to_sock(struct connection *con) sock->sk->sk_user_data = con; con->rx_action = receive_from_sock; - make_sockaddr(&saddr, dlm_config.tcp_port, &addr_len); + make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len); add_sock(sock, con); @@ -577,7 +557,7 @@ out_err: result = 0; } out: - up_write(&con->sock_sem); + mutex_unlock(&con->sock_mutex); return; } @@ -616,10 +596,10 @@ static struct socket *create_listen_sock(struct connection *con, con->sock = sock; /* Bind to our port */ - make_sockaddr(saddr, dlm_config.tcp_port, &addr_len); + make_sockaddr(saddr, dlm_config.ci_tcp_port, &addr_len); result = sock->ops->bind(sock, (struct sockaddr *) saddr, addr_len); if (result < 0) { - printk("dlm: Can't bind to port %d\n", dlm_config.tcp_port); + printk("dlm: Can't bind to port %d\n", dlm_config.ci_tcp_port); sock_release(sock); sock = NULL; con->sock = NULL; @@ -638,7 +618,7 @@ static struct socket *create_listen_sock(struct connection *con, result = sock->ops->listen(sock, 5); if (result < 0) { - printk("dlm: Can't listen on port %d\n", dlm_config.tcp_port); + printk("dlm: Can't listen on port %d\n", dlm_config.ci_tcp_port); sock_release(sock); sock = NULL; goto create_out; @@ -709,6 +689,7 @@ void *dlm_lowcomms_get_buffer(int nodeid, int len, if (!con) return NULL; + spin_lock(&con->writequeue_lock); e = list_entry(con->writequeue.prev, struct writequeue_entry, list); if ((&e->list == &con->writequeue) || (PAGE_CACHE_SIZE - e->end < len)) { @@ -747,6 +728,7 @@ void dlm_lowcomms_commit_buffer(void *mh) struct connection *con = e->con; int users; + spin_lock(&con->writequeue_lock); users = --e->users; if (users) goto out; @@ -754,12 +736,8 @@ void dlm_lowcomms_commit_buffer(void *mh) kunmap(e->page); spin_unlock(&con->writequeue_lock); - if (test_and_set_bit(CF_WRITE_PENDING, &con->flags) == 0) { - spin_lock_bh(&write_sockets_lock); - list_add_tail(&con->write_list, &write_sockets); - spin_unlock_bh(&write_sockets_lock); - - wake_up_interruptible(&lowcomms_send_waitq); + if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) { + queue_work(send_workqueue, &con->swork); } return; @@ -783,7 +761,7 @@ static void send_to_sock(struct connection *con) struct writequeue_entry *e; int len, offset; - down_read(&con->sock_sem); + mutex_lock(&con->sock_mutex); if (con->sock == NULL) goto out_connect; @@ -800,6 +778,7 @@ static void send_to_sock(struct connection *con) offset = e->offset; BUG_ON(len == 0 && e->users == 0); spin_unlock(&con->writequeue_lock); + kmap(e->page); ret = 0; if (len) { @@ -828,18 +807,18 @@ static void send_to_sock(struct connection *con) } spin_unlock(&con->writequeue_lock); out: - up_read(&con->sock_sem); + mutex_unlock(&con->sock_mutex); return; send_error: - up_read(&con->sock_sem); + mutex_unlock(&con->sock_mutex); close_connection(con, false); lowcomms_connect_sock(con); return; out_connect: - up_read(&con->sock_sem); - lowcomms_connect_sock(con); + mutex_unlock(&con->sock_mutex); + connect_to_sock(con); return; } @@ -872,7 +851,6 @@ int dlm_lowcomms_close(int nodeid) if (con) { clean_one_writequeue(con); close_connection(con, true); - atomic_set(&con->waiting_requests, 0); } return 0; @@ -880,102 +858,29 @@ out: return -1; } -/* API send message call, may queue the request */ -/* N.B. This is the old interface - use the new one for new calls */ -int lowcomms_send_message(int nodeid, char *buf, int len, gfp_t allocation) -{ - struct writequeue_entry *e; - char *b; - - e = dlm_lowcomms_get_buffer(nodeid, len, allocation, &b); - if (e) { - memcpy(b, buf, len); - dlm_lowcomms_commit_buffer(e); - return 0; - } - return -ENOBUFS; -} - /* Look for activity on active sockets */ -static void process_sockets(void) +static void process_recv_sockets(struct work_struct *work) { - struct list_head *list; - struct list_head *temp; - int count = 0; + struct connection *con = container_of(work, struct connection, rwork); + int err; - spin_lock_bh(&read_sockets_lock); - list_for_each_safe(list, temp, &read_sockets) { - - struct connection *con = - list_entry(list, struct connection, read_list); - list_del(&con->read_list); - clear_bit(CF_READ_PENDING, &con->flags); - - spin_unlock_bh(&read_sockets_lock); - - /* This can reach zero if we are processing requests - * as they come in. - */ - if (atomic_read(&con->waiting_requests) == 0) { - spin_lock_bh(&read_sockets_lock); - continue; - } - - do { - con->rx_action(con); - - /* Don't starve out everyone else */ - if (++count >= MAX_RX_MSG_COUNT) { - cond_resched(); - count = 0; - } - - } while (!atomic_dec_and_test(&con->waiting_requests) && - !kthread_should_stop()); - - spin_lock_bh(&read_sockets_lock); - } - spin_unlock_bh(&read_sockets_lock); + clear_bit(CF_READ_PENDING, &con->flags); + do { + err = con->rx_action(con); + } while (!err); } -/* Try to send any messages that are pending - */ -static void process_output_queue(void) + +static void process_send_sockets(struct work_struct *work) { - struct list_head *list; - struct list_head *temp; - - spin_lock_bh(&write_sockets_lock); - list_for_each_safe(list, temp, &write_sockets) { - struct connection *con = - list_entry(list, struct connection, write_list); - clear_bit(CF_WRITE_PENDING, &con->flags); - list_del(&con->write_list); - - spin_unlock_bh(&write_sockets_lock); - send_to_sock(con); - spin_lock_bh(&write_sockets_lock); - } - spin_unlock_bh(&write_sockets_lock); -} - -static void process_state_queue(void) -{ - struct list_head *list; - struct list_head *temp; - - spin_lock_bh(&state_sockets_lock); - list_for_each_safe(list, temp, &state_sockets) { - struct connection *con = - list_entry(list, struct connection, state_list); - list_del(&con->state_list); - clear_bit(CF_CONNECT_PENDING, &con->flags); - spin_unlock_bh(&state_sockets_lock); + struct connection *con = container_of(work, struct connection, swork); + if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) { connect_to_sock(con); - spin_lock_bh(&state_sockets_lock); } - spin_unlock_bh(&state_sockets_lock); + + clear_bit(CF_WRITE_PENDING, &con->flags); + send_to_sock(con); } @@ -992,109 +897,33 @@ static void clean_writequeues(void) } } -static int read_list_empty(void) +static void work_stop(void) { - int status; - - spin_lock_bh(&read_sockets_lock); - status = list_empty(&read_sockets); - spin_unlock_bh(&read_sockets_lock); - - return status; + destroy_workqueue(recv_workqueue); + destroy_workqueue(send_workqueue); } -/* DLM Transport comms receive daemon */ -static int dlm_recvd(void *data) +static int work_start(void) { - init_waitqueue_entry(&lowcomms_recv_waitq_head, current); - add_wait_queue(&lowcomms_recv_waitq, &lowcomms_recv_waitq_head); - - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - if (read_list_empty()) - cond_resched(); - set_current_state(TASK_RUNNING); - - process_sockets(); - } - - return 0; -} - -static int write_and_state_lists_empty(void) -{ - int status; - - spin_lock_bh(&write_sockets_lock); - status = list_empty(&write_sockets); - spin_unlock_bh(&write_sockets_lock); - - spin_lock_bh(&state_sockets_lock); - if (list_empty(&state_sockets) == 0) - status = 0; - spin_unlock_bh(&state_sockets_lock); - - return status; -} - -/* DLM Transport send daemon */ -static int dlm_sendd(void *data) -{ - init_waitqueue_entry(&lowcomms_send_waitq_head, current); - add_wait_queue(&lowcomms_send_waitq, &lowcomms_send_waitq_head); - - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - if (write_and_state_lists_empty()) - cond_resched(); - set_current_state(TASK_RUNNING); - - process_state_queue(); - process_output_queue(); - } - - return 0; -} - -static void daemons_stop(void) -{ - kthread_stop(recv_task); - kthread_stop(send_task); -} - -static int daemons_start(void) -{ - struct task_struct *p; int error; - - p = kthread_run(dlm_recvd, NULL, "dlm_recvd"); - error = IS_ERR(p); + recv_workqueue = create_workqueue("dlm_recv"); + error = IS_ERR(recv_workqueue); if (error) { - log_print("can't start dlm_recvd %d", error); + log_print("can't start dlm_recv %d", error); return error; } - recv_task = p; - p = kthread_run(dlm_sendd, NULL, "dlm_sendd"); - error = IS_ERR(p); + send_workqueue = create_singlethread_workqueue("dlm_send"); + error = IS_ERR(send_workqueue); if (error) { - log_print("can't start dlm_sendd %d", error); - kthread_stop(recv_task); + log_print("can't start dlm_send %d", error); + destroy_workqueue(recv_workqueue); return error; } - send_task = p; return 0; } -/* - * Return the largest buffer size we can cope with. - */ -int lowcomms_max_buffer_size(void) -{ - return PAGE_CACHE_SIZE; -} - void dlm_lowcomms_stop(void) { int i; @@ -1107,7 +936,7 @@ void dlm_lowcomms_stop(void) connections[i]->flags |= 0xFF; } - daemons_stop(); + work_stop(); clean_writequeues(); for (i = 0; i < conn_array_size; i++) { @@ -1159,7 +988,7 @@ int dlm_lowcomms_start(void) if (error) goto fail_unlisten; - error = daemons_start(); + error = work_start(); if (error) goto fail_unlisten; diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c index c9b1c3d535f4..a5126e0c68a6 100644 --- a/fs/dlm/midcomms.c +++ b/fs/dlm/midcomms.c @@ -82,7 +82,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base, if (msglen < sizeof(struct dlm_header)) break; err = -E2BIG; - if (msglen > dlm_config.buffer_size) { + if (msglen > dlm_config.ci_buffer_size) { log_print("message size %d from %d too big, buf len %d", msglen, nodeid, len); break; @@ -103,7 +103,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base, if (msglen > sizeof(__tmp) && msg == (struct dlm_header *) __tmp) { - msg = kmalloc(dlm_config.buffer_size, GFP_KERNEL); + msg = kmalloc(dlm_config.ci_buffer_size, GFP_KERNEL); if (msg == NULL) return ret; } diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c index 4cc31be9cd9d..6bfbd6153809 100644 --- a/fs/dlm/rcom.c +++ b/fs/dlm/rcom.c @@ -56,6 +56,10 @@ static int create_rcom(struct dlm_ls *ls, int to_nodeid, int type, int len, rc->rc_type = type; + spin_lock(&ls->ls_recover_lock); + rc->rc_seq = ls->ls_recover_seq; + spin_unlock(&ls->ls_recover_lock); + *mh_ret = mh; *rc_ret = rc; return 0; @@ -78,8 +82,17 @@ static void make_config(struct dlm_ls *ls, struct rcom_config *rf) rf->rf_lsflags = ls->ls_exflags; } -static int check_config(struct dlm_ls *ls, struct rcom_config *rf, int nodeid) +static int check_config(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid) { + struct rcom_config *rf = (struct rcom_config *) rc->rc_buf; + + if ((rc->rc_header.h_version & 0xFFFF0000) != DLM_HEADER_MAJOR) { + log_error(ls, "version mismatch: %x nodeid %d: %x", + DLM_HEADER_MAJOR | DLM_HEADER_MINOR, nodeid, + rc->rc_header.h_version); + return -EINVAL; + } + if (rf->rf_lvblen != ls->ls_lvblen || rf->rf_lsflags != ls->ls_exflags) { log_error(ls, "config mismatch: %d,%x nodeid %d: %d,%x", @@ -125,7 +138,7 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid) goto out; allow_sync_reply(ls, &rc->rc_id); - memset(ls->ls_recover_buf, 0, dlm_config.buffer_size); + memset(ls->ls_recover_buf, 0, dlm_config.ci_buffer_size); send_rcom(ls, mh, rc); @@ -141,8 +154,7 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid) log_debug(ls, "remote node %d not ready", nodeid); rc->rc_result = 0; } else - error = check_config(ls, (struct rcom_config *) rc->rc_buf, - nodeid); + error = check_config(ls, rc, nodeid); /* the caller looks at rc_result for the remote recovery status */ out: return error; @@ -159,6 +171,7 @@ static void receive_rcom_status(struct dlm_ls *ls, struct dlm_rcom *rc_in) if (error) return; rc->rc_id = rc_in->rc_id; + rc->rc_seq_reply = rc_in->rc_seq; rc->rc_result = dlm_recover_status(ls); make_config(ls, (struct rcom_config *) rc->rc_buf); @@ -200,7 +213,7 @@ int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len) if (nodeid == dlm_our_nodeid()) { dlm_copy_master_names(ls, last_name, last_len, ls->ls_recover_buf + len, - dlm_config.buffer_size - len, nodeid); + dlm_config.ci_buffer_size - len, nodeid); goto out; } @@ -210,7 +223,7 @@ int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len) memcpy(rc->rc_buf, last_name, last_len); allow_sync_reply(ls, &rc->rc_id); - memset(ls->ls_recover_buf, 0, dlm_config.buffer_size); + memset(ls->ls_recover_buf, 0, dlm_config.ci_buffer_size); send_rcom(ls, mh, rc); @@ -224,30 +237,17 @@ static void receive_rcom_names(struct dlm_ls *ls, struct dlm_rcom *rc_in) { struct dlm_rcom *rc; struct dlm_mhandle *mh; - int error, inlen, outlen; - int nodeid = rc_in->rc_header.h_nodeid; - uint32_t status = dlm_recover_status(ls); - - /* - * We can't run dlm_dir_rebuild_send (which uses ls_nodes) while - * dlm_recoverd is running ls_nodes_reconfig (which changes ls_nodes). - * It could only happen in rare cases where we get a late NAMES - * message from a previous instance of recovery. - */ - - if (!(status & DLM_RS_NODES)) { - log_debug(ls, "ignoring RCOM_NAMES from %u", nodeid); - return; - } + int error, inlen, outlen, nodeid; nodeid = rc_in->rc_header.h_nodeid; inlen = rc_in->rc_header.h_length - sizeof(struct dlm_rcom); - outlen = dlm_config.buffer_size - sizeof(struct dlm_rcom); + outlen = dlm_config.ci_buffer_size - sizeof(struct dlm_rcom); error = create_rcom(ls, nodeid, DLM_RCOM_NAMES_REPLY, outlen, &rc, &mh); if (error) return; rc->rc_id = rc_in->rc_id; + rc->rc_seq_reply = rc_in->rc_seq; dlm_copy_master_names(ls, rc_in->rc_buf, inlen, rc->rc_buf, outlen, nodeid); @@ -294,6 +294,7 @@ static void receive_rcom_lookup(struct dlm_ls *ls, struct dlm_rcom *rc_in) ret_nodeid = error; rc->rc_result = ret_nodeid; rc->rc_id = rc_in->rc_id; + rc->rc_seq_reply = rc_in->rc_seq; send_rcom(ls, mh, rc); } @@ -375,20 +376,13 @@ static void receive_rcom_lock(struct dlm_ls *ls, struct dlm_rcom *rc_in) memcpy(rc->rc_buf, rc_in->rc_buf, sizeof(struct rcom_lock)); rc->rc_id = rc_in->rc_id; + rc->rc_seq_reply = rc_in->rc_seq; send_rcom(ls, mh, rc); } static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in) { - uint32_t status = dlm_recover_status(ls); - - if (!(status & DLM_RS_DIR)) { - log_debug(ls, "ignoring RCOM_LOCK_REPLY from %u", - rc_in->rc_header.h_nodeid); - return; - } - dlm_recover_process_copy(ls, rc_in); } @@ -415,6 +409,7 @@ static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in) rc->rc_type = DLM_RCOM_STATUS_REPLY; rc->rc_id = rc_in->rc_id; + rc->rc_seq_reply = rc_in->rc_seq; rc->rc_result = -ESRCH; rf = (struct rcom_config *) rc->rc_buf; @@ -426,6 +421,31 @@ static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in) return 0; } +static int is_old_reply(struct dlm_ls *ls, struct dlm_rcom *rc) +{ + uint64_t seq; + int rv = 0; + + switch (rc->rc_type) { + case DLM_RCOM_STATUS_REPLY: + case DLM_RCOM_NAMES_REPLY: + case DLM_RCOM_LOOKUP_REPLY: + case DLM_RCOM_LOCK_REPLY: + spin_lock(&ls->ls_recover_lock); + seq = ls->ls_recover_seq; + spin_unlock(&ls->ls_recover_lock); + if (rc->rc_seq_reply != seq) { + log_debug(ls, "ignoring old reply %x from %d " + "seq_reply %llx expect %llx", + rc->rc_type, rc->rc_header.h_nodeid, + (unsigned long long)rc->rc_seq_reply, + (unsigned long long)seq); + rv = 1; + } + } + return rv; +} + /* Called by dlm_recvd; corresponds to dlm_receive_message() but special recovery-only comms are sent through here. */ @@ -449,11 +469,14 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid) } if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) { - log_error(ls, "ignoring recovery message %x from %d", + log_debug(ls, "ignoring recovery message %x from %d", rc->rc_type, nodeid); goto out; } + if (is_old_reply(ls, rc)) + goto out; + if (nodeid != rc->rc_header.h_nodeid) { log_error(ls, "bad rcom nodeid %d from %d", rc->rc_header.h_nodeid, nodeid); diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c index cf9f6831bab5..c2cc7694cd16 100644 --- a/fs/dlm/recover.c +++ b/fs/dlm/recover.c @@ -44,7 +44,7 @@ static void dlm_wait_timer_fn(unsigned long data) { struct dlm_ls *ls = (struct dlm_ls *) data; - mod_timer(&ls->ls_timer, jiffies + (dlm_config.recover_timer * HZ)); + mod_timer(&ls->ls_timer, jiffies + (dlm_config.ci_recover_timer * HZ)); wake_up(&ls->ls_wait_general); } @@ -55,7 +55,7 @@ int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls)) init_timer(&ls->ls_timer); ls->ls_timer.function = dlm_wait_timer_fn; ls->ls_timer.data = (long) ls; - ls->ls_timer.expires = jiffies + (dlm_config.recover_timer * HZ); + ls->ls_timer.expires = jiffies + (dlm_config.ci_recover_timer * HZ); add_timer(&ls->ls_timer); wait_event(ls->ls_wait_general, testfn(ls) || dlm_recovery_stopped(ls)); @@ -397,7 +397,9 @@ int dlm_recover_masters(struct dlm_ls *ls) if (dlm_no_directory(ls)) count += recover_master_static(r); - else if (!is_master(r) && dlm_is_removed(ls, r->res_nodeid)) { + else if (!is_master(r) && + (dlm_is_removed(ls, r->res_nodeid) || + rsb_flag(r, RSB_NEW_MASTER))) { recover_master(r); count++; } diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c index 650536aa5139..3cb636d60249 100644 --- a/fs/dlm/recoverd.c +++ b/fs/dlm/recoverd.c @@ -77,7 +77,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) error = dlm_recover_members(ls, rv, &neg); if (error) { - log_error(ls, "recover_members failed %d", error); + log_debug(ls, "recover_members failed %d", error); goto fail; } start = jiffies; @@ -89,7 +89,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) error = dlm_recover_directory(ls); if (error) { - log_error(ls, "recover_directory failed %d", error); + log_debug(ls, "recover_directory failed %d", error); goto fail; } @@ -99,7 +99,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) error = dlm_recover_directory_wait(ls); if (error) { - log_error(ls, "recover_directory_wait failed %d", error); + log_debug(ls, "recover_directory_wait failed %d", error); goto fail; } @@ -129,7 +129,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) error = dlm_recover_masters(ls); if (error) { - log_error(ls, "recover_masters failed %d", error); + log_debug(ls, "recover_masters failed %d", error); goto fail; } @@ -139,13 +139,13 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) error = dlm_recover_locks(ls); if (error) { - log_error(ls, "recover_locks failed %d", error); + log_debug(ls, "recover_locks failed %d", error); goto fail; } error = dlm_recover_locks_wait(ls); if (error) { - log_error(ls, "recover_locks_wait failed %d", error); + log_debug(ls, "recover_locks_wait failed %d", error); goto fail; } @@ -166,7 +166,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) error = dlm_recover_locks_wait(ls); if (error) { - log_error(ls, "recover_locks_wait failed %d", error); + log_debug(ls, "recover_locks_wait failed %d", error); goto fail; } } @@ -184,7 +184,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) dlm_set_recover_status(ls, DLM_RS_DONE); error = dlm_recover_done_wait(ls); if (error) { - log_error(ls, "recover_done_wait failed %d", error); + log_debug(ls, "recover_done_wait failed %d", error); goto fail; } @@ -192,19 +192,19 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv) error = enable_locking(ls, rv->seq); if (error) { - log_error(ls, "enable_locking failed %d", error); + log_debug(ls, "enable_locking failed %d", error); goto fail; } error = dlm_process_requestqueue(ls); if (error) { - log_error(ls, "process_requestqueue failed %d", error); + log_debug(ls, "process_requestqueue failed %d", error); goto fail; } error = dlm_recover_waiters_post(ls); if (error) { - log_error(ls, "recover_waiters_post failed %d", error); + log_debug(ls, "recover_waiters_post failed %d", error); goto fail; } diff --git a/fs/dlm/user.c b/fs/dlm/user.c index c37e93e4f2df..d378b7fe2a1e 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -180,6 +180,14 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type) ua->lksb.sb_status == -EAGAIN && !list_empty(&lkb->lkb_ownqueue)) remove_ownqueue = 1; + /* unlocks or cancels of waiting requests need to be removed from the + proc's unlocking list, again there must be a better way... */ + + if (ua->lksb.sb_status == -DLM_EUNLOCK || + (ua->lksb.sb_status == -DLM_ECANCEL && + lkb->lkb_grmode == DLM_LOCK_IV)) + remove_ownqueue = 1; + /* We want to copy the lvb to userspace when the completion ast is read if the status is 0, the lock has an lvb and lvb_ops says we should. We could probably have set_lvb_lock() @@ -523,6 +531,7 @@ static int device_open(struct inode *inode, struct file *file) proc->lockspace = ls->ls_local_handle; INIT_LIST_HEAD(&proc->asts); INIT_LIST_HEAD(&proc->locks); + INIT_LIST_HEAD(&proc->unlocking); spin_lock_init(&proc->asts_spin); spin_lock_init(&proc->locks_spin); init_waitqueue_head(&proc->wait); diff --git a/fs/dlm/util.c b/fs/dlm/util.c index 767197db9944..963889cf6740 100644 --- a/fs/dlm/util.c +++ b/fs/dlm/util.c @@ -134,6 +134,8 @@ void dlm_rcom_out(struct dlm_rcom *rc) rc->rc_type = cpu_to_le32(rc->rc_type); rc->rc_result = cpu_to_le32(rc->rc_result); rc->rc_id = cpu_to_le64(rc->rc_id); + rc->rc_seq = cpu_to_le64(rc->rc_seq); + rc->rc_seq_reply = cpu_to_le64(rc->rc_seq_reply); if (type == DLM_RCOM_LOCK) rcom_lock_out((struct rcom_lock *) rc->rc_buf); @@ -151,6 +153,8 @@ void dlm_rcom_in(struct dlm_rcom *rc) rc->rc_type = le32_to_cpu(rc->rc_type); rc->rc_result = le32_to_cpu(rc->rc_result); rc->rc_id = le64_to_cpu(rc->rc_id); + rc->rc_seq = le64_to_cpu(rc->rc_seq); + rc->rc_seq_reply = le64_to_cpu(rc->rc_seq_reply); if (rc->rc_type == DLM_RCOM_LOCK) rcom_lock_in((struct rcom_lock *) rc->rc_buf); diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index 6a2ffa2db14f..de8e64c03f73 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig @@ -4,44 +4,43 @@ config GFS2_FS select FS_POSIX_ACL select CRC32 help - A cluster filesystem. + A cluster filesystem. - Allows a cluster of computers to simultaneously use a block device - that is shared between them (with FC, iSCSI, NBD, etc...). GFS reads - and writes to the block device like a local filesystem, but also uses - a lock module to allow the computers coordinate their I/O so - filesystem consistency is maintained. One of the nifty features of - GFS is perfect consistency -- changes made to the filesystem on one - machine show up immediately on all other machines in the cluster. + Allows a cluster of computers to simultaneously use a block device + that is shared between them (with FC, iSCSI, NBD, etc...). GFS reads + and writes to the block device like a local filesystem, but also uses + a lock module to allow the computers coordinate their I/O so + filesystem consistency is maintained. One of the nifty features of + GFS is perfect consistency -- changes made to the filesystem on one + machine show up immediately on all other machines in the cluster. - To use the GFS2 filesystem, you will need to enable one or more of - the below locking modules. Documentation and utilities for GFS2 can - be found here: http://sources.redhat.com/cluster + To use the GFS2 filesystem, you will need to enable one or more of + the below locking modules. Documentation and utilities for GFS2 can + be found here: http://sources.redhat.com/cluster config GFS2_FS_LOCKING_NOLOCK tristate "GFS2 \"nolock\" locking module" depends on GFS2_FS help - Single node locking module for GFS2. + Single node locking module for GFS2. - Use this module if you want to use GFS2 on a single node without - its clustering features. You can still take advantage of the - large file support, and upgrade to running a full cluster later on - if required. + Use this module if you want to use GFS2 on a single node without + its clustering features. You can still take advantage of the + large file support, and upgrade to running a full cluster later on + if required. - If you will only be using GFS2 in cluster mode, you do not need this - module. + If you will only be using GFS2 in cluster mode, you do not need this + module. config GFS2_FS_LOCKING_DLM tristate "GFS2 DLM locking module" - depends on GFS2_FS && NET && INET && (IPV6 || IPV6=n) + depends on GFS2_FS && SYSFS && NET && INET && (IPV6 || IPV6=n) select IP_SCTP if DLM_SCTP select CONFIGFS_FS select DLM help - Multiple node locking module for GFS2 - - Most users of GFS2 will require this module. It provides the locking - interface between GFS2 and the DLM, which is required to use GFS2 - in a cluster environment. + Multiple node locking module for GFS2 + Most users of GFS2 will require this module. It provides the locking + interface between GFS2 and the DLM, which is required to use GFS2 + in a cluster environment. diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 8240c1ff94f4..113f6c9110c7 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -773,7 +773,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, gfs2_free_data(ip, bstart, blen); } - ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC; gfs2_dinode_out(ip, dibh->b_data); @@ -848,7 +848,7 @@ static int do_grow(struct gfs2_inode *ip, u64 size) } ip->i_di.di_size = size; - ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC; error = gfs2_meta_inode_buffer(ip, &dibh); if (error) @@ -963,7 +963,7 @@ static int trunc_start(struct gfs2_inode *ip, u64 size) if (gfs2_is_stuffed(ip)) { ip->i_di.di_size = size; - ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size); @@ -975,7 +975,7 @@ static int trunc_start(struct gfs2_inode *ip, u64 size) if (!error) { ip->i_di.di_size = size; - ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC; ip->i_di.di_flags |= GFS2_DIF_TRUNC_IN_PROG; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); @@ -1048,7 +1048,7 @@ static int trunc_end(struct gfs2_inode *ip) ip->i_num.no_addr; gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); } - ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC; ip->i_di.di_flags &= ~GFS2_DIF_TRUNC_IN_PROG; gfs2_trans_add_bh(ip->i_gl, dibh, 1); diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 0fdcb7713cd9..c93ca8f361b5 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -131,7 +131,7 @@ static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf, memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size); if (ip->i_di.di_size < offset + size) ip->i_di.di_size = offset + size; - ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC; gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -229,7 +229,7 @@ out: if (ip->i_di.di_size < offset + copied) ip->i_di.di_size = offset + copied; - ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); @@ -1198,12 +1198,11 @@ static int compare_dents(const void *a, const void *b) */ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset, - void *opaque, gfs2_filldir_t filldir, + void *opaque, filldir_t filldir, const struct gfs2_dirent **darr, u32 entries, int *copied) { const struct gfs2_dirent *dent, *dent_next; - struct gfs2_inum_host inum; u64 off, off_next; unsigned int x, y; int run = 0; @@ -1240,11 +1239,9 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset, *offset = off; } - gfs2_inum_in(&inum, (char *)&dent->de_inum); - error = filldir(opaque, (const char *)(dent + 1), be16_to_cpu(dent->de_name_len), - off, &inum, + off, be64_to_cpu(dent->de_inum.no_addr), be16_to_cpu(dent->de_type)); if (error) return 1; @@ -1262,8 +1259,8 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset, } static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, - gfs2_filldir_t filldir, int *copied, - unsigned *depth, u64 leaf_no) + filldir_t filldir, int *copied, unsigned *depth, + u64 leaf_no) { struct gfs2_inode *ip = GFS2_I(inode); struct buffer_head *bh; @@ -1343,7 +1340,7 @@ out: */ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, - gfs2_filldir_t filldir) + filldir_t filldir) { struct gfs2_inode *dip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); @@ -1402,7 +1399,7 @@ out: } int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, - gfs2_filldir_t filldir) + filldir_t filldir) { struct gfs2_inode *dip = GFS2_I(inode); struct dirent_gather g; @@ -1568,7 +1565,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name, break; gfs2_trans_add_bh(ip->i_gl, bh, 1); ip->i_di.di_entries++; - ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC; gfs2_dinode_out(ip, bh->b_data); brelse(bh); error = 0; @@ -1654,7 +1651,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name) gfs2_consist_inode(dip); gfs2_trans_add_bh(dip->i_gl, bh, 1); dip->i_di.di_entries--; - dip->i_inode.i_mtime.tv_sec = dip->i_inode.i_ctime.tv_sec = get_seconds(); + dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME_SEC; gfs2_dinode_out(dip, bh->b_data); brelse(bh); mark_inode_dirty(&dip->i_inode); @@ -1702,7 +1699,7 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, gfs2_trans_add_bh(dip->i_gl, bh, 1); } - dip->i_inode.i_mtime.tv_sec = dip->i_inode.i_ctime.tv_sec = get_seconds(); + dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME_SEC; gfs2_dinode_out(dip, bh->b_data); brelse(bh); return 0; diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h index b21b33668a5b..48fe89046bba 100644 --- a/fs/gfs2/dir.h +++ b/fs/gfs2/dir.h @@ -16,30 +16,13 @@ struct inode; struct gfs2_inode; struct gfs2_inum; -/** - * gfs2_filldir_t - Report a directory entry to the caller of gfs2_dir_read() - * @opaque: opaque data used by the function - * @name: the name of the directory entry - * @length: the length of the name - * @offset: the entry's offset in the directory - * @inum: the inode number the entry points to - * @type: the type of inode the entry points to - * - * Returns: 0 on success, 1 if buffer full - */ - -typedef int (*gfs2_filldir_t) (void *opaque, - const char *name, unsigned int length, - u64 offset, - struct gfs2_inum_host *inum, unsigned int type); - int gfs2_dir_search(struct inode *dir, const struct qstr *filename, struct gfs2_inum_host *inum, unsigned int *type); int gfs2_dir_add(struct inode *inode, const struct qstr *filename, const struct gfs2_inum_host *inum, unsigned int type); int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename); -int gfs2_dir_read(struct inode *inode, u64 * offset, void *opaque, - gfs2_filldir_t filldir); +int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, + filldir_t filldir); int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, struct gfs2_inum_host *new_inum, unsigned int new_type); diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c index ebebbdcd7057..0c83c7f4dda8 100644 --- a/fs/gfs2/eattr.c +++ b/fs/gfs2/eattr.c @@ -301,7 +301,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { - ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_ctime = CURRENT_TIME_SEC; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -718,7 +718,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, (er->er_mode & S_IFMT)); ip->i_inode.i_mode = er->er_mode; } - ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_ctime = CURRENT_TIME_SEC; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -853,7 +853,7 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, (ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT)); ip->i_inode.i_mode = er->er_mode; } - ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_ctime = CURRENT_TIME_SEC; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -1134,7 +1134,7 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el) error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { - ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_ctime = CURRENT_TIME_SEC; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 438146904b58..6618c1190252 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include "gfs2.h" @@ -33,11 +35,6 @@ #include "super.h" #include "util.h" -struct greedy { - struct gfs2_holder gr_gh; - struct delayed_work gr_work; -}; - struct gfs2_gl_hash_bucket { struct hlist_head hb_list; }; @@ -47,6 +44,9 @@ typedef void (*glock_examiner) (struct gfs2_glock * gl); static int gfs2_dump_lockstate(struct gfs2_sbd *sdp); static int dump_glock(struct gfs2_glock *gl); static int dump_inode(struct gfs2_inode *ip); +static void gfs2_glock_xmote_th(struct gfs2_holder *gh); +static void gfs2_glock_drop_th(struct gfs2_glock *gl); +static DECLARE_RWSEM(gfs2_umount_flush_sem); #define GFS2_GL_HASH_SHIFT 15 #define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT) @@ -212,30 +212,6 @@ out: return rv; } -/** - * queue_empty - check to see if a glock's queue is empty - * @gl: the glock - * @head: the head of the queue to check - * - * This function protects the list in the event that a process already - * has a holder on the list and is adding a second holder for itself. - * The glmutex lock is what generally prevents processes from working - * on the same glock at once, but the special case of adding a second - * holder for yourself ("recursive" locking) doesn't involve locking - * glmutex, making the spin lock necessary. - * - * Returns: 1 if the queue is empty - */ - -static inline int queue_empty(struct gfs2_glock *gl, struct list_head *head) -{ - int empty; - spin_lock(&gl->gl_spin); - empty = list_empty(head); - spin_unlock(&gl->gl_spin); - return empty; -} - /** * search_bucket() - Find struct gfs2_glock by lock number * @bucket: the bucket to search @@ -395,11 +371,6 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, gh->gh_flags = flags; gh->gh_error = 0; gh->gh_iflags = 0; - init_completion(&gh->gh_wait); - - if (gh->gh_state == LM_ST_EXCLUSIVE) - gh->gh_flags |= GL_LOCAL_EXCL; - gfs2_glock_hold(gl); } @@ -417,9 +388,6 @@ void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder * { gh->gh_state = state; gh->gh_flags = flags; - if (gh->gh_state == LM_ST_EXCLUSIVE) - gh->gh_flags |= GL_LOCAL_EXCL; - gh->gh_iflags &= 1 << HIF_ALLOCED; gh->gh_ip = (unsigned long)__builtin_return_address(0); } @@ -479,6 +447,29 @@ static void gfs2_holder_put(struct gfs2_holder *gh) kfree(gh); } +static void gfs2_holder_dispose_or_wake(struct gfs2_holder *gh) +{ + if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) { + gfs2_holder_put(gh); + return; + } + clear_bit(HIF_WAIT, &gh->gh_iflags); + smp_mb(); + wake_up_bit(&gh->gh_iflags, HIF_WAIT); +} + +static int holder_wait(void *word) +{ + schedule(); + return 0; +} + +static void wait_on_holder(struct gfs2_holder *gh) +{ + might_sleep(); + wait_on_bit(&gh->gh_iflags, HIF_WAIT, holder_wait, TASK_UNINTERRUPTIBLE); +} + /** * rq_mutex - process a mutex request in the queue * @gh: the glock holder @@ -493,7 +484,9 @@ static int rq_mutex(struct gfs2_holder *gh) list_del_init(&gh->gh_list); /* gh->gh_error never examined. */ set_bit(GLF_LOCK, &gl->gl_flags); - complete(&gh->gh_wait); + clear_bit(HIF_WAIT, &gh->gh_iflags); + smp_mb(); + wake_up_bit(&gh->gh_iflags, HIF_WAIT); return 1; } @@ -511,7 +504,6 @@ static int rq_promote(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; struct gfs2_sbd *sdp = gl->gl_sbd; - const struct gfs2_glock_operations *glops = gl->gl_ops; if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) { if (list_empty(&gl->gl_holders)) { @@ -526,7 +518,7 @@ static int rq_promote(struct gfs2_holder *gh) gfs2_reclaim_glock(sdp); } - glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags); + gfs2_glock_xmote_th(gh); spin_lock(&gl->gl_spin); } return 1; @@ -537,11 +529,11 @@ static int rq_promote(struct gfs2_holder *gh) set_bit(GLF_LOCK, &gl->gl_flags); } else { struct gfs2_holder *next_gh; - if (gh->gh_flags & GL_LOCAL_EXCL) + if (gh->gh_state == LM_ST_EXCLUSIVE) return 1; next_gh = list_entry(gl->gl_holders.next, struct gfs2_holder, gh_list); - if (next_gh->gh_flags & GL_LOCAL_EXCL) + if (next_gh->gh_state == LM_ST_EXCLUSIVE) return 1; } @@ -549,7 +541,7 @@ static int rq_promote(struct gfs2_holder *gh) gh->gh_error = 0; set_bit(HIF_HOLDER, &gh->gh_iflags); - complete(&gh->gh_wait); + gfs2_holder_dispose_or_wake(gh); return 0; } @@ -564,7 +556,6 @@ static int rq_promote(struct gfs2_holder *gh) static int rq_demote(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; - const struct gfs2_glock_operations *glops = gl->gl_ops; if (!list_empty(&gl->gl_holders)) return 1; @@ -573,10 +564,7 @@ static int rq_demote(struct gfs2_holder *gh) list_del_init(&gh->gh_list); gh->gh_error = 0; spin_unlock(&gl->gl_spin); - if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) - gfs2_holder_put(gh); - else - complete(&gh->gh_wait); + gfs2_holder_dispose_or_wake(gh); spin_lock(&gl->gl_spin); } else { gl->gl_req_gh = gh; @@ -585,9 +573,9 @@ static int rq_demote(struct gfs2_holder *gh) if (gh->gh_state == LM_ST_UNLOCKED || gl->gl_state != LM_ST_EXCLUSIVE) - glops->go_drop_th(gl); + gfs2_glock_drop_th(gl); else - glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags); + gfs2_glock_xmote_th(gh); spin_lock(&gl->gl_spin); } @@ -595,30 +583,6 @@ static int rq_demote(struct gfs2_holder *gh) return 0; } -/** - * rq_greedy - process a queued request to drop greedy status - * @gh: the glock holder - * - * Returns: 1 if the queue is blocked - */ - -static int rq_greedy(struct gfs2_holder *gh) -{ - struct gfs2_glock *gl = gh->gh_gl; - - list_del_init(&gh->gh_list); - /* gh->gh_error never examined. */ - clear_bit(GLF_GREEDY, &gl->gl_flags); - spin_unlock(&gl->gl_spin); - - gfs2_holder_uninit(gh); - kfree(container_of(gh, struct greedy, gr_gh)); - - spin_lock(&gl->gl_spin); - - return 0; -} - /** * run_queue - process holder structures on a glock * @gl: the glock @@ -649,8 +613,6 @@ static void run_queue(struct gfs2_glock *gl) if (test_bit(HIF_DEMOTE, &gh->gh_iflags)) blocked = rq_demote(gh); - else if (test_bit(HIF_GREEDY, &gh->gh_iflags)) - blocked = rq_greedy(gh); else gfs2_assert_warn(gl->gl_sbd, 0); @@ -684,6 +646,8 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl) gfs2_holder_init(gl, 0, 0, &gh); set_bit(HIF_MUTEX, &gh.gh_iflags); + if (test_and_set_bit(HIF_WAIT, &gh.gh_iflags)) + BUG(); spin_lock(&gl->gl_spin); if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { @@ -691,11 +655,13 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl) } else { gl->gl_owner = current; gl->gl_ip = (unsigned long)__builtin_return_address(0); - complete(&gh.gh_wait); + clear_bit(HIF_WAIT, &gh.gh_iflags); + smp_mb(); + wake_up_bit(&gh.gh_iflags, HIF_WAIT); } spin_unlock(&gl->gl_spin); - wait_for_completion(&gh.gh_wait); + wait_on_holder(&gh); gfs2_holder_uninit(&gh); } @@ -774,6 +740,7 @@ restart: return; set_bit(HIF_DEMOTE, &new_gh->gh_iflags); set_bit(HIF_DEALLOC, &new_gh->gh_iflags); + set_bit(HIF_WAIT, &new_gh->gh_iflags); goto restart; } @@ -825,7 +792,7 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) int op_done = 1; gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); - gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders)); + gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); gfs2_assert_warn(sdp, !(ret & LM_OUT_ASYNC)); state_change(gl, ret & LM_OUT_ST_MASK); @@ -908,12 +875,8 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) gfs2_glock_put(gl); - if (gh) { - if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) - gfs2_holder_put(gh); - else - complete(&gh->gh_wait); - } + if (gh) + gfs2_holder_dispose_or_wake(gh); } /** @@ -924,23 +887,26 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret) * */ -void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags) +void gfs2_glock_xmote_th(struct gfs2_holder *gh) { + struct gfs2_glock *gl = gh->gh_gl; struct gfs2_sbd *sdp = gl->gl_sbd; + int flags = gh->gh_flags; + unsigned state = gh->gh_state; const struct gfs2_glock_operations *glops = gl->gl_ops; int lck_flags = flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB | LM_FLAG_NOEXP | LM_FLAG_ANY | LM_FLAG_PRIORITY); unsigned int lck_ret; + if (glops->go_xmote_th) + glops->go_xmote_th(gl); + gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); - gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders)); + gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); gfs2_assert_warn(sdp, state != LM_ST_UNLOCKED); gfs2_assert_warn(sdp, state != gl->gl_state); - if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync) - glops->go_sync(gl); - gfs2_glock_hold(gl); gl->gl_req_bh = xmote_bh; @@ -971,10 +937,8 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) const struct gfs2_glock_operations *glops = gl->gl_ops; struct gfs2_holder *gh = gl->gl_req_gh; - clear_bit(GLF_PREFETCH, &gl->gl_flags); - gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); - gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders)); + gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); gfs2_assert_warn(sdp, !ret); state_change(gl, LM_ST_UNLOCKED); @@ -1001,12 +965,8 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) gfs2_glock_put(gl); - if (gh) { - if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) - gfs2_holder_put(gh); - else - complete(&gh->gh_wait); - } + if (gh) + gfs2_holder_dispose_or_wake(gh); } /** @@ -1015,18 +975,18 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret) * */ -void gfs2_glock_drop_th(struct gfs2_glock *gl) +static void gfs2_glock_drop_th(struct gfs2_glock *gl) { struct gfs2_sbd *sdp = gl->gl_sbd; const struct gfs2_glock_operations *glops = gl->gl_ops; unsigned int ret; - gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); - gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders)); - gfs2_assert_warn(sdp, gl->gl_state != LM_ST_UNLOCKED); + if (glops->go_drop_th) + glops->go_drop_th(gl); - if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync) - glops->go_sync(gl); + gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags)); + gfs2_assert_warn(sdp, list_empty(&gl->gl_holders)); + gfs2_assert_warn(sdp, gl->gl_state != LM_ST_UNLOCKED); gfs2_glock_hold(gl); gl->gl_req_bh = drop_bh; @@ -1107,8 +1067,7 @@ static int glock_wait_internal(struct gfs2_holder *gh) if (gh->gh_flags & LM_FLAG_PRIORITY) do_cancels(gh); - wait_for_completion(&gh->gh_wait); - + wait_on_holder(gh); if (gh->gh_error) return gh->gh_error; @@ -1164,6 +1123,8 @@ static void add_to_queue(struct gfs2_holder *gh) struct gfs2_holder *existing; BUG_ON(!gh->gh_owner); + if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags)) + BUG(); existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner); if (existing) { @@ -1227,8 +1188,6 @@ restart: } } - clear_bit(GLF_PREFETCH, &gl->gl_flags); - return error; } @@ -1320,98 +1279,6 @@ void gfs2_glock_dq(struct gfs2_holder *gh) spin_unlock(&gl->gl_spin); } -/** - * gfs2_glock_prefetch - Try to prefetch a glock - * @gl: the glock - * @state: the state to prefetch in - * @flags: flags passed to go_xmote_th() - * - */ - -static void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state, - int flags) -{ - const struct gfs2_glock_operations *glops = gl->gl_ops; - - spin_lock(&gl->gl_spin); - - if (test_bit(GLF_LOCK, &gl->gl_flags) || !list_empty(&gl->gl_holders) || - !list_empty(&gl->gl_waiters1) || !list_empty(&gl->gl_waiters2) || - !list_empty(&gl->gl_waiters3) || - relaxed_state_ok(gl->gl_state, state, flags)) { - spin_unlock(&gl->gl_spin); - return; - } - - set_bit(GLF_PREFETCH, &gl->gl_flags); - set_bit(GLF_LOCK, &gl->gl_flags); - spin_unlock(&gl->gl_spin); - - glops->go_xmote_th(gl, state, flags); -} - -static void greedy_work(struct work_struct *work) -{ - struct greedy *gr = container_of(work, struct greedy, gr_work.work); - struct gfs2_holder *gh = &gr->gr_gh; - struct gfs2_glock *gl = gh->gh_gl; - const struct gfs2_glock_operations *glops = gl->gl_ops; - - clear_bit(GLF_SKIP_WAITERS2, &gl->gl_flags); - - if (glops->go_greedy) - glops->go_greedy(gl); - - spin_lock(&gl->gl_spin); - - if (list_empty(&gl->gl_waiters2)) { - clear_bit(GLF_GREEDY, &gl->gl_flags); - spin_unlock(&gl->gl_spin); - gfs2_holder_uninit(gh); - kfree(gr); - } else { - gfs2_glock_hold(gl); - list_add_tail(&gh->gh_list, &gl->gl_waiters2); - run_queue(gl); - spin_unlock(&gl->gl_spin); - gfs2_glock_put(gl); - } -} - -/** - * gfs2_glock_be_greedy - - * @gl: - * @time: - * - * Returns: 0 if go_greedy will be called, 1 otherwise - */ - -int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time) -{ - struct greedy *gr; - struct gfs2_holder *gh; - - if (!time || gl->gl_sbd->sd_args.ar_localcaching || - test_and_set_bit(GLF_GREEDY, &gl->gl_flags)) - return 1; - - gr = kmalloc(sizeof(struct greedy), GFP_KERNEL); - if (!gr) { - clear_bit(GLF_GREEDY, &gl->gl_flags); - return 1; - } - gh = &gr->gr_gh; - - gfs2_holder_init(gl, 0, 0, gh); - set_bit(HIF_GREEDY, &gh->gh_iflags); - INIT_DELAYED_WORK(&gr->gr_work, greedy_work); - - set_bit(GLF_SKIP_WAITERS2, &gl->gl_flags); - schedule_delayed_work(&gr->gr_work, time); - - return 0; -} - /** * gfs2_glock_dq_uninit - dequeue a holder from a glock and initialize it * @gh: the holder structure @@ -1470,10 +1337,7 @@ static int glock_compare(const void *arg_a, const void *arg_b) return 1; if (a->ln_number < b->ln_number) return -1; - if (gh_a->gh_state == LM_ST_SHARED && gh_b->gh_state == LM_ST_EXCLUSIVE) - return 1; - if (!(gh_a->gh_flags & GL_LOCAL_EXCL) && (gh_b->gh_flags & GL_LOCAL_EXCL)) - return 1; + BUG_ON(gh_a->gh_gl->gl_ops->go_type == gh_b->gh_gl->gl_ops->go_type); return 0; } @@ -1617,34 +1481,6 @@ void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs) gfs2_glock_dq_uninit(&ghs[x]); } -/** - * gfs2_glock_prefetch_num - prefetch a glock based on lock number - * @sdp: the filesystem - * @number: the lock number - * @glops: the glock operations for the type of glock - * @state: the state to acquire the glock in - * @flags: modifier flags for the aquisition - * - * Returns: errno - */ - -void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number, - const struct gfs2_glock_operations *glops, - unsigned int state, int flags) -{ - struct gfs2_glock *gl; - int error; - - if (atomic_read(&sdp->sd_reclaim_count) < - gfs2_tune_get(sdp, gt_reclaim_limit)) { - error = gfs2_glock_get(sdp, number, glops, CREATE, &gl); - if (!error) { - gfs2_glock_prefetch(gl, state, flags); - gfs2_glock_put(gl); - } - } -} - /** * gfs2_lvb_hold - attach a LVB from a glock * @gl: The glock in question @@ -1703,8 +1539,6 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name, if (!gl) return; - if (gl->gl_ops->go_callback) - gl->gl_ops->go_callback(gl, state); handle_callback(gl, state); spin_lock(&gl->gl_spin); @@ -1746,12 +1580,14 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data) struct lm_async_cb *async = data; struct gfs2_glock *gl; + down_read(&gfs2_umount_flush_sem); gl = gfs2_glock_find(sdp, &async->lc_name); if (gfs2_assert_warn(sdp, gl)) return; if (!gfs2_assert_warn(sdp, gl->gl_req_bh)) gl->gl_req_bh(gl, async->lc_ret); gfs2_glock_put(gl); + up_read(&gfs2_umount_flush_sem); return; } @@ -1781,15 +1617,11 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data) static int demote_ok(struct gfs2_glock *gl) { - struct gfs2_sbd *sdp = gl->gl_sbd; const struct gfs2_glock_operations *glops = gl->gl_ops; int demote = 1; if (test_bit(GLF_STICKY, &gl->gl_flags)) demote = 0; - else if (test_bit(GLF_PREFETCH, &gl->gl_flags)) - demote = time_after_eq(jiffies, gl->gl_stamp + - gfs2_tune_get(sdp, gt_prefetch_secs) * HZ); else if (glops->go_demote_ok) demote = glops->go_demote_ok(gl); @@ -1845,7 +1677,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp) atomic_inc(&sdp->sd_reclaimed); if (gfs2_glmutex_trylock(gl)) { - if (queue_empty(gl, &gl->gl_holders) && + if (list_empty(&gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl)) handle_callback(gl, LM_ST_UNLOCKED); gfs2_glmutex_unlock(gl); @@ -1909,7 +1741,7 @@ static void scan_glock(struct gfs2_glock *gl) return; if (gfs2_glmutex_trylock(gl)) { - if (queue_empty(gl, &gl->gl_holders) && + if (list_empty(&gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl)) goto out_schedule; gfs2_glmutex_unlock(gl); @@ -1958,7 +1790,7 @@ static void clear_glock(struct gfs2_glock *gl) } if (gfs2_glmutex_trylock(gl)) { - if (queue_empty(gl, &gl->gl_holders) && + if (list_empty(&gl->gl_holders) && gl->gl_state != LM_ST_UNLOCKED) handle_callback(gl, LM_ST_UNLOCKED); gfs2_glmutex_unlock(gl); @@ -2000,7 +1832,9 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait) t = jiffies; } + down_write(&gfs2_umount_flush_sem); invalidate_inodes(sdp->sd_vfs); + up_write(&gfs2_umount_flush_sem); msleep(10); } } diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index fb39108fc05c..f50e40ceca43 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -20,7 +20,6 @@ #define LM_FLAG_ANY 0x00000008 #define LM_FLAG_PRIORITY 0x00000010 */ -#define GL_LOCAL_EXCL 0x00000020 #define GL_ASYNC 0x00000040 #define GL_EXACT 0x00000080 #define GL_SKIP 0x00000100 @@ -83,17 +82,11 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *gh); void gfs2_holder_uninit(struct gfs2_holder *gh); - -void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags); -void gfs2_glock_drop_th(struct gfs2_glock *gl); - int gfs2_glock_nq(struct gfs2_holder *gh); int gfs2_glock_poll(struct gfs2_holder *gh); int gfs2_glock_wait(struct gfs2_holder *gh); void gfs2_glock_dq(struct gfs2_holder *gh); -int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time); - void gfs2_glock_dq_uninit(struct gfs2_holder *gh); int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number, const struct gfs2_glock_operations *glops, @@ -103,10 +96,6 @@ int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs); void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs); void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs); -void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number, - const struct gfs2_glock_operations *glops, - unsigned int state, int flags); - /** * gfs2_glock_nq_init - intialize a holder and enqueue it on a glock * @gl: the glock diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index b068d10bcb6e..c4b0391b7aa2 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -117,12 +117,14 @@ static void gfs2_pte_inval(struct gfs2_glock *gl) static void meta_go_sync(struct gfs2_glock *gl) { + if (gl->gl_state != LM_ST_EXCLUSIVE) + return; + if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) { gfs2_log_flush(gl->gl_sbd, gl); gfs2_meta_sync(gl); gfs2_ail_empty_gl(gl); } - } /** @@ -141,6 +143,37 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags) gl->gl_vn++; } +/** + * inode_go_sync - Sync the dirty data and/or metadata for an inode glock + * @gl: the glock protecting the inode + * + */ + +static void inode_go_sync(struct gfs2_glock *gl) +{ + struct gfs2_inode *ip = gl->gl_object; + + if (ip && !S_ISREG(ip->i_inode.i_mode)) + ip = NULL; + + if (test_bit(GLF_DIRTY, &gl->gl_flags)) { + gfs2_log_flush(gl->gl_sbd, gl); + if (ip) + filemap_fdatawrite(ip->i_inode.i_mapping); + gfs2_meta_sync(gl); + if (ip) { + struct address_space *mapping = ip->i_inode.i_mapping; + int error = filemap_fdatawait(mapping); + if (error == -ENOSPC) + set_bit(AS_ENOSPC, &mapping->flags); + else if (error) + set_bit(AS_EIO, &mapping->flags); + } + clear_bit(GLF_DIRTY, &gl->gl_flags); + gfs2_ail_empty_gl(gl); + } +} + /** * inode_go_xmote_th - promote/demote a glock * @gl: the glock @@ -149,12 +182,12 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags) * */ -static void inode_go_xmote_th(struct gfs2_glock *gl, unsigned int state, - int flags) +static void inode_go_xmote_th(struct gfs2_glock *gl) { if (gl->gl_state != LM_ST_UNLOCKED) gfs2_pte_inval(gl); - gfs2_glock_xmote_th(gl, state, flags); + if (gl->gl_state == LM_ST_EXCLUSIVE) + inode_go_sync(gl); } /** @@ -189,38 +222,8 @@ static void inode_go_xmote_bh(struct gfs2_glock *gl) static void inode_go_drop_th(struct gfs2_glock *gl) { gfs2_pte_inval(gl); - gfs2_glock_drop_th(gl); -} - -/** - * inode_go_sync - Sync the dirty data and/or metadata for an inode glock - * @gl: the glock protecting the inode - * - */ - -static void inode_go_sync(struct gfs2_glock *gl) -{ - struct gfs2_inode *ip = gl->gl_object; - - if (ip && !S_ISREG(ip->i_inode.i_mode)) - ip = NULL; - - if (test_bit(GLF_DIRTY, &gl->gl_flags)) { - gfs2_log_flush(gl->gl_sbd, gl); - if (ip) - filemap_fdatawrite(ip->i_inode.i_mapping); - gfs2_meta_sync(gl); - if (ip) { - struct address_space *mapping = ip->i_inode.i_mapping; - int error = filemap_fdatawait(mapping); - if (error == -ENOSPC) - set_bit(AS_ENOSPC, &mapping->flags); - else if (error) - set_bit(AS_EIO, &mapping->flags); - } - clear_bit(GLF_DIRTY, &gl->gl_flags); - gfs2_ail_empty_gl(gl); - } + if (gl->gl_state == LM_ST_EXCLUSIVE) + inode_go_sync(gl); } /** @@ -295,7 +298,7 @@ static int inode_go_lock(struct gfs2_holder *gh) if ((ip->i_di.di_flags & GFS2_DIF_TRUNC_IN_PROG) && (gl->gl_state == LM_ST_EXCLUSIVE) && - (gh->gh_flags & GL_LOCAL_EXCL)) + (gh->gh_state == LM_ST_EXCLUSIVE)) error = gfs2_truncatei_resume(ip); return error; @@ -318,39 +321,6 @@ static void inode_go_unlock(struct gfs2_holder *gh) gfs2_meta_cache_flush(ip); } -/** - * inode_greedy - - * @gl: the glock - * - */ - -static void inode_greedy(struct gfs2_glock *gl) -{ - struct gfs2_sbd *sdp = gl->gl_sbd; - struct gfs2_inode *ip = gl->gl_object; - unsigned int quantum = gfs2_tune_get(sdp, gt_greedy_quantum); - unsigned int max = gfs2_tune_get(sdp, gt_greedy_max); - unsigned int new_time; - - spin_lock(&ip->i_spin); - - if (time_after(ip->i_last_pfault + quantum, jiffies)) { - new_time = ip->i_greedy + quantum; - if (new_time > max) - new_time = max; - } else { - new_time = ip->i_greedy - quantum; - if (!new_time || new_time > max) - new_time = 1; - } - - ip->i_greedy = new_time; - - spin_unlock(&ip->i_spin); - - iput(&ip->i_inode); -} - /** * rgrp_go_demote_ok - Check to see if it's ok to unlock a RG's glock * @gl: the glock @@ -398,8 +368,7 @@ static void rgrp_go_unlock(struct gfs2_holder *gh) * */ -static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state, - int flags) +static void trans_go_xmote_th(struct gfs2_glock *gl) { struct gfs2_sbd *sdp = gl->gl_sbd; @@ -408,8 +377,6 @@ static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state, gfs2_meta_syncfs(sdp); gfs2_log_shutdown(sdp); } - - gfs2_glock_xmote_th(gl, state, flags); } /** @@ -461,8 +428,6 @@ static void trans_go_drop_th(struct gfs2_glock *gl) gfs2_meta_syncfs(sdp); gfs2_log_shutdown(sdp); } - - gfs2_glock_drop_th(gl); } /** @@ -478,8 +443,8 @@ static int quota_go_demote_ok(struct gfs2_glock *gl) } const struct gfs2_glock_operations gfs2_meta_glops = { - .go_xmote_th = gfs2_glock_xmote_th, - .go_drop_th = gfs2_glock_drop_th, + .go_xmote_th = meta_go_sync, + .go_drop_th = meta_go_sync, .go_type = LM_TYPE_META, }; @@ -487,19 +452,14 @@ const struct gfs2_glock_operations gfs2_inode_glops = { .go_xmote_th = inode_go_xmote_th, .go_xmote_bh = inode_go_xmote_bh, .go_drop_th = inode_go_drop_th, - .go_sync = inode_go_sync, .go_inval = inode_go_inval, .go_demote_ok = inode_go_demote_ok, .go_lock = inode_go_lock, .go_unlock = inode_go_unlock, - .go_greedy = inode_greedy, .go_type = LM_TYPE_INODE, }; const struct gfs2_glock_operations gfs2_rgrp_glops = { - .go_xmote_th = gfs2_glock_xmote_th, - .go_drop_th = gfs2_glock_drop_th, - .go_sync = meta_go_sync, .go_inval = meta_go_inval, .go_demote_ok = rgrp_go_demote_ok, .go_lock = rgrp_go_lock, @@ -515,33 +475,23 @@ const struct gfs2_glock_operations gfs2_trans_glops = { }; const struct gfs2_glock_operations gfs2_iopen_glops = { - .go_xmote_th = gfs2_glock_xmote_th, - .go_drop_th = gfs2_glock_drop_th, .go_type = LM_TYPE_IOPEN, }; const struct gfs2_glock_operations gfs2_flock_glops = { - .go_xmote_th = gfs2_glock_xmote_th, - .go_drop_th = gfs2_glock_drop_th, .go_type = LM_TYPE_FLOCK, }; const struct gfs2_glock_operations gfs2_nondisk_glops = { - .go_xmote_th = gfs2_glock_xmote_th, - .go_drop_th = gfs2_glock_drop_th, .go_type = LM_TYPE_NONDISK, }; const struct gfs2_glock_operations gfs2_quota_glops = { - .go_xmote_th = gfs2_glock_xmote_th, - .go_drop_th = gfs2_glock_drop_th, .go_demote_ok = quota_go_demote_ok, .go_type = LM_TYPE_QUOTA, }; const struct gfs2_glock_operations gfs2_journal_glops = { - .go_xmote_th = gfs2_glock_xmote_th, - .go_drop_th = gfs2_glock_drop_th, .go_type = LM_TYPE_JOURNAL, }; diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 734421edae85..12c80fd28db5 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -101,17 +101,14 @@ struct gfs2_bufdata { }; struct gfs2_glock_operations { - void (*go_xmote_th) (struct gfs2_glock *gl, unsigned int state, int flags); + void (*go_xmote_th) (struct gfs2_glock *gl); void (*go_xmote_bh) (struct gfs2_glock *gl); void (*go_drop_th) (struct gfs2_glock *gl); void (*go_drop_bh) (struct gfs2_glock *gl); - void (*go_sync) (struct gfs2_glock *gl); void (*go_inval) (struct gfs2_glock *gl, int flags); int (*go_demote_ok) (struct gfs2_glock *gl); int (*go_lock) (struct gfs2_holder *gh); void (*go_unlock) (struct gfs2_holder *gh); - void (*go_callback) (struct gfs2_glock *gl, unsigned int state); - void (*go_greedy) (struct gfs2_glock *gl); const int go_type; }; @@ -120,7 +117,6 @@ enum { HIF_MUTEX = 0, HIF_PROMOTE = 1, HIF_DEMOTE = 2, - HIF_GREEDY = 3, /* States */ HIF_ALLOCED = 4, @@ -128,6 +124,7 @@ enum { HIF_HOLDER = 6, HIF_FIRST = 7, HIF_ABORTED = 9, + HIF_WAIT = 10, }; struct gfs2_holder { @@ -140,17 +137,14 @@ struct gfs2_holder { int gh_error; unsigned long gh_iflags; - struct completion gh_wait; unsigned long gh_ip; }; enum { GLF_LOCK = 1, GLF_STICKY = 2, - GLF_PREFETCH = 3, GLF_DIRTY = 5, GLF_SKIP_WAITERS2 = 6, - GLF_GREEDY = 7, }; struct gfs2_glock { @@ -167,7 +161,7 @@ struct gfs2_glock { unsigned long gl_ip; struct list_head gl_holders; struct list_head gl_waiters1; /* HIF_MUTEX */ - struct list_head gl_waiters2; /* HIF_DEMOTE, HIF_GREEDY */ + struct list_head gl_waiters2; /* HIF_DEMOTE */ struct list_head gl_waiters3; /* HIF_PROMOTE */ const struct gfs2_glock_operations *gl_ops; @@ -236,7 +230,6 @@ struct gfs2_inode { spinlock_t i_spin; struct rw_semaphore i_rw_mutex; - unsigned int i_greedy; unsigned long i_last_pfault; struct buffer_head *i_cache[GFS2_MAX_META_HEIGHT]; @@ -418,17 +411,12 @@ struct gfs2_tune { unsigned int gt_atime_quantum; /* Min secs between atime updates */ unsigned int gt_new_files_jdata; unsigned int gt_new_files_directio; - unsigned int gt_max_atomic_write; /* Split big writes into this size */ unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */ unsigned int gt_lockdump_size; unsigned int gt_stall_secs; /* Detects trouble! */ unsigned int gt_complain_secs; unsigned int gt_reclaim_limit; /* Max num of glocks in reclaim list */ unsigned int gt_entries_per_readdir; - unsigned int gt_prefetch_secs; /* Usage window for prefetched glocks */ - unsigned int gt_greedy_default; - unsigned int gt_greedy_quantum; - unsigned int gt_greedy_max; unsigned int gt_statfs_quantum; unsigned int gt_statfs_slow; }; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index d122074c45e1..0d6831a40565 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -287,10 +287,8 @@ out: * * Returns: errno */ - int gfs2_change_nlink(struct gfs2_inode *ip, int diff) { - struct gfs2_sbd *sdp = ip->i_inode.i_sb->s_fs_info; struct buffer_head *dibh; u32 nlink; int error; @@ -315,42 +313,34 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff) else drop_nlink(&ip->i_inode); - ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_ctime = CURRENT_TIME_SEC; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); mark_inode_dirty(&ip->i_inode); - if (ip->i_inode.i_nlink == 0) { - struct gfs2_rgrpd *rgd; - struct gfs2_holder ri_gh, rg_gh; - - error = gfs2_rindex_hold(sdp, &ri_gh); - if (error) - goto out; - error = -EIO; - rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr); - if (!rgd) - goto out_norgrp; - error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh); - if (error) - goto out_norgrp; - + if (ip->i_inode.i_nlink == 0) gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */ - gfs2_glock_dq_uninit(&rg_gh); -out_norgrp: - gfs2_glock_dq_uninit(&ri_gh); - } -out: + return error; } struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) { struct qstr qstr; + struct inode *inode; gfs2_str2qstr(&qstr, name); - return gfs2_lookupi(dip, &qstr, 1, NULL); + inode = gfs2_lookupi(dip, &qstr, 1, NULL); + /* gfs2_lookupi has inconsistent callers: vfs + * related routines expect NULL for no entry found, + * gfs2_lookup_simple callers expect ENOENT + * and do not check for NULL. + */ + if (inode == NULL) + return ERR_PTR(-ENOENT); + else + return inode; } @@ -361,8 +351,10 @@ struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) * @is_root: If 1, ignore the caller's permissions * @i_gh: An uninitialized holder for the new inode glock * - * There will always be a vnode (Linux VFS inode) for the d_gh inode unless - * @is_root is true. + * This can be called via the VFS filldir function when NFS is doing + * a readdirplus and the inode which its intending to stat isn't + * already in cache. In this case we must not take the directory glock + * again, since the readdir call will have already taken that lock. * * Returns: errno */ @@ -375,8 +367,9 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, struct gfs2_holder d_gh; struct gfs2_inum_host inum; unsigned int type; - int error = 0; + int error; struct inode *inode = NULL; + int unlock = 0; if (!name->len || name->len > GFS2_FNAMESIZE) return ERR_PTR(-ENAMETOOLONG); @@ -388,9 +381,12 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, return dir; } - error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); - if (error) - return ERR_PTR(error); + if (gfs2_glock_is_locked_by_me(dip->i_gl) == 0) { + error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); + if (error) + return ERR_PTR(error); + unlock = 1; + } if (!is_root) { error = permission(dir, MAY_EXEC, NULL); @@ -405,10 +401,11 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, inode = gfs2_inode_lookup(sb, &inum, type); out: - gfs2_glock_dq_uninit(&d_gh); + if (unlock) + gfs2_glock_dq_uninit(&d_gh); if (error == -ENOENT) return NULL; - return inode; + return inode ? inode : ERR_PTR(error); } static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino) diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c index effe4a337c1d..e30673dd37e0 100644 --- a/fs/gfs2/lm.c +++ b/fs/gfs2/lm.c @@ -104,15 +104,9 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) vprintk(fmt, args); va_end(args); - fs_err(sdp, "about to withdraw from the cluster\n"); + fs_err(sdp, "about to withdraw this file system\n"); BUG_ON(sdp->sd_args.ar_debug); - - fs_err(sdp, "waiting for outstanding I/O\n"); - - /* FIXME: suspend dm device so oustanding bio's complete - and all further io requests fail */ - fs_err(sdp, "telling LM to withdraw\n"); gfs2_withdraw_lockproto(&sdp->sd_lockstruct); fs_err(sdp, "withdrawn\n"); diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index 33af707a4d3f..a87c7bf3c568 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h @@ -36,7 +36,7 @@ #define GDLM_STRNAME_BYTES 24 #define GDLM_LVB_SIZE 32 -#define GDLM_DROP_COUNT 50000 +#define GDLM_DROP_COUNT 200000 #define GDLM_DROP_PERIOD 60 #define GDLM_NAME_LEN 128 diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c index 2194b1d5b5ec..a0e7eda643ed 100644 --- a/fs/gfs2/locking/dlm/main.c +++ b/fs/gfs2/locking/dlm/main.c @@ -11,9 +11,6 @@ #include "lock_dlm.h" -extern int gdlm_drop_count; -extern int gdlm_drop_period; - extern struct lm_lockops gdlm_ops; static int __init init_lock_dlm(void) @@ -40,9 +37,6 @@ static int __init init_lock_dlm(void) return error; } - gdlm_drop_count = GDLM_DROP_COUNT; - gdlm_drop_period = GDLM_DROP_PERIOD; - printk(KERN_INFO "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__); return 0; diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index cdd1694e889b..1d8faa3da8af 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c @@ -9,8 +9,6 @@ #include "lock_dlm.h" -int gdlm_drop_count; -int gdlm_drop_period; const struct lm_lockops gdlm_ops; @@ -24,8 +22,8 @@ static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp, if (!ls) return NULL; - ls->drop_locks_count = gdlm_drop_count; - ls->drop_locks_period = gdlm_drop_period; + ls->drop_locks_count = GDLM_DROP_COUNT; + ls->drop_locks_period = GDLM_DROP_PERIOD; ls->fscb = cb; ls->sdp = sdp; ls->fsflags = flags; diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c index 29ae06f94944..4746b884662d 100644 --- a/fs/gfs2/locking/dlm/sysfs.c +++ b/fs/gfs2/locking/dlm/sysfs.c @@ -116,6 +116,17 @@ static ssize_t recover_status_show(struct gdlm_ls *ls, char *buf) return sprintf(buf, "%d\n", ls->recover_jid_status); } +static ssize_t drop_count_show(struct gdlm_ls *ls, char *buf) +{ + return sprintf(buf, "%d\n", ls->drop_locks_count); +} + +static ssize_t drop_count_store(struct gdlm_ls *ls, const char *buf, size_t len) +{ + ls->drop_locks_count = simple_strtol(buf, NULL, 0); + return len; +} + struct gdlm_attr { struct attribute attr; ssize_t (*show)(struct gdlm_ls *, char *); @@ -135,6 +146,7 @@ GDLM_ATTR(first_done, 0444, first_done_show, NULL); GDLM_ATTR(recover, 0644, recover_show, recover_store); GDLM_ATTR(recover_done, 0444, recover_done_show, NULL); GDLM_ATTR(recover_status, 0444, recover_status_show, NULL); +GDLM_ATTR(drop_count, 0644, drop_count_show, drop_count_store); static struct attribute *gdlm_attrs[] = { &gdlm_attr_proto_name.attr, @@ -147,6 +159,7 @@ static struct attribute *gdlm_attrs[] = { &gdlm_attr_recover.attr, &gdlm_attr_recover_done.attr, &gdlm_attr_recover_status.attr, + &gdlm_attr_drop_count.attr, NULL, }; diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 4d7f94d8c7bd..16bb4b4561ae 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -69,13 +69,16 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le); struct gfs2_trans *tr; - if (!list_empty(&bd->bd_list_tr)) + gfs2_log_lock(sdp); + if (!list_empty(&bd->bd_list_tr)) { + gfs2_log_unlock(sdp); return; - + } tr = current->journal_info; tr->tr_touched = 1; tr->tr_num_buf++; list_add(&bd->bd_list_tr, &tr->tr_list_buf); + gfs2_log_unlock(sdp); if (!list_empty(&le->le_list)) return; @@ -84,7 +87,6 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) gfs2_meta_check(sdp, bd->bd_bh); gfs2_pin(sdp, bd->bd_bh); - gfs2_log_lock(sdp); sdp->sd_log_num_buf++; list_add(&le->le_list, &sdp->sd_log_le_buf); @@ -98,11 +100,13 @@ static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) struct list_head *head = &tr->tr_list_buf; struct gfs2_bufdata *bd; + gfs2_log_lock(sdp); while (!list_empty(head)) { bd = list_entry(head->next, struct gfs2_bufdata, bd_list_tr); list_del_init(&bd->bd_list_tr); tr->tr_num_buf--; } + gfs2_log_unlock(sdp); gfs2_assert_warn(sdp, !tr->tr_num_buf); } @@ -462,13 +466,17 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le) struct address_space *mapping = bd->bd_bh->b_page->mapping; struct gfs2_inode *ip = GFS2_I(mapping->host); + gfs2_log_lock(sdp); tr->tr_touched = 1; if (list_empty(&bd->bd_list_tr) && (ip->i_di.di_flags & GFS2_DIF_JDATA)) { tr->tr_num_buf++; list_add(&bd->bd_list_tr, &tr->tr_list_buf); + gfs2_log_unlock(sdp); gfs2_pin(sdp, bd->bd_bh); tr->tr_num_buf_new++; + } else { + gfs2_log_unlock(sdp); } gfs2_trans_add_gl(bd->bd_gl); gfs2_log_lock(sdp); diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index d8d69a72a10d..56e33590b656 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -156,6 +157,32 @@ out_ignore: return 0; } +/** + * gfs2_writepages - Write a bunch of dirty pages back to disk + * @mapping: The mapping to write + * @wbc: Write-back control + * + * For journaled files and/or ordered writes this just falls back to the + * kernel's default writepages path for now. We will probably want to change + * that eventually (i.e. when we look at allocate on flush). + * + * For the data=writeback case though we can already ignore buffer heads + * and write whole extents at once. This is a big reduction in the + * number of I/O requests we send and the bmap calls we make in this case. + */ +static int gfs2_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + struct inode *inode = mapping->host; + struct gfs2_inode *ip = GFS2_I(inode); + struct gfs2_sbd *sdp = GFS2_SB(inode); + + if (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK && !gfs2_is_jdata(ip)) + return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc); + + return generic_writepages(mapping, wbc); +} + /** * stuffed_readpage - Fill in a Linux page with stuffed file data * @ip: the inode @@ -256,7 +283,7 @@ out_unlock: * the page lock and the glock) and return having done no I/O. Its * obviously not something we'd want to do on too regular a basis. * Any I/O we ignore at this time will be done via readpage later. - * 2. We have to handle stuffed files here too. + * 2. We don't handle stuffed files here we let readpage do the honours. * 3. mpage_readpages() does most of the heavy lifting in the common case. * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places. * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as @@ -269,8 +296,7 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping, struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); struct gfs2_holder gh; - unsigned page_idx; - int ret; + int ret = 0; int do_unlock = 0; if (likely(file != &gfs2_internal_file_sentinel)) { @@ -289,29 +315,8 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping, goto out_unlock; } skip_lock: - if (gfs2_is_stuffed(ip)) { - struct pagevec lru_pvec; - pagevec_init(&lru_pvec, 0); - for (page_idx = 0; page_idx < nr_pages; page_idx++) { - struct page *page = list_entry(pages->prev, struct page, lru); - prefetchw(&page->flags); - list_del(&page->lru); - if (!add_to_page_cache(page, mapping, - page->index, GFP_KERNEL)) { - ret = stuffed_readpage(ip, page); - unlock_page(page); - if (!pagevec_add(&lru_pvec, page)) - __pagevec_lru_add(&lru_pvec); - } else { - page_cache_release(page); - } - } - pagevec_lru_add(&lru_pvec); - ret = 0; - } else { - /* What we really want to do .... */ + if (!gfs2_is_stuffed(ip)) ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block); - } if (do_unlock) { gfs2_glock_dq_m(1, &gh); @@ -356,8 +361,10 @@ static int gfs2_prepare_write(struct file *file, struct page *page, gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|LM_FLAG_TRY_1CB, &ip->i_gh); error = gfs2_glock_nq_atime(&ip->i_gh); if (unlikely(error)) { - if (error == GLR_TRYFAILED) + if (error == GLR_TRYFAILED) { + unlock_page(page); error = AOP_TRUNCATED_PAGE; + } goto out_uninit; } @@ -594,6 +601,36 @@ static void gfs2_invalidatepage(struct page *page, unsigned long offset) return; } +/** + * gfs2_ok_for_dio - check that dio is valid on this file + * @ip: The inode + * @rw: READ or WRITE + * @offset: The offset at which we are reading or writing + * + * Returns: 0 (to ignore the i/o request and thus fall back to buffered i/o) + * 1 (to accept the i/o request) + */ +static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset) +{ + /* + * Should we return an error here? I can't see that O_DIRECT for + * a journaled file makes any sense. For now we'll silently fall + * back to buffered I/O, likewise we do the same for stuffed + * files since they are (a) small and (b) unaligned. + */ + if (gfs2_is_jdata(ip)) + return 0; + + if (gfs2_is_stuffed(ip)) + return 0; + + if (offset > i_size_read(&ip->i_inode)) + return 0; + return 1; +} + + + static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs) @@ -604,42 +641,28 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, struct gfs2_holder gh; int rv; - if (rw == READ) - mutex_lock(&inode->i_mutex); /* - * Shared lock, even if its a write, since we do no allocation - * on this path. All we need change is atime. + * Deferred lock, even if its a write, since we do no allocation + * on this path. All we need change is atime, and this lock mode + * ensures that other nodes have flushed their buffered read caches + * (i.e. their page cache entries for this inode). We do not, + * unfortunately have the option of only flushing a range like + * the VFS does. */ - gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); + gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, GL_ATIME, &gh); rv = gfs2_glock_nq_atime(&gh); if (rv) - goto out; + return rv; + rv = gfs2_ok_for_dio(ip, rw, offset); + if (rv != 1) + goto out; /* dio not valid, fall back to buffered i/o */ - if (offset > i_size_read(inode)) - goto out; - - /* - * Should we return an error here? I can't see that O_DIRECT for - * a journaled file makes any sense. For now we'll silently fall - * back to buffered I/O, likewise we do the same for stuffed - * files since they are (a) small and (b) unaligned. - */ - if (gfs2_is_jdata(ip)) - goto out; - - if (gfs2_is_stuffed(ip)) - goto out; - - rv = blockdev_direct_IO_own_locking(rw, iocb, inode, - inode->i_sb->s_bdev, - iov, offset, nr_segs, - gfs2_get_block_direct, NULL); + rv = blockdev_direct_IO_no_locking(rw, iocb, inode, inode->i_sb->s_bdev, + iov, offset, nr_segs, + gfs2_get_block_direct, NULL); out: gfs2_glock_dq_m(1, &gh); gfs2_holder_uninit(&gh); - if (rw == READ) - mutex_unlock(&inode->i_mutex); - return rv; } @@ -763,6 +786,7 @@ out: const struct address_space_operations gfs2_file_aops = { .writepage = gfs2_writepage, + .writepages = gfs2_writepages, .readpage = gfs2_readpage, .readpages = gfs2_readpages, .sync_page = block_sync_page, diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c index d355899585d8..9187eb174b43 100644 --- a/fs/gfs2/ops_dentry.c +++ b/fs/gfs2/ops_dentry.c @@ -46,6 +46,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) struct gfs2_inum_host inum; unsigned int type; int error; + int had_lock=0; if (inode && is_bad_inode(inode)) goto invalid; @@ -53,9 +54,12 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) if (sdp->sd_args.ar_localcaching) goto valid; - error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); - if (error) - goto fail; + had_lock = gfs2_glock_is_locked_by_me(dip->i_gl); + if (!had_lock) { + error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); + if (error) + goto fail; + } error = gfs2_dir_search(parent->d_inode, &dentry->d_name, &inum, &type); switch (error) { @@ -82,13 +86,15 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) } valid_gunlock: - gfs2_glock_dq_uninit(&d_gh); + if (!had_lock) + gfs2_glock_dq_uninit(&d_gh); valid: dput(parent); return 1; invalid_gunlock: - gfs2_glock_dq_uninit(&d_gh); + if (!had_lock) + gfs2_glock_dq_uninit(&d_gh); invalid: if (inode && S_ISDIR(inode->i_mode)) { if (have_submounts(dentry)) diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index b4e7b8775315..4855e8cca622 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c @@ -22,6 +22,7 @@ #include "glock.h" #include "glops.h" #include "inode.h" +#include "ops_dentry.h" #include "ops_export.h" #include "rgrp.h" #include "util.h" @@ -112,13 +113,12 @@ struct get_name_filldir { char *name; }; -static int get_name_filldir(void *opaque, const char *name, unsigned int length, - u64 offset, struct gfs2_inum_host *inum, - unsigned int type) +static int get_name_filldir(void *opaque, const char *name, int length, + loff_t offset, u64 inum, unsigned int type) { - struct get_name_filldir *gnfd = (struct get_name_filldir *)opaque; + struct get_name_filldir *gnfd = opaque; - if (!gfs2_inum_equal(inum, &gnfd->inum)) + if (inum != gnfd->inum.no_addr) return 0; memcpy(gnfd->name, name, length); @@ -189,6 +189,7 @@ static struct dentry *gfs2_get_parent(struct dentry *child) return ERR_PTR(-ENOMEM); } + dentry->d_op = &gfs2_dops; return dentry; } @@ -215,8 +216,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj) } error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops, - LM_ST_SHARED, LM_FLAG_ANY | GL_LOCAL_EXCL, - &i_gh); + LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) return ERR_PTR(error); @@ -269,6 +269,7 @@ out_inode: return ERR_PTR(-ENOMEM); } + dentry->d_op = &gfs2_dops; return dentry; fail_rgd: diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index faa07e4b97d0..c996aa739a05 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c @@ -43,15 +43,6 @@ #include "util.h" #include "eaops.h" -/* For regular, non-NFS */ -struct filldir_reg { - struct gfs2_sbd *fdr_sbd; - int fdr_prefetch; - - filldir_t fdr_filldir; - void *fdr_opaque; -}; - /* * Most fields left uninitialised to catch anybody who tries to * use them. f_flags set to prevent file_accessed() from touching @@ -127,41 +118,6 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) return error; } -/** - * filldir_func - Report a directory entry to the caller of gfs2_dir_read() - * @opaque: opaque data used by the function - * @name: the name of the directory entry - * @length: the length of the name - * @offset: the entry's offset in the directory - * @inum: the inode number the entry points to - * @type: the type of inode the entry points to - * - * Returns: 0 on success, 1 if buffer full - */ - -static int filldir_func(void *opaque, const char *name, unsigned int length, - u64 offset, struct gfs2_inum_host *inum, - unsigned int type) -{ - struct filldir_reg *fdr = (struct filldir_reg *)opaque; - struct gfs2_sbd *sdp = fdr->fdr_sbd; - int error; - - error = fdr->fdr_filldir(fdr->fdr_opaque, name, length, offset, - inum->no_addr, type); - if (error) - return 1; - - if (fdr->fdr_prefetch && !(length == 1 && *name == '.')) { - gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_inode_glops, - LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY); - gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_iopen_glops, - LM_ST_SHARED, LM_FLAG_TRY); - } - - return 0; -} - /** * gfs2_readdir - Read directory entries from a directory * @file: The directory to read from @@ -175,16 +131,10 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) { struct inode *dir = file->f_mapping->host; struct gfs2_inode *dip = GFS2_I(dir); - struct filldir_reg fdr; struct gfs2_holder d_gh; u64 offset = file->f_pos; int error; - fdr.fdr_sbd = GFS2_SB(dir); - fdr.fdr_prefetch = 1; - fdr.fdr_filldir = filldir; - fdr.fdr_opaque = dirent; - gfs2_holder_init(dip->i_gl, LM_ST_SHARED, GL_ATIME, &d_gh); error = gfs2_glock_nq_atime(&d_gh); if (error) { @@ -192,7 +142,7 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) return error; } - error = gfs2_dir_read(dir, &offset, &fdr, filldir_func); + error = gfs2_dir_read(dir, &offset, dirent, filldir); gfs2_glock_dq_uninit(&d_gh); diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 636dda4c7d38..f40a84807d75 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -264,13 +264,23 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_inode *ip = GFS2_I(dentry->d_inode); - struct gfs2_holder ghs[2]; + struct gfs2_holder ghs[3]; + struct gfs2_rgrpd *rgd; + struct gfs2_holder ri_gh; int error; - gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); - gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); + error = gfs2_rindex_hold(sdp, &ri_gh); + if (error) + return error; - error = gfs2_glock_nq_m(2, ghs); + gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); + + rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr); + gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); + + + error = gfs2_glock_nq_m(3, ghs); if (error) goto out; @@ -291,10 +301,12 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) out_end_trans: gfs2_trans_end(sdp); out_gunlock: - gfs2_glock_dq_m(2, ghs); + gfs2_glock_dq_m(3, ghs); out: gfs2_holder_uninit(ghs); gfs2_holder_uninit(ghs + 1); + gfs2_holder_uninit(ghs + 2); + gfs2_glock_dq_uninit(&ri_gh); return error; } @@ -449,13 +461,22 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) struct gfs2_inode *dip = GFS2_I(dir); struct gfs2_sbd *sdp = GFS2_SB(dir); struct gfs2_inode *ip = GFS2_I(dentry->d_inode); - struct gfs2_holder ghs[2]; + struct gfs2_holder ghs[3]; + struct gfs2_rgrpd *rgd; + struct gfs2_holder ri_gh; int error; + + error = gfs2_rindex_hold(sdp, &ri_gh); + if (error) + return error; gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); - error = gfs2_glock_nq_m(2, ghs); + rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr); + gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2); + + error = gfs2_glock_nq_m(3, ghs); if (error) goto out; @@ -483,10 +504,12 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry) gfs2_trans_end(sdp); out_gunlock: - gfs2_glock_dq_m(2, ghs); + gfs2_glock_dq_m(3, ghs); out: gfs2_holder_uninit(ghs); gfs2_holder_uninit(ghs + 1); + gfs2_holder_uninit(ghs + 2); + gfs2_glock_dq_uninit(&ri_gh); return error; } @@ -547,7 +570,8 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, struct gfs2_inode *ip = GFS2_I(odentry->d_inode); struct gfs2_inode *nip = NULL; struct gfs2_sbd *sdp = GFS2_SB(odir); - struct gfs2_holder ghs[4], r_gh; + struct gfs2_holder ghs[5], r_gh; + struct gfs2_rgrpd *nrgd; unsigned int num_gh; int dir_rename = 0; int alloc_required; @@ -587,6 +611,13 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, if (nip) { gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); num_gh++; + /* grab the resource lock for unlink flag twiddling + * this is the case of the target file already existing + * so we unlink before doing the rename + */ + nrgd = gfs2_blk2rgrpd(sdp, nip->i_num.no_addr); + if (nrgd) + gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++); } error = gfs2_glock_nq_m(num_gh, ghs); @@ -684,12 +715,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + al->al_rgd->rd_ri.ri_length + 4 * RES_DINODE + 4 * RES_LEAF + - RES_STATFS + RES_QUOTA, 0); + RES_STATFS + RES_QUOTA + 4, 0); if (error) goto out_ipreserv; } else { error = gfs2_trans_begin(sdp, 4 * RES_DINODE + - 5 * RES_LEAF, 0); + 5 * RES_LEAF + 4, 0); if (error) goto out_gunlock; } @@ -728,7 +759,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, error = gfs2_meta_inode_buffer(ip, &dibh); if (error) goto out_end_trans; - ip->i_inode.i_ctime.tv_sec = get_seconds(); + ip->i_inode.i_ctime = CURRENT_TIME_SEC; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); @@ -1018,7 +1049,7 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, } generic_fillattr(inode, stat); - if (unlock); + if (unlock) gfs2_glock_dq_uninit(&gh); return 0; diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 7685b46f934b..47369d011214 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -173,6 +173,9 @@ static void gfs2_write_super_lockfs(struct super_block *sb) struct gfs2_sbd *sdp = sb->s_fs_info; int error; + if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) + return; + for (;;) { error = gfs2_freeze_fs(sdp); if (!error) @@ -426,6 +429,12 @@ static void gfs2_delete_inode(struct inode *inode) } error = gfs2_dinode_dealloc(ip); + /* + * Must do this before unlock to avoid trying to write back + * potentially dirty data now that inode no longer exists + * on disk. + */ + truncate_inode_pages(&inode->i_data, 0); out_unlock: gfs2_glock_dq(&ip->i_iopen_gh); @@ -443,14 +452,12 @@ out: static struct inode *gfs2_alloc_inode(struct super_block *sb) { - struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_inode *ip; ip = kmem_cache_alloc(gfs2_inode_cachep, GFP_KERNEL); if (ip) { ip->i_flags = 0; ip->i_gl = NULL; - ip->i_greedy = gfs2_tune_get(sdp, gt_greedy_default); ip->i_last_pfault = jiffies; } return &ip->i_inode; diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 45a5f11fc39a..14b380fb0602 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -28,34 +28,13 @@ #include "trans.h" #include "util.h" -static void pfault_be_greedy(struct gfs2_inode *ip) -{ - unsigned int time; - - spin_lock(&ip->i_spin); - time = ip->i_greedy; - ip->i_last_pfault = jiffies; - spin_unlock(&ip->i_spin); - - igrab(&ip->i_inode); - if (gfs2_glock_be_greedy(ip->i_gl, time)) - iput(&ip->i_inode); -} - static struct page *gfs2_private_nopage(struct vm_area_struct *area, unsigned long address, int *type) { struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host); - struct page *result; set_bit(GIF_PAGED, &ip->i_flags); - - result = filemap_nopage(area, address, type); - - if (result && result != NOPAGE_OOM) - pfault_be_greedy(ip); - - return result; + return filemap_nopage(area, address, type); } static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) @@ -167,7 +146,6 @@ static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, set_page_dirty(result); } - pfault_be_greedy(ip); out: gfs2_glock_dq_uninit(&i_gh); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 43a24f2e5905..70f424fcf1cd 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -71,17 +71,12 @@ void gfs2_tune_init(struct gfs2_tune *gt) gt->gt_atime_quantum = 3600; gt->gt_new_files_jdata = 0; gt->gt_new_files_directio = 0; - gt->gt_max_atomic_write = 4 << 20; gt->gt_max_readahead = 1 << 18; gt->gt_lockdump_size = 131072; gt->gt_stall_secs = 600; gt->gt_complain_secs = 10; gt->gt_reclaim_limit = 5000; gt->gt_entries_per_readdir = 32; - gt->gt_prefetch_secs = 10; - gt->gt_greedy_default = HZ / 10; - gt->gt_greedy_quantum = HZ / 40; - gt->gt_greedy_max = HZ / 4; gt->gt_statfs_quantum = 30; gt->gt_statfs_slow = 0; } @@ -359,8 +354,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) mutex_lock(&sdp->sd_jindex_mutex); for (;;) { - error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, - GL_LOCAL_EXCL, ji_gh); + error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, ji_gh); if (error) break; @@ -529,8 +523,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp) struct gfs2_log_header_host head; int error; - error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, - GL_LOCAL_EXCL, &t_gh); + error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &t_gh); if (error) return error; @@ -583,9 +576,8 @@ int gfs2_make_fs_ro(struct gfs2_sbd *sdp) gfs2_quota_sync(sdp); gfs2_statfs_sync(sdp); - error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, - GL_LOCAL_EXCL | GL_NOCACHE, - &t_gh); + error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE, + &t_gh); if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) return error; diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 983eaf1e06be..d01f9f0fda26 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -436,17 +436,12 @@ TUNE_ATTR(atime_quantum, 0); TUNE_ATTR(max_readahead, 0); TUNE_ATTR(complain_secs, 0); TUNE_ATTR(reclaim_limit, 0); -TUNE_ATTR(prefetch_secs, 0); TUNE_ATTR(statfs_slow, 0); TUNE_ATTR(new_files_jdata, 0); TUNE_ATTR(new_files_directio, 0); TUNE_ATTR(quota_simul_sync, 1); TUNE_ATTR(quota_cache_secs, 1); -TUNE_ATTR(max_atomic_write, 1); TUNE_ATTR(stall_secs, 1); -TUNE_ATTR(greedy_default, 1); -TUNE_ATTR(greedy_quantum, 1); -TUNE_ATTR(greedy_max, 1); TUNE_ATTR(statfs_quantum, 1); TUNE_ATTR_DAEMON(scand_secs, scand_process); TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process); @@ -465,15 +460,10 @@ static struct attribute *tune_attrs[] = { &tune_attr_max_readahead.attr, &tune_attr_complain_secs.attr, &tune_attr_reclaim_limit.attr, - &tune_attr_prefetch_secs.attr, &tune_attr_statfs_slow.attr, &tune_attr_quota_simul_sync.attr, &tune_attr_quota_cache_secs.attr, - &tune_attr_max_atomic_write.attr, &tune_attr_stall_secs.attr, - &tune_attr_greedy_default.attr, - &tune_attr_greedy_quantum.attr, - &tune_attr_greedy_max.attr, &tune_attr_statfs_quantum.attr, &tune_attr_scand_secs.attr, &tune_attr_recoverd_secs.attr, diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index f5719117edfe..e285022f006c 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -182,9 +182,9 @@ int jfs_get_block(struct inode *ip, sector_t lblock, * Take appropriate lock on inode */ if (create) - IWRITE_LOCK(ip); + IWRITE_LOCK(ip, RDWRLOCK_NORMAL); else - IREAD_LOCK(ip); + IREAD_LOCK(ip, RDWRLOCK_NORMAL); if (((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size) && (!xtLookup(ip, lblock64, xlen, &xflag, &xaddr, &xlen, 0)) && @@ -359,7 +359,7 @@ void jfs_truncate(struct inode *ip) nobh_truncate_page(ip->i_mapping, ip->i_size); - IWRITE_LOCK(ip); + IWRITE_LOCK(ip, RDWRLOCK_NORMAL); jfs_truncate_nolock(ip, ip->i_size); IWRITE_UNLOCK(ip); } diff --git a/fs/jfs/jfs_debug.h b/fs/jfs/jfs_debug.h index ddffbbd4d955..7378798f0b21 100644 --- a/fs/jfs/jfs_debug.h +++ b/fs/jfs/jfs_debug.h @@ -39,10 +39,6 @@ extern void jfs_proc_clean(void); /* * assert with traditional printf/panic */ -#ifdef CONFIG_KERNEL_ASSERTS -/* kgdb stuff */ -#define assert(p) KERNEL_ASSERT(#p, p) -#else #define assert(p) do { \ if (!(p)) { \ printk(KERN_CRIT "BUG at %s:%d assert(%s)\n", \ @@ -50,7 +46,6 @@ extern void jfs_proc_clean(void); BUG(); \ } \ } while (0) -#endif /* * debug ON diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 23546c8fd48b..82b0544bd76d 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -337,7 +337,7 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks) struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap; - IREAD_LOCK(ipbmap); + IREAD_LOCK(ipbmap, RDWRLOCK_DMAP); /* block to be freed better be within the mapsize. */ if (unlikely((blkno == 0) || (blkno + nblocks > bmp->db_mapsize))) { @@ -733,7 +733,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) * allocation group size, try to allocate anywhere. */ if (l2nb > bmp->db_agl2size) { - IWRITE_LOCK(ipbmap); + IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP); rc = dbAllocAny(bmp, nblocks, l2nb, results); @@ -774,7 +774,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) * the hint using a tiered strategy. */ if (nblocks <= BPERDMAP) { - IREAD_LOCK(ipbmap); + IREAD_LOCK(ipbmap, RDWRLOCK_DMAP); /* get the buffer for the dmap containing the hint. */ @@ -844,7 +844,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) /* try to satisfy the allocation request with blocks within * the same allocation group as the hint. */ - IWRITE_LOCK(ipbmap); + IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP); if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) != -ENOSPC) goto write_unlock; @@ -856,7 +856,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) * Let dbNextAG recommend a preferred allocation group */ agno = dbNextAG(ipbmap); - IWRITE_LOCK(ipbmap); + IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP); /* Try to allocate within this allocation group. if that fails, try to * allocate anywhere in the map. @@ -900,7 +900,7 @@ int dbAllocExact(struct inode *ip, s64 blkno, int nblocks) s64 lblkno; struct metapage *mp; - IREAD_LOCK(ipbmap); + IREAD_LOCK(ipbmap, RDWRLOCK_DMAP); /* * validate extent request: @@ -1050,7 +1050,7 @@ static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) */ extblkno = lastblkno + 1; - IREAD_LOCK(ipbmap); + IREAD_LOCK(ipbmap, RDWRLOCK_DMAP); /* better be within the file system */ bmp = sbi->bmap; @@ -3116,7 +3116,7 @@ int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks) struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap; struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap; - IREAD_LOCK(ipbmap); + IREAD_LOCK(ipbmap, RDWRLOCK_DMAP); /* block to be allocated better be within the mapsize. */ ASSERT(nblocks <= bmp->db_mapsize - blkno); diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index 53f63b47a6d3..aa5124b643b1 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -331,7 +331,7 @@ int diRead(struct inode *ip) /* read the iag */ imap = JFS_IP(ipimap)->i_imap; - IREAD_LOCK(ipimap); + IREAD_LOCK(ipimap, RDWRLOCK_IMAP); rc = diIAGRead(imap, iagno, &mp); IREAD_UNLOCK(ipimap); if (rc) { @@ -920,7 +920,7 @@ int diFree(struct inode *ip) /* Obtain read lock in imap inode. Don't release it until we have * read all of the IAG's that we are going to. */ - IREAD_LOCK(ipimap); + IREAD_LOCK(ipimap, RDWRLOCK_IMAP); /* read the iag. */ @@ -1415,7 +1415,7 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip) AG_LOCK(imap, agno); /* Get read lock on imap inode */ - IREAD_LOCK(ipimap); + IREAD_LOCK(ipimap, RDWRLOCK_IMAP); /* get the iag number and read the iag */ iagno = INOTOIAG(inum); @@ -1808,7 +1808,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip) return -ENOSPC; /* obtain read lock on imap inode */ - IREAD_LOCK(imap->im_ipimap); + IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP); /* read the iag at the head of the list. */ @@ -1946,7 +1946,7 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip) } else { /* read the iag. */ - IREAD_LOCK(imap->im_ipimap); + IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP); if ((rc = diIAGRead(imap, iagno, &mp))) { IREAD_UNLOCK(imap->im_ipimap); jfs_error(ip->i_sb, "diAllocExt: error reading iag"); @@ -2509,7 +2509,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) */ /* acquire inode map lock */ - IWRITE_LOCK(ipimap); + IWRITE_LOCK(ipimap, RDWRLOCK_IMAP); if (ipimap->i_size >> L2PSIZE != imap->im_nextiag + 1) { IWRITE_UNLOCK(ipimap); @@ -2648,7 +2648,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) } /* obtain read lock on map */ - IREAD_LOCK(ipimap); + IREAD_LOCK(ipimap, RDWRLOCK_IMAP); /* read the iag */ if ((rc = diIAGRead(imap, iagno, &mp))) { @@ -2779,7 +2779,7 @@ diUpdatePMap(struct inode *ipimap, return -EIO; } /* read the iag */ - IREAD_LOCK(ipimap); + IREAD_LOCK(ipimap, RDWRLOCK_IMAP); rc = diIAGRead(imap, iagno, &mp); IREAD_UNLOCK(ipimap); if (rc) diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h index 94005584445a..8f453eff3c83 100644 --- a/fs/jfs/jfs_incore.h +++ b/fs/jfs/jfs_incore.h @@ -109,9 +109,11 @@ struct jfs_inode_info { #define JFS_ACL_NOT_CACHED ((void *)-1) -#define IREAD_LOCK(ip) down_read(&JFS_IP(ip)->rdwrlock) +#define IREAD_LOCK(ip, subclass) \ + down_read_nested(&JFS_IP(ip)->rdwrlock, subclass) #define IREAD_UNLOCK(ip) up_read(&JFS_IP(ip)->rdwrlock) -#define IWRITE_LOCK(ip) down_write(&JFS_IP(ip)->rdwrlock) +#define IWRITE_LOCK(ip, subclass) \ + down_write_nested(&JFS_IP(ip)->rdwrlock, subclass) #define IWRITE_UNLOCK(ip) up_write(&JFS_IP(ip)->rdwrlock) /* @@ -127,6 +129,29 @@ enum cflags { COMMIT_Synclist, /* metadata pages on group commit synclist */ }; +/* + * commit_mutex nesting subclasses: + */ +enum commit_mutex_class +{ + COMMIT_MUTEX_PARENT, + COMMIT_MUTEX_CHILD, + COMMIT_MUTEX_SECOND_PARENT, /* Renaming */ + COMMIT_MUTEX_VICTIM /* Inode being unlinked due to rename */ +}; + +/* + * rdwrlock subclasses: + * The dmap inode may be locked while a normal inode or the imap inode are + * locked. + */ +enum rdwrlock_class +{ + RDWRLOCK_NORMAL, + RDWRLOCK_IMAP, + RDWRLOCK_DMAP +}; + #define set_cflag(flag, ip) set_bit(flag, &(JFS_IP(ip)->cflag)) #define clear_cflag(flag, ip) clear_bit(flag, &(JFS_IP(ip)->cflag)) #define test_cflag(flag, ip) test_bit(flag, &(JFS_IP(ip)->cflag)) diff --git a/fs/jfs/jfs_lock.h b/fs/jfs/jfs_lock.h index 7d78e83d7c40..df48ece4b7a3 100644 --- a/fs/jfs/jfs_lock.h +++ b/fs/jfs/jfs_lock.h @@ -42,7 +42,7 @@ do { \ if (cond) \ break; \ unlock_cmd; \ - schedule(); \ + io_schedule(); \ lock_cmd; \ } \ current->state = TASK_RUNNING; \ diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index ceaf03b94935..58deae007507 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -56,7 +56,7 @@ static inline void __lock_metapage(struct metapage *mp) set_current_state(TASK_UNINTERRUPTIBLE); if (metapage_locked(mp)) { unlock_page(mp->page); - schedule(); + io_schedule(); lock_page(mp->page); } } while (trylock_metapage(mp)); diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index d558e51b0df8..6988a1082f58 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -135,7 +135,7 @@ static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event) add_wait_queue(event, &wait); set_current_state(TASK_UNINTERRUPTIBLE); TXN_UNLOCK(); - schedule(); + io_schedule(); current->state = TASK_RUNNING; remove_wait_queue(event, &wait); } diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c index e98eb03e5310..acc97c46d8a4 100644 --- a/fs/jfs/jfs_xtree.c +++ b/fs/jfs/jfs_xtree.c @@ -757,6 +757,11 @@ static int xtSearch(struct inode *ip, s64 xoff, s64 *nextp, nsplit = 0; /* push (bn, index) of the parent page/entry */ + if (BT_STACK_FULL(btstack)) { + jfs_error(ip->i_sb, "stack overrun in xtSearch!"); + XT_PUTPAGE(mp); + return -EIO; + } BT_PUSH(btstack, bn, index); /* get the child page block number */ @@ -3915,6 +3920,11 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag) */ getChild: /* save current parent entry for the child page */ + if (BT_STACK_FULL(&btstack)) { + jfs_error(ip->i_sb, "stack overrun in xtTruncate!"); + XT_PUTPAGE(mp); + return -EIO; + } BT_PUSH(&btstack, bn, index); /* get child page */ @@ -4112,6 +4122,11 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size) */ getChild: /* save current parent entry for the child page */ + if (BT_STACK_FULL(&btstack)) { + jfs_error(ip->i_sb, "stack overrun in xtTruncate_pmap!"); + XT_PUTPAGE(mp); + return -EIO; + } BT_PUSH(&btstack, bn, index); /* get child page */ diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index a6a8c16c872c..7ab47561b68d 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -104,8 +104,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, tid = txBegin(dip->i_sb, 0); - mutex_lock(&JFS_IP(dip)->commit_mutex); - mutex_lock(&JFS_IP(ip)->commit_mutex); + mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT); + mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); rc = jfs_init_acl(tid, ip, dip); if (rc) @@ -238,8 +238,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) tid = txBegin(dip->i_sb, 0); - mutex_lock(&JFS_IP(dip)->commit_mutex); - mutex_lock(&JFS_IP(ip)->commit_mutex); + mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT); + mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); rc = jfs_init_acl(tid, ip, dip); if (rc) @@ -365,8 +365,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) tid = txBegin(dip->i_sb, 0); - mutex_lock(&JFS_IP(dip)->commit_mutex); - mutex_lock(&JFS_IP(ip)->commit_mutex); + mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT); + mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); iplist[0] = dip; iplist[1] = ip; @@ -483,12 +483,12 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) if ((rc = get_UCSname(&dname, dentry))) goto out; - IWRITE_LOCK(ip); + IWRITE_LOCK(ip, RDWRLOCK_NORMAL); tid = txBegin(dip->i_sb, 0); - mutex_lock(&JFS_IP(dip)->commit_mutex); - mutex_lock(&JFS_IP(ip)->commit_mutex); + mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT); + mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); iplist[0] = dip; iplist[1] = ip; @@ -802,8 +802,8 @@ static int jfs_link(struct dentry *old_dentry, tid = txBegin(ip->i_sb, 0); - mutex_lock(&JFS_IP(dir)->commit_mutex); - mutex_lock(&JFS_IP(ip)->commit_mutex); + mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT); + mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); /* * scan parent directory for entry/freespace @@ -913,8 +913,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, tid = txBegin(dip->i_sb, 0); - mutex_lock(&JFS_IP(dip)->commit_mutex); - mutex_lock(&JFS_IP(ip)->commit_mutex); + mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT); + mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); rc = jfs_init_security(tid, ip, dip); if (rc) @@ -1127,7 +1127,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out3; } } else if (new_ip) { - IWRITE_LOCK(new_ip); + IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL); /* Init inode for quota operations. */ DQUOT_INIT(new_ip); } @@ -1137,13 +1137,21 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, */ tid = txBegin(new_dir->i_sb, 0); - mutex_lock(&JFS_IP(new_dir)->commit_mutex); - mutex_lock(&JFS_IP(old_ip)->commit_mutex); + /* + * How do we know the locking is safe from deadlocks? + * The vfs does the hard part for us. Any time we are taking nested + * commit_mutexes, the vfs already has i_mutex held on the parent. + * Here, the vfs has already taken i_mutex on both old_dir and new_dir. + */ + mutex_lock_nested(&JFS_IP(new_dir)->commit_mutex, COMMIT_MUTEX_PARENT); + mutex_lock_nested(&JFS_IP(old_ip)->commit_mutex, COMMIT_MUTEX_CHILD); if (old_dir != new_dir) - mutex_lock(&JFS_IP(old_dir)->commit_mutex); + mutex_lock_nested(&JFS_IP(old_dir)->commit_mutex, + COMMIT_MUTEX_SECOND_PARENT); if (new_ip) { - mutex_lock(&JFS_IP(new_ip)->commit_mutex); + mutex_lock_nested(&JFS_IP(new_ip)->commit_mutex, + COMMIT_MUTEX_VICTIM); /* * Change existing directory entry to new inode number */ @@ -1357,8 +1365,8 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, tid = txBegin(dir->i_sb, 0); - mutex_lock(&JFS_IP(dir)->commit_mutex); - mutex_lock(&JFS_IP(ip)->commit_mutex); + mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT); + mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD); rc = jfs_init_acl(tid, ip, dir); if (rc) diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 277ca67a2ad6..5a9779bb9236 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -184,10 +184,9 @@ static void o2hb_disarm_write_timeout(struct o2hb_region *reg) flush_scheduled_work(); } -static inline void o2hb_bio_wait_init(struct o2hb_bio_wait_ctxt *wc, - unsigned int num_ios) +static inline void o2hb_bio_wait_init(struct o2hb_bio_wait_ctxt *wc) { - atomic_set(&wc->wc_num_reqs, num_ios); + atomic_set(&wc->wc_num_reqs, 1); init_completion(&wc->wc_io_complete); wc->wc_error = 0; } @@ -212,6 +211,7 @@ static void o2hb_wait_on_io(struct o2hb_region *reg, struct address_space *mapping = reg->hr_bdev->bd_inode->i_mapping; blk_run_address_space(mapping); + o2hb_bio_wait_dec(wc, 1); wait_for_completion(&wc->wc_io_complete); } @@ -231,6 +231,7 @@ static int o2hb_bio_end_io(struct bio *bio, return 1; o2hb_bio_wait_dec(wc, 1); + bio_put(bio); return 0; } @@ -238,23 +239,22 @@ static int o2hb_bio_end_io(struct bio *bio, * start_slot. */ static struct bio *o2hb_setup_one_bio(struct o2hb_region *reg, struct o2hb_bio_wait_ctxt *wc, - unsigned int start_slot, - unsigned int num_slots) + unsigned int *current_slot, + unsigned int max_slots) { - int i, nr_vecs, len, first_page, last_page; + int len, current_page; unsigned int vec_len, vec_start; unsigned int bits = reg->hr_block_bits; unsigned int spp = reg->hr_slots_per_page; + unsigned int cs = *current_slot; struct bio *bio; struct page *page; - nr_vecs = (num_slots + spp - 1) / spp; - /* Testing has shown this allocation to take long enough under * GFP_KERNEL that the local node can get fenced. It would be * nicest if we could pre-allocate these bios and avoid this * all together. */ - bio = bio_alloc(GFP_ATOMIC, nr_vecs); + bio = bio_alloc(GFP_ATOMIC, 16); if (!bio) { mlog(ML_ERROR, "Could not alloc slots BIO!\n"); bio = ERR_PTR(-ENOMEM); @@ -262,137 +262,53 @@ static struct bio *o2hb_setup_one_bio(struct o2hb_region *reg, } /* Must put everything in 512 byte sectors for the bio... */ - bio->bi_sector = (reg->hr_start_block + start_slot) << (bits - 9); + bio->bi_sector = (reg->hr_start_block + cs) << (bits - 9); bio->bi_bdev = reg->hr_bdev; bio->bi_private = wc; bio->bi_end_io = o2hb_bio_end_io; - first_page = start_slot / spp; - last_page = first_page + nr_vecs; - vec_start = (start_slot << bits) % PAGE_CACHE_SIZE; - for(i = first_page; i < last_page; i++) { - page = reg->hr_slot_data[i]; + vec_start = (cs << bits) % PAGE_CACHE_SIZE; + while(cs < max_slots) { + current_page = cs / spp; + page = reg->hr_slot_data[current_page]; - vec_len = PAGE_CACHE_SIZE; - /* last page might be short */ - if (((i + 1) * spp) > (start_slot + num_slots)) - vec_len = ((num_slots + start_slot) % spp) << bits; - vec_len -= vec_start; + vec_len = min(PAGE_CACHE_SIZE, + (max_slots-cs) * (PAGE_CACHE_SIZE/spp) ); mlog(ML_HB_BIO, "page %d, vec_len = %u, vec_start = %u\n", - i, vec_len, vec_start); + current_page, vec_len, vec_start); len = bio_add_page(bio, page, vec_len, vec_start); - if (len != vec_len) { - bio_put(bio); - bio = ERR_PTR(-EIO); - - mlog(ML_ERROR, "Error adding page to bio i = %d, " - "vec_len = %u, len = %d\n, start = %u\n", - i, vec_len, len, vec_start); - goto bail; - } + if (len != vec_len) break; + cs += vec_len / (PAGE_CACHE_SIZE/spp); vec_start = 0; } bail: + *current_slot = cs; return bio; } -/* - * Compute the maximum number of sectors the bdev can handle in one bio, - * as a power of two. - * - * Stolen from oracleasm, thanks Joel! - */ -static int compute_max_sectors(struct block_device *bdev) -{ - int max_pages, max_sectors, pow_two_sectors; - - struct request_queue *q; - - q = bdev_get_queue(bdev); - max_pages = q->max_sectors >> (PAGE_SHIFT - 9); - if (max_pages > BIO_MAX_PAGES) - max_pages = BIO_MAX_PAGES; - if (max_pages > q->max_phys_segments) - max_pages = q->max_phys_segments; - if (max_pages > q->max_hw_segments) - max_pages = q->max_hw_segments; - max_pages--; /* Handle I/Os that straddle a page */ - - if (max_pages) { - max_sectors = max_pages << (PAGE_SHIFT - 9); - } else { - /* If BIO contains 1 or less than 1 page. */ - max_sectors = q->max_sectors; - } - /* Why is fls() 1-based???? */ - pow_two_sectors = 1 << (fls(max_sectors) - 1); - - return pow_two_sectors; -} - -static inline void o2hb_compute_request_limits(struct o2hb_region *reg, - unsigned int num_slots, - unsigned int *num_bios, - unsigned int *slots_per_bio) -{ - unsigned int max_sectors, io_sectors; - - max_sectors = compute_max_sectors(reg->hr_bdev); - - io_sectors = num_slots << (reg->hr_block_bits - 9); - - *num_bios = (io_sectors + max_sectors - 1) / max_sectors; - *slots_per_bio = max_sectors >> (reg->hr_block_bits - 9); - - mlog(ML_HB_BIO, "My io size is %u sectors for %u slots. This " - "device can handle %u sectors of I/O\n", io_sectors, num_slots, - max_sectors); - mlog(ML_HB_BIO, "Will need %u bios holding %u slots each\n", - *num_bios, *slots_per_bio); -} - static int o2hb_read_slots(struct o2hb_region *reg, unsigned int max_slots) { - unsigned int num_bios, slots_per_bio, start_slot, num_slots; - int i, status; + unsigned int current_slot=0; + int status; struct o2hb_bio_wait_ctxt wc; - struct bio **bios; struct bio *bio; - o2hb_compute_request_limits(reg, max_slots, &num_bios, &slots_per_bio); + o2hb_bio_wait_init(&wc); - bios = kcalloc(num_bios, sizeof(struct bio *), GFP_KERNEL); - if (!bios) { - status = -ENOMEM; - mlog_errno(status); - return status; - } - - o2hb_bio_wait_init(&wc, num_bios); - - num_slots = slots_per_bio; - for(i = 0; i < num_bios; i++) { - start_slot = i * slots_per_bio; - - /* adjust num_slots at last bio */ - if (max_slots < (start_slot + num_slots)) - num_slots = max_slots - start_slot; - - bio = o2hb_setup_one_bio(reg, &wc, start_slot, num_slots); + while(current_slot < max_slots) { + bio = o2hb_setup_one_bio(reg, &wc, ¤t_slot, max_slots); if (IS_ERR(bio)) { - o2hb_bio_wait_dec(&wc, num_bios - i); - status = PTR_ERR(bio); mlog_errno(status); goto bail_and_wait; } - bios[i] = bio; + atomic_inc(&wc.wc_num_reqs); submit_bio(READ, bio); } @@ -403,38 +319,30 @@ bail_and_wait: if (wc.wc_error && !status) status = wc.wc_error; - if (bios) { - for(i = 0; i < num_bios; i++) - if (bios[i]) - bio_put(bios[i]); - kfree(bios); - } - return status; } static int o2hb_issue_node_write(struct o2hb_region *reg, - struct bio **write_bio, struct o2hb_bio_wait_ctxt *write_wc) { int status; unsigned int slot; struct bio *bio; - o2hb_bio_wait_init(write_wc, 1); + o2hb_bio_wait_init(write_wc); slot = o2nm_this_node(); - bio = o2hb_setup_one_bio(reg, write_wc, slot, 1); + bio = o2hb_setup_one_bio(reg, write_wc, &slot, slot+1); if (IS_ERR(bio)) { status = PTR_ERR(bio); mlog_errno(status); goto bail; } + atomic_inc(&write_wc->wc_num_reqs); submit_bio(WRITE, bio); - *write_bio = bio; status = 0; bail: return status; @@ -826,7 +734,6 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg) { int i, ret, highest_node, change = 0; unsigned long configured_nodes[BITS_TO_LONGS(O2NM_MAX_NODES)]; - struct bio *write_bio; struct o2hb_bio_wait_ctxt write_wc; ret = o2nm_configured_node_map(configured_nodes, @@ -864,7 +771,7 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg) /* And fire off the write. Note that we don't wait on this I/O * until later. */ - ret = o2hb_issue_node_write(reg, &write_bio, &write_wc); + ret = o2hb_issue_node_write(reg, &write_wc); if (ret < 0) { mlog_errno(ret); return ret; @@ -882,7 +789,6 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg) * people we find in our steady state have seen us. */ o2hb_wait_on_io(reg, &write_wc); - bio_put(write_bio); if (write_wc.wc_error) { /* Do not re-arm the write timeout on I/O error - we * can't be sure that the new block ever made it to @@ -943,7 +849,6 @@ static int o2hb_thread(void *data) { int i, ret; struct o2hb_region *reg = data; - struct bio *write_bio; struct o2hb_bio_wait_ctxt write_wc; struct timeval before_hb, after_hb; unsigned int elapsed_msec; @@ -993,10 +898,9 @@ static int o2hb_thread(void *data) * * XXX: Should we skip this on unclean_stop? */ o2hb_prepare_block(reg, 0); - ret = o2hb_issue_node_write(reg, &write_bio, &write_wc); + ret = o2hb_issue_node_write(reg, &write_wc); if (ret == 0) { o2hb_wait_on_io(reg, &write_wc); - bio_put(write_bio); } else { mlog_errno(ret); } diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index ae4ff4a6636b..1718215fc018 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -556,6 +556,8 @@ static void o2net_register_callbacks(struct sock *sk, sk->sk_data_ready = o2net_data_ready; sk->sk_state_change = o2net_state_change; + mutex_init(&sc->sc_send_lock); + write_unlock_bh(&sk->sk_callback_lock); } @@ -688,6 +690,7 @@ static void o2net_handler_put(struct o2net_msg_handler *nmh) * be given to the handler if their payload is longer than the max. */ int o2net_register_handler(u32 msg_type, u32 key, u32 max_len, o2net_msg_handler_func *func, void *data, + o2net_post_msg_handler_func *post_func, struct list_head *unreg_list) { struct o2net_msg_handler *nmh = NULL; @@ -722,6 +725,7 @@ int o2net_register_handler(u32 msg_type, u32 key, u32 max_len, nmh->nh_func = func; nmh->nh_func_data = data; + nmh->nh_post_func = post_func; nmh->nh_msg_type = msg_type; nmh->nh_max_len = max_len; nmh->nh_key = key; @@ -856,10 +860,12 @@ static void o2net_sendpage(struct o2net_sock_container *sc, ssize_t ret; + mutex_lock(&sc->sc_send_lock); ret = sc->sc_sock->ops->sendpage(sc->sc_sock, virt_to_page(kmalloced_virt), (long)kmalloced_virt & ~PAGE_MASK, size, MSG_DONTWAIT); + mutex_unlock(&sc->sc_send_lock); if (ret != size) { mlog(ML_ERROR, "sendpage of size %zu to " SC_NODEF_FMT " failed with %zd\n", size, SC_NODEF_ARGS(sc), ret); @@ -974,8 +980,10 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, /* finally, convert the message header to network byte-order * and send */ + mutex_lock(&sc->sc_send_lock); ret = o2net_send_tcp_msg(sc->sc_sock, vec, veclen, sizeof(struct o2net_msg) + caller_bytes); + mutex_unlock(&sc->sc_send_lock); msglog(msg, "sending returned %d\n", ret); if (ret < 0) { mlog(0, "error returned from o2net_send_tcp_msg=%d\n", ret); @@ -1049,6 +1057,7 @@ static int o2net_process_message(struct o2net_sock_container *sc, int ret = 0, handler_status; enum o2net_system_error syserr; struct o2net_msg_handler *nmh = NULL; + void *ret_data = NULL; msglog(hdr, "processing message\n"); @@ -1101,17 +1110,26 @@ static int o2net_process_message(struct o2net_sock_container *sc, sc->sc_msg_type = be16_to_cpu(hdr->msg_type); handler_status = (nmh->nh_func)(hdr, sizeof(struct o2net_msg) + be16_to_cpu(hdr->data_len), - nmh->nh_func_data); + nmh->nh_func_data, &ret_data); do_gettimeofday(&sc->sc_tv_func_stop); out_respond: /* this destroys the hdr, so don't use it after this */ + mutex_lock(&sc->sc_send_lock); ret = o2net_send_status_magic(sc->sc_sock, hdr, syserr, handler_status); + mutex_unlock(&sc->sc_send_lock); hdr = NULL; mlog(0, "sending handler status %d, syserr %d returned %d\n", handler_status, syserr, ret); + if (nmh) { + BUG_ON(ret_data != NULL && nmh->nh_post_func == NULL); + if (nmh->nh_post_func) + (nmh->nh_post_func)(handler_status, nmh->nh_func_data, + ret_data); + } + out: if (nmh) o2net_handler_put(nmh); @@ -1795,13 +1813,13 @@ out: ready(sk, bytes); } -static int o2net_open_listening_sock(__be16 port) +static int o2net_open_listening_sock(__be32 addr, __be16 port) { struct socket *sock = NULL; int ret; struct sockaddr_in sin = { .sin_family = PF_INET, - .sin_addr = { .s_addr = (__force u32)htonl(INADDR_ANY) }, + .sin_addr = { .s_addr = (__force u32)addr }, .sin_port = (__force u16)port, }; @@ -1824,15 +1842,15 @@ static int o2net_open_listening_sock(__be16 port) sock->sk->sk_reuse = 1; ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin)); if (ret < 0) { - mlog(ML_ERROR, "unable to bind socket to port %d, ret=%d\n", - ntohs(port), ret); + mlog(ML_ERROR, "unable to bind socket at %u.%u.%u.%u:%u, " + "ret=%d\n", NIPQUAD(addr), ntohs(port), ret); goto out; } ret = sock->ops->listen(sock, 64); if (ret < 0) { - mlog(ML_ERROR, "unable to listen on port %d, ret=%d\n", - ntohs(port), ret); + mlog(ML_ERROR, "unable to listen on %u.%u.%u.%u:%u, ret=%d\n", + NIPQUAD(addr), ntohs(port), ret); } out: @@ -1865,7 +1883,8 @@ int o2net_start_listening(struct o2nm_node *node) return -ENOMEM; /* ? */ } - ret = o2net_open_listening_sock(node->nd_ipv4_port); + ret = o2net_open_listening_sock(node->nd_ipv4_address, + node->nd_ipv4_port); if (ret) { destroy_workqueue(o2net_wq); o2net_wq = NULL; diff --git a/fs/ocfs2/cluster/tcp.h b/fs/ocfs2/cluster/tcp.h index 21a4e43df836..da880fc215f0 100644 --- a/fs/ocfs2/cluster/tcp.h +++ b/fs/ocfs2/cluster/tcp.h @@ -50,7 +50,10 @@ struct o2net_msg __u8 buf[0]; }; -typedef int (o2net_msg_handler_func)(struct o2net_msg *msg, u32 len, void *data); +typedef int (o2net_msg_handler_func)(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +typedef void (o2net_post_msg_handler_func)(int status, void *data, + void *ret_data); #define O2NET_MAX_PAYLOAD_BYTES (4096 - sizeof(struct o2net_msg)) @@ -99,6 +102,7 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *vec, int o2net_register_handler(u32 msg_type, u32 key, u32 max_len, o2net_msg_handler_func *func, void *data, + o2net_post_msg_handler_func *post_func, struct list_head *unreg_list); void o2net_unregister_handler_list(struct list_head *list); diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h index b700dc9624d1..4dae5df5e467 100644 --- a/fs/ocfs2/cluster/tcp_internal.h +++ b/fs/ocfs2/cluster/tcp_internal.h @@ -38,6 +38,12 @@ * locking semantics of the file system using the protocol. It should * be somewhere else, I'm sure, but right now it isn't. * + * New in version 7: + * - DLM join domain includes the live nodemap + * + * New in version 6: + * - DLM lockres remote refcount fixes. + * * New in version 5: * - Network timeout checking protocol * @@ -51,7 +57,7 @@ * - full 64 bit i_size in the metadata lock lvbs * - introduction of "rw" lock and pushing meta/data locking down */ -#define O2NET_PROTOCOL_VERSION 5ULL +#define O2NET_PROTOCOL_VERSION 7ULL struct o2net_handshake { __be64 protocol_version; __be64 connector_id; @@ -149,6 +155,8 @@ struct o2net_sock_container { struct timeval sc_tv_func_stop; u32 sc_msg_key; u16 sc_msg_type; + + struct mutex sc_send_lock; }; struct o2net_msg_handler { @@ -158,6 +166,8 @@ struct o2net_msg_handler { u32 nh_key; o2net_msg_handler_func *nh_func; o2net_msg_handler_func *nh_func_data; + o2net_post_msg_handler_func + *nh_post_func; struct kref nh_kref; struct list_head nh_unregister_item; }; diff --git a/fs/ocfs2/dlm/dlmast.c b/fs/ocfs2/dlm/dlmast.c index 681046d51393..241cad342a48 100644 --- a/fs/ocfs2/dlm/dlmast.c +++ b/fs/ocfs2/dlm/dlmast.c @@ -263,7 +263,8 @@ void dlm_do_local_bast(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, -int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data) +int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { int ret; unsigned int locklen; @@ -311,8 +312,8 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data) past->type != DLM_BAST) { mlog(ML_ERROR, "Unknown ast type! %d, cookie=%u:%llu" "name=%.*s\n", past->type, - dlm_get_lock_cookie_node(cookie), - dlm_get_lock_cookie_seq(cookie), + dlm_get_lock_cookie_node(be64_to_cpu(cookie)), + dlm_get_lock_cookie_seq(be64_to_cpu(cookie)), locklen, name); ret = DLM_IVLOCKID; goto leave; @@ -323,8 +324,8 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data) mlog(0, "got %sast for unknown lockres! " "cookie=%u:%llu, name=%.*s, namelen=%u\n", past->type == DLM_AST ? "" : "b", - dlm_get_lock_cookie_node(cookie), - dlm_get_lock_cookie_seq(cookie), + dlm_get_lock_cookie_node(be64_to_cpu(cookie)), + dlm_get_lock_cookie_seq(be64_to_cpu(cookie)), locklen, name, locklen); ret = DLM_IVLOCKID; goto leave; @@ -369,7 +370,8 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data) mlog(0, "got %sast for unknown lock! cookie=%u:%llu, " "name=%.*s, namelen=%u\n", past->type == DLM_AST ? "" : "b", - dlm_get_lock_cookie_node(cookie), dlm_get_lock_cookie_seq(cookie), + dlm_get_lock_cookie_node(be64_to_cpu(cookie)), + dlm_get_lock_cookie_seq(be64_to_cpu(cookie)), locklen, name, locklen); ret = DLM_NORMAL; diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h index 6b6ff76538c5..e90b92f9ece1 100644 --- a/fs/ocfs2/dlm/dlmcommon.h +++ b/fs/ocfs2/dlm/dlmcommon.h @@ -180,6 +180,11 @@ struct dlm_assert_master_priv unsigned ignore_higher:1; }; +struct dlm_deref_lockres_priv +{ + struct dlm_lock_resource *deref_res; + u8 deref_node; +}; struct dlm_work_item { @@ -191,6 +196,7 @@ struct dlm_work_item struct dlm_request_all_locks_priv ral; struct dlm_mig_lockres_priv ml; struct dlm_assert_master_priv am; + struct dlm_deref_lockres_priv dl; } u; }; @@ -222,6 +228,9 @@ static inline void __dlm_set_joining_node(struct dlm_ctxt *dlm, #define DLM_LOCK_RES_DIRTY 0x00000008 #define DLM_LOCK_RES_IN_PROGRESS 0x00000010 #define DLM_LOCK_RES_MIGRATING 0x00000020 +#define DLM_LOCK_RES_DROPPING_REF 0x00000040 +#define DLM_LOCK_RES_BLOCK_DIRTY 0x00001000 +#define DLM_LOCK_RES_SETREF_INPROG 0x00002000 /* max milliseconds to wait to sync up a network failure with a node death */ #define DLM_NODE_DEATH_WAIT_MAX (5 * 1000) @@ -265,6 +274,8 @@ struct dlm_lock_resource u8 owner; //node which owns the lock resource, or unknown u16 state; char lvb[DLM_LVB_LEN]; + unsigned int inflight_locks; + unsigned long refmap[BITS_TO_LONGS(O2NM_MAX_NODES)]; }; struct dlm_migratable_lock @@ -367,7 +378,7 @@ enum { DLM_CONVERT_LOCK_MSG, /* 504 */ DLM_PROXY_AST_MSG, /* 505 */ DLM_UNLOCK_LOCK_MSG, /* 506 */ - DLM_UNUSED_MSG2, /* 507 */ + DLM_DEREF_LOCKRES_MSG, /* 507 */ DLM_MIGRATE_REQUEST_MSG, /* 508 */ DLM_MIG_LOCKRES_MSG, /* 509 */ DLM_QUERY_JOIN_MSG, /* 510 */ @@ -417,6 +428,9 @@ struct dlm_master_request u8 name[O2NM_MAX_NAME_LEN]; }; +#define DLM_ASSERT_RESPONSE_REASSERT 0x00000001 +#define DLM_ASSERT_RESPONSE_MASTERY_REF 0x00000002 + #define DLM_ASSERT_MASTER_MLE_CLEANUP 0x00000001 #define DLM_ASSERT_MASTER_REQUERY 0x00000002 #define DLM_ASSERT_MASTER_FINISH_MIGRATION 0x00000004 @@ -430,6 +444,8 @@ struct dlm_assert_master u8 name[O2NM_MAX_NAME_LEN]; }; +#define DLM_MIGRATE_RESPONSE_MASTERY_REF 0x00000001 + struct dlm_migrate_request { u8 master; @@ -609,12 +625,16 @@ struct dlm_begin_reco }; +#define BITS_PER_BYTE 8 +#define BITS_TO_BYTES(bits) (((bits)+BITS_PER_BYTE-1)/BITS_PER_BYTE) + struct dlm_query_join_request { u8 node_idx; u8 pad1[2]; u8 name_len; u8 domain[O2NM_MAX_NAME_LEN]; + u8 node_map[BITS_TO_BYTES(O2NM_MAX_NODES)]; }; struct dlm_assert_joined @@ -648,6 +668,16 @@ struct dlm_finalize_reco __be32 pad2; }; +struct dlm_deref_lockres +{ + u32 pad1; + u16 pad2; + u8 node_idx; + u8 namelen; + + u8 name[O2NM_MAX_NAME_LEN]; +}; + static inline enum dlm_status __dlm_lockres_state_to_status(struct dlm_lock_resource *res) { @@ -688,16 +718,20 @@ void dlm_lock_put(struct dlm_lock *lock); void dlm_lock_attach_lockres(struct dlm_lock *lock, struct dlm_lock_resource *res); -int dlm_create_lock_handler(struct o2net_msg *msg, u32 len, void *data); -int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data); -int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data); +int dlm_create_lock_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); void dlm_revert_pending_convert(struct dlm_lock_resource *res, struct dlm_lock *lock); void dlm_revert_pending_lock(struct dlm_lock_resource *res, struct dlm_lock *lock); -int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data); +int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); void dlm_commit_pending_cancel(struct dlm_lock_resource *res, struct dlm_lock *lock); void dlm_commit_pending_unlock(struct dlm_lock_resource *res, @@ -721,8 +755,6 @@ void __dlm_lockres_calc_usage(struct dlm_ctxt *dlm, struct dlm_lock_resource *res); void dlm_lockres_calc_usage(struct dlm_ctxt *dlm, struct dlm_lock_resource *res); -void dlm_purge_lockres(struct dlm_ctxt *dlm, - struct dlm_lock_resource *lockres); static inline void dlm_lockres_get(struct dlm_lock_resource *res) { /* This is called on every lookup, so it might be worth @@ -733,6 +765,10 @@ void dlm_lockres_put(struct dlm_lock_resource *res); void __dlm_unhash_lockres(struct dlm_lock_resource *res); void __dlm_insert_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res); +struct dlm_lock_resource * __dlm_lookup_lockres_full(struct dlm_ctxt *dlm, + const char *name, + unsigned int len, + unsigned int hash); struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm, const char *name, unsigned int len, @@ -753,6 +789,47 @@ struct dlm_lock_resource *dlm_new_lockres(struct dlm_ctxt *dlm, const char *name, unsigned int namelen); +#define dlm_lockres_set_refmap_bit(bit,res) \ + __dlm_lockres_set_refmap_bit(bit,res,__FILE__,__LINE__) +#define dlm_lockres_clear_refmap_bit(bit,res) \ + __dlm_lockres_clear_refmap_bit(bit,res,__FILE__,__LINE__) + +static inline void __dlm_lockres_set_refmap_bit(int bit, + struct dlm_lock_resource *res, + const char *file, + int line) +{ + //printk("%s:%d:%.*s: setting bit %d\n", file, line, + // res->lockname.len, res->lockname.name, bit); + set_bit(bit, res->refmap); +} + +static inline void __dlm_lockres_clear_refmap_bit(int bit, + struct dlm_lock_resource *res, + const char *file, + int line) +{ + //printk("%s:%d:%.*s: clearing bit %d\n", file, line, + // res->lockname.len, res->lockname.name, bit); + clear_bit(bit, res->refmap); +} + +void __dlm_lockres_drop_inflight_ref(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res, + const char *file, + int line); +void __dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res, + int new_lockres, + const char *file, + int line); +#define dlm_lockres_drop_inflight_ref(d,r) \ + __dlm_lockres_drop_inflight_ref(d,r,__FILE__,__LINE__) +#define dlm_lockres_grab_inflight_ref(d,r) \ + __dlm_lockres_grab_inflight_ref(d,r,0,__FILE__,__LINE__) +#define dlm_lockres_grab_inflight_ref_new(d,r) \ + __dlm_lockres_grab_inflight_ref(d,r,1,__FILE__,__LINE__) + void dlm_queue_ast(struct dlm_ctxt *dlm, struct dlm_lock *lock); void dlm_queue_bast(struct dlm_ctxt *dlm, struct dlm_lock *lock); void dlm_do_local_ast(struct dlm_ctxt *dlm, @@ -801,10 +878,7 @@ int dlm_heartbeat_init(struct dlm_ctxt *dlm); void dlm_hb_node_down_cb(struct o2nm_node *node, int idx, void *data); void dlm_hb_node_up_cb(struct o2nm_node *node, int idx, void *data); -int dlm_lockres_is_dirty(struct dlm_ctxt *dlm, struct dlm_lock_resource *res); -int dlm_migrate_lockres(struct dlm_ctxt *dlm, - struct dlm_lock_resource *res, - u8 target); +int dlm_empty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res); int dlm_finish_migration(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, u8 old_master); @@ -812,15 +886,27 @@ void dlm_lockres_release_ast(struct dlm_ctxt *dlm, struct dlm_lock_resource *res); void __dlm_lockres_reserve_ast(struct dlm_lock_resource *res); -int dlm_master_request_handler(struct o2net_msg *msg, u32 len, void *data); -int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data); -int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data); -int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data); -int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data); -int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data); -int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data); -int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data); -int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data); +int dlm_master_request_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +void dlm_assert_master_post_handler(int status, void *data, void *ret_data); +int dlm_deref_lockres_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); int dlm_do_master_requery(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, u8 nodenum, u8 *real_master); @@ -856,10 +942,12 @@ static inline void __dlm_wait_on_lockres(struct dlm_lock_resource *res) int dlm_init_mle_cache(void); void dlm_destroy_mle_cache(void); void dlm_hb_event_notify_attached(struct dlm_ctxt *dlm, int idx, int node_up); +int dlm_drop_lockres_ref(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res); void dlm_clean_master_list(struct dlm_ctxt *dlm, u8 dead_node); int dlm_lock_basts_flushed(struct dlm_ctxt *dlm, struct dlm_lock *lock); - +int __dlm_lockres_has_locks(struct dlm_lock_resource *res); int __dlm_lockres_unused(struct dlm_lock_resource *res); static inline const char * dlm_lock_mode_name(int mode) diff --git a/fs/ocfs2/dlm/dlmconvert.c b/fs/ocfs2/dlm/dlmconvert.c index c764dc8e40a2..ecb4d997221e 100644 --- a/fs/ocfs2/dlm/dlmconvert.c +++ b/fs/ocfs2/dlm/dlmconvert.c @@ -286,8 +286,8 @@ enum dlm_status dlmconvert_remote(struct dlm_ctxt *dlm, __dlm_print_one_lock_resource(res); mlog(ML_ERROR, "converting a remote lock that is already " "converting! (cookie=%u:%llu, conv=%d)\n", - dlm_get_lock_cookie_node(lock->ml.cookie), - dlm_get_lock_cookie_seq(lock->ml.cookie), + dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), + dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)), lock->ml.convert_type); status = DLM_DENIED; goto bail; @@ -418,7 +418,8 @@ static enum dlm_status dlm_send_remote_convert_request(struct dlm_ctxt *dlm, * returns: DLM_NORMAL, DLM_IVLOCKID, DLM_BADARGS, * status from __dlmconvert_master */ -int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data) +int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_ctxt *dlm = data; struct dlm_convert_lock *cnv = (struct dlm_convert_lock *)msg->buf; @@ -428,7 +429,7 @@ int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data) struct dlm_lockstatus *lksb; enum dlm_status status = DLM_NORMAL; u32 flags; - int call_ast = 0, kick_thread = 0, ast_reserved = 0; + int call_ast = 0, kick_thread = 0, ast_reserved = 0, wake = 0; if (!dlm_grab(dlm)) { dlm_error(DLM_REJECTED); @@ -479,25 +480,14 @@ int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data) } lock = NULL; } - if (!lock) { - __dlm_print_one_lock_resource(res); - list_for_each(iter, &res->granted) { - lock = list_entry(iter, struct dlm_lock, list); - if (lock->ml.node == cnv->node_idx) { - mlog(ML_ERROR, "There is something here " - "for node %u, lock->ml.cookie=%llu, " - "cnv->cookie=%llu\n", cnv->node_idx, - (unsigned long long)lock->ml.cookie, - (unsigned long long)cnv->cookie); - break; - } - } - lock = NULL; - } spin_unlock(&res->spinlock); if (!lock) { status = DLM_IVLOCKID; - dlm_error(status); + mlog(ML_ERROR, "did not find lock to convert on grant queue! " + "cookie=%u:%llu\n", + dlm_get_lock_cookie_node(be64_to_cpu(cnv->cookie)), + dlm_get_lock_cookie_seq(be64_to_cpu(cnv->cookie))); + __dlm_print_one_lock_resource(res); goto leave; } @@ -524,8 +514,11 @@ int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data) cnv->requested_type, &call_ast, &kick_thread); res->state &= ~DLM_LOCK_RES_IN_PROGRESS; + wake = 1; } spin_unlock(&res->spinlock); + if (wake) + wake_up(&res->wq); if (status != DLM_NORMAL) { if (status != DLM_NOTQUEUED) @@ -534,12 +527,7 @@ int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data) } leave: - if (!lock) - mlog(ML_ERROR, "did not find lock to convert on grant queue! " - "cookie=%u:%llu\n", - dlm_get_lock_cookie_node(cnv->cookie), - dlm_get_lock_cookie_seq(cnv->cookie)); - else + if (lock) dlm_lock_put(lock); /* either queue the ast or release it, if reserved */ diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c index 3f6c8d88f7af..64239b37e5d4 100644 --- a/fs/ocfs2/dlm/dlmdebug.c +++ b/fs/ocfs2/dlm/dlmdebug.c @@ -53,6 +53,23 @@ void dlm_print_one_lock_resource(struct dlm_lock_resource *res) spin_unlock(&res->spinlock); } +static void dlm_print_lockres_refmap(struct dlm_lock_resource *res) +{ + int bit; + assert_spin_locked(&res->spinlock); + + mlog(ML_NOTICE, " refmap nodes: [ "); + bit = 0; + while (1) { + bit = find_next_bit(res->refmap, O2NM_MAX_NODES, bit); + if (bit >= O2NM_MAX_NODES) + break; + printk("%u ", bit); + bit++; + } + printk("], inflight=%u\n", res->inflight_locks); +} + void __dlm_print_one_lock_resource(struct dlm_lock_resource *res) { struct list_head *iter2; @@ -65,6 +82,7 @@ void __dlm_print_one_lock_resource(struct dlm_lock_resource *res) res->owner, res->state); mlog(ML_NOTICE, " last used: %lu, on purge list: %s\n", res->last_used, list_empty(&res->purge) ? "no" : "yes"); + dlm_print_lockres_refmap(res); mlog(ML_NOTICE, " granted queue: \n"); list_for_each(iter2, &res->granted) { lock = list_entry(iter2, struct dlm_lock, list); @@ -72,8 +90,8 @@ void __dlm_print_one_lock_resource(struct dlm_lock_resource *res) mlog(ML_NOTICE, " type=%d, conv=%d, node=%u, " "cookie=%u:%llu, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c)\n", lock->ml.type, lock->ml.convert_type, lock->ml.node, - dlm_get_lock_cookie_node(lock->ml.cookie), - dlm_get_lock_cookie_seq(lock->ml.cookie), + dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), + dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)), list_empty(&lock->ast_list) ? 'y' : 'n', lock->ast_pending ? 'y' : 'n', list_empty(&lock->bast_list) ? 'y' : 'n', @@ -87,8 +105,8 @@ void __dlm_print_one_lock_resource(struct dlm_lock_resource *res) mlog(ML_NOTICE, " type=%d, conv=%d, node=%u, " "cookie=%u:%llu, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c)\n", lock->ml.type, lock->ml.convert_type, lock->ml.node, - dlm_get_lock_cookie_node(lock->ml.cookie), - dlm_get_lock_cookie_seq(lock->ml.cookie), + dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), + dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)), list_empty(&lock->ast_list) ? 'y' : 'n', lock->ast_pending ? 'y' : 'n', list_empty(&lock->bast_list) ? 'y' : 'n', @@ -102,8 +120,8 @@ void __dlm_print_one_lock_resource(struct dlm_lock_resource *res) mlog(ML_NOTICE, " type=%d, conv=%d, node=%u, " "cookie=%u:%llu, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c)\n", lock->ml.type, lock->ml.convert_type, lock->ml.node, - dlm_get_lock_cookie_node(lock->ml.cookie), - dlm_get_lock_cookie_seq(lock->ml.cookie), + dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), + dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)), list_empty(&lock->ast_list) ? 'y' : 'n', lock->ast_pending ? 'y' : 'n', list_empty(&lock->bast_list) ? 'y' : 'n', diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index f0b25f2dd205..6087c4749fee 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -48,6 +48,36 @@ #define MLOG_MASK_PREFIX (ML_DLM|ML_DLM_DOMAIN) #include "cluster/masklog.h" +/* + * ocfs2 node maps are array of long int, which limits to send them freely + * across the wire due to endianness issues. To workaround this, we convert + * long ints to byte arrays. Following 3 routines are helper functions to + * set/test/copy bits within those array of bytes + */ +static inline void byte_set_bit(u8 nr, u8 map[]) +{ + map[nr >> 3] |= (1UL << (nr & 7)); +} + +static inline int byte_test_bit(u8 nr, u8 map[]) +{ + return ((1UL << (nr & 7)) & (map[nr >> 3])) != 0; +} + +static inline void byte_copymap(u8 dmap[], unsigned long smap[], + unsigned int sz) +{ + unsigned int nn; + + if (!sz) + return; + + memset(dmap, 0, ((sz + 7) >> 3)); + for (nn = 0 ; nn < sz; nn++) + if (test_bit(nn, smap)) + byte_set_bit(nn, dmap); +} + static void dlm_free_pagevec(void **vec, int pages) { while (pages--) @@ -95,10 +125,14 @@ static DECLARE_WAIT_QUEUE_HEAD(dlm_domain_events); #define DLM_DOMAIN_BACKOFF_MS 200 -static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data); -static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data); -static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data); -static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data); +static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); +static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data); static void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm); @@ -125,10 +159,10 @@ void __dlm_insert_lockres(struct dlm_ctxt *dlm, hlist_add_head(&res->hash_node, bucket); } -struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm, - const char *name, - unsigned int len, - unsigned int hash) +struct dlm_lock_resource * __dlm_lookup_lockres_full(struct dlm_ctxt *dlm, + const char *name, + unsigned int len, + unsigned int hash) { struct hlist_head *bucket; struct hlist_node *list; @@ -154,6 +188,37 @@ struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm, return NULL; } +/* intended to be called by functions which do not care about lock + * resources which are being purged (most net _handler functions). + * this will return NULL for any lock resource which is found but + * currently in the process of dropping its mastery reference. + * use __dlm_lookup_lockres_full when you need the lock resource + * regardless (e.g. dlm_get_lock_resource) */ +struct dlm_lock_resource * __dlm_lookup_lockres(struct dlm_ctxt *dlm, + const char *name, + unsigned int len, + unsigned int hash) +{ + struct dlm_lock_resource *res = NULL; + + mlog_entry("%.*s\n", len, name); + + assert_spin_locked(&dlm->spinlock); + + res = __dlm_lookup_lockres_full(dlm, name, len, hash); + if (res) { + spin_lock(&res->spinlock); + if (res->state & DLM_LOCK_RES_DROPPING_REF) { + spin_unlock(&res->spinlock); + dlm_lockres_put(res); + return NULL; + } + spin_unlock(&res->spinlock); + } + + return res; +} + struct dlm_lock_resource * dlm_lookup_lockres(struct dlm_ctxt *dlm, const char *name, unsigned int len) @@ -330,43 +395,60 @@ static void dlm_complete_dlm_shutdown(struct dlm_ctxt *dlm) wake_up(&dlm_domain_events); } -static void dlm_migrate_all_locks(struct dlm_ctxt *dlm) +static int dlm_migrate_all_locks(struct dlm_ctxt *dlm) { - int i; + int i, num, n, ret = 0; struct dlm_lock_resource *res; + struct hlist_node *iter; + struct hlist_head *bucket; + int dropped; mlog(0, "Migrating locks from domain %s\n", dlm->name); -restart: + + num = 0; spin_lock(&dlm->spinlock); for (i = 0; i < DLM_HASH_BUCKETS; i++) { - while (!hlist_empty(dlm_lockres_hash(dlm, i))) { - res = hlist_entry(dlm_lockres_hash(dlm, i)->first, - struct dlm_lock_resource, hash_node); - /* need reference when manually grabbing lockres */ +redo_bucket: + n = 0; + bucket = dlm_lockres_hash(dlm, i); + iter = bucket->first; + while (iter) { + n++; + res = hlist_entry(iter, struct dlm_lock_resource, + hash_node); dlm_lockres_get(res); - /* this should unhash the lockres - * and exit with dlm->spinlock */ - mlog(0, "purging res=%p\n", res); - if (dlm_lockres_is_dirty(dlm, res)) { - /* HACK! this should absolutely go. - * need to figure out why some empty - * lockreses are still marked dirty */ - mlog(ML_ERROR, "lockres %.*s dirty!\n", - res->lockname.len, res->lockname.name); + /* migrate, if necessary. this will drop the dlm + * spinlock and retake it if it does migration. */ + dropped = dlm_empty_lockres(dlm, res); + + spin_lock(&res->spinlock); + __dlm_lockres_calc_usage(dlm, res); + iter = res->hash_node.next; + spin_unlock(&res->spinlock); - spin_unlock(&dlm->spinlock); - dlm_kick_thread(dlm, res); - wait_event(dlm->ast_wq, !dlm_lockres_is_dirty(dlm, res)); - dlm_lockres_put(res); - goto restart; - } - dlm_purge_lockres(dlm, res); dlm_lockres_put(res); + + cond_resched_lock(&dlm->spinlock); + + if (dropped) + goto redo_bucket; } + num += n; + mlog(0, "%s: touched %d lockreses in bucket %d " + "(tot=%d)\n", dlm->name, n, i, num); } spin_unlock(&dlm->spinlock); + wake_up(&dlm->dlm_thread_wq); + /* let the dlm thread take care of purging, keep scanning until + * nothing remains in the hash */ + if (num) { + mlog(0, "%s: %d lock resources in hash last pass\n", + dlm->name, num); + ret = -EAGAIN; + } mlog(0, "DONE Migrating locks from domain %s\n", dlm->name); + return ret; } static int dlm_no_joining_node(struct dlm_ctxt *dlm) @@ -418,7 +500,8 @@ static void __dlm_print_nodes(struct dlm_ctxt *dlm) printk("\n"); } -static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data) +static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_ctxt *dlm = data; unsigned int node; @@ -571,7 +654,9 @@ void dlm_unregister_domain(struct dlm_ctxt *dlm) /* We changed dlm state, notify the thread */ dlm_kick_thread(dlm, NULL); - dlm_migrate_all_locks(dlm); + while (dlm_migrate_all_locks(dlm)) { + mlog(0, "%s: more migration to do\n", dlm->name); + } dlm_mark_domain_leaving(dlm); dlm_leave_domain(dlm); dlm_complete_dlm_shutdown(dlm); @@ -580,11 +665,13 @@ void dlm_unregister_domain(struct dlm_ctxt *dlm) } EXPORT_SYMBOL_GPL(dlm_unregister_domain); -static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data) +static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_query_join_request *query; enum dlm_query_join_response response; struct dlm_ctxt *dlm = NULL; + u8 nodenum; query = (struct dlm_query_join_request *) msg->buf; @@ -608,6 +695,28 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data) spin_lock(&dlm_domain_lock); dlm = __dlm_lookup_domain_full(query->domain, query->name_len); + if (!dlm) + goto unlock_respond; + + /* + * There is a small window where the joining node may not see the + * node(s) that just left but still part of the cluster. DISALLOW + * join request if joining node has different node map. + */ + nodenum=0; + while (nodenum < O2NM_MAX_NODES) { + if (test_bit(nodenum, dlm->domain_map)) { + if (!byte_test_bit(nodenum, query->node_map)) { + mlog(0, "disallow join as node %u does not " + "have node %u in its nodemap\n", + query->node_idx, nodenum); + response = JOIN_DISALLOW; + goto unlock_respond; + } + } + nodenum++; + } + /* Once the dlm ctxt is marked as leaving then we don't want * to be put in someone's domain map. * Also, explicitly disallow joining at certain troublesome @@ -626,15 +735,15 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data) /* Disallow parallel joins. */ response = JOIN_DISALLOW; } else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) { - mlog(ML_NOTICE, "node %u trying to join, but recovery " + mlog(0, "node %u trying to join, but recovery " "is ongoing.\n", bit); response = JOIN_DISALLOW; } else if (test_bit(bit, dlm->recovery_map)) { - mlog(ML_NOTICE, "node %u trying to join, but it " + mlog(0, "node %u trying to join, but it " "still needs recovery.\n", bit); response = JOIN_DISALLOW; } else if (test_bit(bit, dlm->domain_map)) { - mlog(ML_NOTICE, "node %u trying to join, but it " + mlog(0, "node %u trying to join, but it " "is still in the domain! needs recovery?\n", bit); response = JOIN_DISALLOW; @@ -649,6 +758,7 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data) spin_unlock(&dlm->spinlock); } +unlock_respond: spin_unlock(&dlm_domain_lock); respond: @@ -657,7 +767,8 @@ respond: return response; } -static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data) +static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_assert_joined *assert; struct dlm_ctxt *dlm = NULL; @@ -694,7 +805,8 @@ static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data) return 0; } -static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data) +static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_cancel_join *cancel; struct dlm_ctxt *dlm = NULL; @@ -796,6 +908,9 @@ static int dlm_request_join(struct dlm_ctxt *dlm, join_msg.name_len = strlen(dlm->name); memcpy(join_msg.domain, dlm->name, join_msg.name_len); + /* copy live node map to join message */ + byte_copymap(join_msg.node_map, dlm->live_nodes_map, O2NM_MAX_NODES); + status = o2net_send_message(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, &join_msg, sizeof(join_msg), node, &retval); if (status < 0 && status != -ENOPROTOOPT) { @@ -1036,98 +1151,106 @@ static int dlm_register_domain_handlers(struct dlm_ctxt *dlm) status = o2net_register_handler(DLM_MASTER_REQUEST_MSG, dlm->key, sizeof(struct dlm_master_request), dlm_master_request_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, NULL, &dlm->dlm_domain_handlers); if (status) goto bail; status = o2net_register_handler(DLM_ASSERT_MASTER_MSG, dlm->key, sizeof(struct dlm_assert_master), dlm_assert_master_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, dlm_assert_master_post_handler, + &dlm->dlm_domain_handlers); if (status) goto bail; status = o2net_register_handler(DLM_CREATE_LOCK_MSG, dlm->key, sizeof(struct dlm_create_lock), dlm_create_lock_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, NULL, &dlm->dlm_domain_handlers); if (status) goto bail; status = o2net_register_handler(DLM_CONVERT_LOCK_MSG, dlm->key, DLM_CONVERT_LOCK_MAX_LEN, dlm_convert_lock_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, NULL, &dlm->dlm_domain_handlers); if (status) goto bail; status = o2net_register_handler(DLM_UNLOCK_LOCK_MSG, dlm->key, DLM_UNLOCK_LOCK_MAX_LEN, dlm_unlock_lock_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, NULL, &dlm->dlm_domain_handlers); if (status) goto bail; status = o2net_register_handler(DLM_PROXY_AST_MSG, dlm->key, DLM_PROXY_AST_MAX_LEN, dlm_proxy_ast_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, NULL, &dlm->dlm_domain_handlers); if (status) goto bail; status = o2net_register_handler(DLM_EXIT_DOMAIN_MSG, dlm->key, sizeof(struct dlm_exit_domain), dlm_exit_domain_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, NULL, &dlm->dlm_domain_handlers); + if (status) + goto bail; + + status = o2net_register_handler(DLM_DEREF_LOCKRES_MSG, dlm->key, + sizeof(struct dlm_deref_lockres), + dlm_deref_lockres_handler, + dlm, NULL, &dlm->dlm_domain_handlers); if (status) goto bail; status = o2net_register_handler(DLM_MIGRATE_REQUEST_MSG, dlm->key, sizeof(struct dlm_migrate_request), dlm_migrate_request_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, NULL, &dlm->dlm_domain_handlers); if (status) goto bail; status = o2net_register_handler(DLM_MIG_LOCKRES_MSG, dlm->key, DLM_MIG_LOCKRES_MAX_LEN, dlm_mig_lockres_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, NULL, &dlm->dlm_domain_handlers); if (status) goto bail; status = o2net_register_handler(DLM_MASTER_REQUERY_MSG, dlm->key, sizeof(struct dlm_master_requery), dlm_master_requery_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, NULL, &dlm->dlm_domain_handlers); if (status) goto bail; status = o2net_register_handler(DLM_LOCK_REQUEST_MSG, dlm->key, sizeof(struct dlm_lock_request), dlm_request_all_locks_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, NULL, &dlm->dlm_domain_handlers); if (status) goto bail; status = o2net_register_handler(DLM_RECO_DATA_DONE_MSG, dlm->key, sizeof(struct dlm_reco_data_done), dlm_reco_data_done_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, NULL, &dlm->dlm_domain_handlers); if (status) goto bail; status = o2net_register_handler(DLM_BEGIN_RECO_MSG, dlm->key, sizeof(struct dlm_begin_reco), dlm_begin_reco_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, NULL, &dlm->dlm_domain_handlers); if (status) goto bail; status = o2net_register_handler(DLM_FINALIZE_RECO_MSG, dlm->key, sizeof(struct dlm_finalize_reco), dlm_finalize_reco_handler, - dlm, &dlm->dlm_domain_handlers); + dlm, NULL, &dlm->dlm_domain_handlers); if (status) goto bail; @@ -1141,6 +1264,8 @@ bail: static int dlm_join_domain(struct dlm_ctxt *dlm) { int status; + unsigned int backoff; + unsigned int total_backoff = 0; BUG_ON(!dlm); @@ -1172,18 +1297,27 @@ static int dlm_join_domain(struct dlm_ctxt *dlm) } do { - unsigned int backoff; status = dlm_try_to_join_domain(dlm); /* If we're racing another node to the join, then we * need to back off temporarily and let them * complete. */ +#define DLM_JOIN_TIMEOUT_MSECS 90000 if (status == -EAGAIN) { if (signal_pending(current)) { status = -ERESTARTSYS; goto bail; } + if (total_backoff > + msecs_to_jiffies(DLM_JOIN_TIMEOUT_MSECS)) { + status = -ERESTARTSYS; + mlog(ML_NOTICE, "Timed out joining dlm domain " + "%s after %u msecs\n", dlm->name, + jiffies_to_msecs(total_backoff)); + goto bail; + } + /* * After you! * No, after you! @@ -1193,6 +1327,7 @@ static int dlm_join_domain(struct dlm_ctxt *dlm) */ backoff = (unsigned int)(jiffies & 0x3); backoff *= DLM_DOMAIN_BACKOFF_MS; + total_backoff += backoff; mlog(0, "backoff %d\n", backoff); msleep(backoff); } @@ -1421,21 +1556,21 @@ static int dlm_register_net_handlers(void) status = o2net_register_handler(DLM_QUERY_JOIN_MSG, DLM_MOD_KEY, sizeof(struct dlm_query_join_request), dlm_query_join_handler, - NULL, &dlm_join_handlers); + NULL, NULL, &dlm_join_handlers); if (status) goto bail; status = o2net_register_handler(DLM_ASSERT_JOINED_MSG, DLM_MOD_KEY, sizeof(struct dlm_assert_joined), dlm_assert_joined_handler, - NULL, &dlm_join_handlers); + NULL, NULL, &dlm_join_handlers); if (status) goto bail; status = o2net_register_handler(DLM_CANCEL_JOIN_MSG, DLM_MOD_KEY, sizeof(struct dlm_cancel_join), dlm_cancel_join_handler, - NULL, &dlm_join_handlers); + NULL, NULL, &dlm_join_handlers); bail: if (status < 0) diff --git a/fs/ocfs2/dlm/dlmlock.c b/fs/ocfs2/dlm/dlmlock.c index e5ca3db197f6..52578d907d9a 100644 --- a/fs/ocfs2/dlm/dlmlock.c +++ b/fs/ocfs2/dlm/dlmlock.c @@ -163,6 +163,10 @@ static enum dlm_status dlmlock_master(struct dlm_ctxt *dlm, kick_thread = 1; } } + /* reduce the inflight count, this may result in the lockres + * being purged below during calc_usage */ + if (lock->ml.node == dlm->node_num) + dlm_lockres_drop_inflight_ref(dlm, res); spin_unlock(&res->spinlock); wake_up(&res->wq); @@ -437,7 +441,8 @@ struct dlm_lock * dlm_new_lock(int type, u8 node, u64 cookie, * held on exit: none * returns: DLM_NORMAL, DLM_SYSERR, DLM_IVLOCKID, DLM_NOTQUEUED */ -int dlm_create_lock_handler(struct o2net_msg *msg, u32 len, void *data) +int dlm_create_lock_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_ctxt *dlm = data; struct dlm_create_lock *create = (struct dlm_create_lock *)msg->buf; diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index 0ad872055cb3..77e4e6169a0d 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -99,9 +99,10 @@ static void dlm_mle_node_up(struct dlm_ctxt *dlm, int idx); static void dlm_assert_master_worker(struct dlm_work_item *item, void *data); -static int dlm_do_assert_master(struct dlm_ctxt *dlm, const char *lockname, - unsigned int namelen, void *nodemap, - u32 flags); +static int dlm_do_assert_master(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res, + void *nodemap, u32 flags); +static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data); static inline int dlm_mle_equal(struct dlm_ctxt *dlm, struct dlm_master_list_entry *mle, @@ -237,7 +238,8 @@ static int dlm_find_mle(struct dlm_ctxt *dlm, struct dlm_master_list_entry **mle, char *name, unsigned int namelen); -static int dlm_do_master_request(struct dlm_master_list_entry *mle, int to); +static int dlm_do_master_request(struct dlm_lock_resource *res, + struct dlm_master_list_entry *mle, int to); static int dlm_wait_for_lock_mastery(struct dlm_ctxt *dlm, @@ -687,6 +689,7 @@ static void dlm_init_lockres(struct dlm_ctxt *dlm, INIT_LIST_HEAD(&res->purge); atomic_set(&res->asts_reserved, 0); res->migration_pending = 0; + res->inflight_locks = 0; kref_init(&res->refs); @@ -700,6 +703,7 @@ static void dlm_init_lockres(struct dlm_ctxt *dlm, res->last_used = 0; memset(res->lvb, 0, DLM_LVB_LEN); + memset(res->refmap, 0, sizeof(res->refmap)); } struct dlm_lock_resource *dlm_new_lockres(struct dlm_ctxt *dlm, @@ -722,6 +726,42 @@ struct dlm_lock_resource *dlm_new_lockres(struct dlm_ctxt *dlm, return res; } +void __dlm_lockres_grab_inflight_ref(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res, + int new_lockres, + const char *file, + int line) +{ + if (!new_lockres) + assert_spin_locked(&res->spinlock); + + if (!test_bit(dlm->node_num, res->refmap)) { + BUG_ON(res->inflight_locks != 0); + dlm_lockres_set_refmap_bit(dlm->node_num, res); + } + res->inflight_locks++; + mlog(0, "%s:%.*s: inflight++: now %u\n", + dlm->name, res->lockname.len, res->lockname.name, + res->inflight_locks); +} + +void __dlm_lockres_drop_inflight_ref(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res, + const char *file, + int line) +{ + assert_spin_locked(&res->spinlock); + + BUG_ON(res->inflight_locks == 0); + res->inflight_locks--; + mlog(0, "%s:%.*s: inflight--: now %u\n", + dlm->name, res->lockname.len, res->lockname.name, + res->inflight_locks); + if (res->inflight_locks == 0) + dlm_lockres_clear_refmap_bit(dlm->node_num, res); + wake_up(&res->wq); +} + /* * lookup a lock resource by name. * may already exist in the hashtable. @@ -752,6 +792,7 @@ struct dlm_lock_resource * dlm_get_lock_resource(struct dlm_ctxt *dlm, unsigned int hash; int tries = 0; int bit, wait_on_recovery = 0; + int drop_inflight_if_nonlocal = 0; BUG_ON(!lockid); @@ -761,9 +802,30 @@ struct dlm_lock_resource * dlm_get_lock_resource(struct dlm_ctxt *dlm, lookup: spin_lock(&dlm->spinlock); - tmpres = __dlm_lookup_lockres(dlm, lockid, namelen, hash); + tmpres = __dlm_lookup_lockres_full(dlm, lockid, namelen, hash); if (tmpres) { + int dropping_ref = 0; + + spin_lock(&tmpres->spinlock); + if (tmpres->owner == dlm->node_num) { + BUG_ON(tmpres->state & DLM_LOCK_RES_DROPPING_REF); + dlm_lockres_grab_inflight_ref(dlm, tmpres); + } else if (tmpres->state & DLM_LOCK_RES_DROPPING_REF) + dropping_ref = 1; + spin_unlock(&tmpres->spinlock); spin_unlock(&dlm->spinlock); + + /* wait until done messaging the master, drop our ref to allow + * the lockres to be purged, start over. */ + if (dropping_ref) { + spin_lock(&tmpres->spinlock); + __dlm_wait_on_lockres_flags(tmpres, DLM_LOCK_RES_DROPPING_REF); + spin_unlock(&tmpres->spinlock); + dlm_lockres_put(tmpres); + tmpres = NULL; + goto lookup; + } + mlog(0, "found in hash!\n"); if (res) dlm_lockres_put(res); @@ -793,6 +855,7 @@ lookup: spin_lock(&res->spinlock); dlm_change_lockres_owner(dlm, res, dlm->node_num); __dlm_insert_lockres(dlm, res); + dlm_lockres_grab_inflight_ref(dlm, res); spin_unlock(&res->spinlock); spin_unlock(&dlm->spinlock); /* lockres still marked IN_PROGRESS */ @@ -805,29 +868,40 @@ lookup: /* if we found a block, wait for lock to be mastered by another node */ blocked = dlm_find_mle(dlm, &mle, (char *)lockid, namelen); if (blocked) { + int mig; if (mle->type == DLM_MLE_MASTER) { mlog(ML_ERROR, "master entry for nonexistent lock!\n"); BUG(); - } else if (mle->type == DLM_MLE_MIGRATION) { - /* migration is in progress! */ - /* the good news is that we now know the - * "current" master (mle->master). */ - + } + mig = (mle->type == DLM_MLE_MIGRATION); + /* if there is a migration in progress, let the migration + * finish before continuing. we can wait for the absence + * of the MIGRATION mle: either the migrate finished or + * one of the nodes died and the mle was cleaned up. + * if there is a BLOCK here, but it already has a master + * set, we are too late. the master does not have a ref + * for us in the refmap. detach the mle and drop it. + * either way, go back to the top and start over. */ + if (mig || mle->master != O2NM_MAX_NODES) { + BUG_ON(mig && mle->master == dlm->node_num); + /* we arrived too late. the master does not + * have a ref for us. retry. */ + mlog(0, "%s:%.*s: late on %s\n", + dlm->name, namelen, lockid, + mig ? "MIGRATION" : "BLOCK"); spin_unlock(&dlm->master_lock); - assert_spin_locked(&dlm->spinlock); - - /* set the lockres owner and hash it */ - spin_lock(&res->spinlock); - dlm_set_lockres_owner(dlm, res, mle->master); - __dlm_insert_lockres(dlm, res); - spin_unlock(&res->spinlock); spin_unlock(&dlm->spinlock); /* master is known, detach */ - dlm_mle_detach_hb_events(dlm, mle); + if (!mig) + dlm_mle_detach_hb_events(dlm, mle); dlm_put_mle(mle); mle = NULL; - goto wake_waiters; + /* this is lame, but we cant wait on either + * the mle or lockres waitqueue here */ + if (mig) + msleep(100); + goto lookup; } } else { /* go ahead and try to master lock on this node */ @@ -858,6 +932,13 @@ lookup: /* finally add the lockres to its hash bucket */ __dlm_insert_lockres(dlm, res); + /* since this lockres is new it doesnt not require the spinlock */ + dlm_lockres_grab_inflight_ref_new(dlm, res); + + /* if this node does not become the master make sure to drop + * this inflight reference below */ + drop_inflight_if_nonlocal = 1; + /* get an extra ref on the mle in case this is a BLOCK * if so, the creator of the BLOCK may try to put the last * ref at this time in the assert master handler, so we @@ -910,7 +991,7 @@ redo_request: ret = -EINVAL; dlm_node_iter_init(mle->vote_map, &iter); while ((nodenum = dlm_node_iter_next(&iter)) >= 0) { - ret = dlm_do_master_request(mle, nodenum); + ret = dlm_do_master_request(res, mle, nodenum); if (ret < 0) mlog_errno(ret); if (mle->master != O2NM_MAX_NODES) { @@ -960,6 +1041,8 @@ wait: wake_waiters: spin_lock(&res->spinlock); + if (res->owner != dlm->node_num && drop_inflight_if_nonlocal) + dlm_lockres_drop_inflight_ref(dlm, res); res->state &= ~DLM_LOCK_RES_IN_PROGRESS; spin_unlock(&res->spinlock); wake_up(&res->wq); @@ -998,7 +1081,7 @@ recheck: /* this will cause the master to re-assert across * the whole cluster, freeing up mles */ if (res->owner != dlm->node_num) { - ret = dlm_do_master_request(mle, res->owner); + ret = dlm_do_master_request(res, mle, res->owner); if (ret < 0) { /* give recovery a chance to run */ mlog(ML_ERROR, "link to %u went down?: %d\n", res->owner, ret); @@ -1062,6 +1145,8 @@ recheck: * now tell other nodes that I am * mastering this. */ mle->master = dlm->node_num; + /* ref was grabbed in get_lock_resource + * will be dropped in dlmlock_master */ assert = 1; sleep = 0; } @@ -1087,7 +1172,8 @@ recheck: (atomic_read(&mle->woken) == 1), timeo); if (res->owner == O2NM_MAX_NODES) { - mlog(0, "waiting again\n"); + mlog(0, "%s:%.*s: waiting again\n", dlm->name, + res->lockname.len, res->lockname.name); goto recheck; } mlog(0, "done waiting, master is %u\n", res->owner); @@ -1100,8 +1186,7 @@ recheck: m = dlm->node_num; mlog(0, "about to master %.*s here, this=%u\n", res->lockname.len, res->lockname.name, m); - ret = dlm_do_assert_master(dlm, res->lockname.name, - res->lockname.len, mle->vote_map, 0); + ret = dlm_do_assert_master(dlm, res, mle->vote_map, 0); if (ret) { /* This is a failure in the network path, * not in the response to the assert_master @@ -1117,6 +1202,8 @@ recheck: /* set the lockres owner */ spin_lock(&res->spinlock); + /* mastery reference obtained either during + * assert_master_handler or in get_lock_resource */ dlm_change_lockres_owner(dlm, res, m); spin_unlock(&res->spinlock); @@ -1283,7 +1370,8 @@ static int dlm_restart_lock_mastery(struct dlm_ctxt *dlm, * */ -static int dlm_do_master_request(struct dlm_master_list_entry *mle, int to) +static int dlm_do_master_request(struct dlm_lock_resource *res, + struct dlm_master_list_entry *mle, int to) { struct dlm_ctxt *dlm = mle->dlm; struct dlm_master_request request; @@ -1339,6 +1427,9 @@ again: case DLM_MASTER_RESP_YES: set_bit(to, mle->response_map); mlog(0, "node %u is the master, response=YES\n", to); + mlog(0, "%s:%.*s: master node %u now knows I have a " + "reference\n", dlm->name, res->lockname.len, + res->lockname.name, to); mle->master = to; break; case DLM_MASTER_RESP_NO: @@ -1379,7 +1470,8 @@ out: * * if possible, TRIM THIS DOWN!!! */ -int dlm_master_request_handler(struct o2net_msg *msg, u32 len, void *data) +int dlm_master_request_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { u8 response = DLM_MASTER_RESP_MAYBE; struct dlm_ctxt *dlm = data; @@ -1417,10 +1509,11 @@ way_up_top: /* take care of the easy cases up front */ spin_lock(&res->spinlock); - if (res->state & DLM_LOCK_RES_RECOVERING) { + if (res->state & (DLM_LOCK_RES_RECOVERING| + DLM_LOCK_RES_MIGRATING)) { spin_unlock(&res->spinlock); mlog(0, "returning DLM_MASTER_RESP_ERROR since res is " - "being recovered\n"); + "being recovered/migrated\n"); response = DLM_MASTER_RESP_ERROR; if (mle) kmem_cache_free(dlm_mle_cache, mle); @@ -1428,8 +1521,10 @@ way_up_top: } if (res->owner == dlm->node_num) { + mlog(0, "%s:%.*s: setting bit %u in refmap\n", + dlm->name, namelen, name, request->node_idx); + dlm_lockres_set_refmap_bit(request->node_idx, res); spin_unlock(&res->spinlock); - // mlog(0, "this node is the master\n"); response = DLM_MASTER_RESP_YES; if (mle) kmem_cache_free(dlm_mle_cache, mle); @@ -1477,7 +1572,6 @@ way_up_top: mlog(0, "node %u is master, but trying to migrate to " "node %u.\n", tmpmle->master, tmpmle->new_master); if (tmpmle->master == dlm->node_num) { - response = DLM_MASTER_RESP_YES; mlog(ML_ERROR, "no owner on lockres, but this " "node is trying to migrate it to %u?!\n", tmpmle->new_master); @@ -1494,6 +1588,10 @@ way_up_top: * go back and clean the mles on any * other nodes */ dispatch_assert = 1; + dlm_lockres_set_refmap_bit(request->node_idx, res); + mlog(0, "%s:%.*s: setting bit %u in refmap\n", + dlm->name, namelen, name, + request->node_idx); } else response = DLM_MASTER_RESP_NO; } else { @@ -1607,17 +1705,24 @@ send_response: * can periodically run all locks owned by this node * and re-assert across the cluster... */ -static int dlm_do_assert_master(struct dlm_ctxt *dlm, const char *lockname, - unsigned int namelen, void *nodemap, - u32 flags) +int dlm_do_assert_master(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res, + void *nodemap, u32 flags) { struct dlm_assert_master assert; int to, tmpret; struct dlm_node_iter iter; int ret = 0; int reassert; + const char *lockname = res->lockname.name; + unsigned int namelen = res->lockname.len; BUG_ON(namelen > O2NM_MAX_NAME_LEN); + + spin_lock(&res->spinlock); + res->state |= DLM_LOCK_RES_SETREF_INPROG; + spin_unlock(&res->spinlock); + again: reassert = 0; @@ -1647,6 +1752,7 @@ again: mlog(0, "link to %d went down!\n", to); /* any nonzero status return will do */ ret = tmpret; + r = 0; } else if (r < 0) { /* ok, something horribly messed. kill thyself. */ mlog(ML_ERROR,"during assert master of %.*s to %u, " @@ -1661,17 +1767,39 @@ again: spin_unlock(&dlm->master_lock); spin_unlock(&dlm->spinlock); BUG(); - } else if (r == EAGAIN) { + } + + if (r & DLM_ASSERT_RESPONSE_REASSERT && + !(r & DLM_ASSERT_RESPONSE_MASTERY_REF)) { + mlog(ML_ERROR, "%.*s: very strange, " + "master MLE but no lockres on %u\n", + namelen, lockname, to); + } + + if (r & DLM_ASSERT_RESPONSE_REASSERT) { mlog(0, "%.*s: node %u create mles on other " "nodes and requests a re-assert\n", namelen, lockname, to); reassert = 1; } + if (r & DLM_ASSERT_RESPONSE_MASTERY_REF) { + mlog(0, "%.*s: node %u has a reference to this " + "lockres, set the bit in the refmap\n", + namelen, lockname, to); + spin_lock(&res->spinlock); + dlm_lockres_set_refmap_bit(to, res); + spin_unlock(&res->spinlock); + } } if (reassert) goto again; + spin_lock(&res->spinlock); + res->state &= ~DLM_LOCK_RES_SETREF_INPROG; + spin_unlock(&res->spinlock); + wake_up(&res->wq); + return ret; } @@ -1684,7 +1812,8 @@ again: * * if possible, TRIM THIS DOWN!!! */ -int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data) +int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_ctxt *dlm = data; struct dlm_master_list_entry *mle = NULL; @@ -1693,7 +1822,7 @@ int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data) char *name; unsigned int namelen, hash; u32 flags; - int master_request = 0; + int master_request = 0, have_lockres_ref = 0; int ret = 0; if (!dlm_grab(dlm)) @@ -1851,6 +1980,7 @@ ok: spin_unlock(&mle->spinlock); if (res) { + int wake = 0; spin_lock(&res->spinlock); if (mle->type == DLM_MLE_MIGRATION) { mlog(0, "finishing off migration of lockres %.*s, " @@ -1858,12 +1988,16 @@ ok: res->lockname.len, res->lockname.name, dlm->node_num, mle->new_master); res->state &= ~DLM_LOCK_RES_MIGRATING; + wake = 1; dlm_change_lockres_owner(dlm, res, mle->new_master); BUG_ON(res->state & DLM_LOCK_RES_DIRTY); } else { dlm_change_lockres_owner(dlm, res, mle->master); } spin_unlock(&res->spinlock); + have_lockres_ref = 1; + if (wake) + wake_up(&res->wq); } /* master is known, detach if not already detached. @@ -1913,12 +2047,28 @@ ok: done: ret = 0; - if (res) - dlm_lockres_put(res); + if (res) { + spin_lock(&res->spinlock); + res->state |= DLM_LOCK_RES_SETREF_INPROG; + spin_unlock(&res->spinlock); + *ret_data = (void *)res; + } dlm_put(dlm); if (master_request) { mlog(0, "need to tell master to reassert\n"); - ret = EAGAIN; // positive. negative would shoot down the node. + /* positive. negative would shoot down the node. */ + ret |= DLM_ASSERT_RESPONSE_REASSERT; + if (!have_lockres_ref) { + mlog(ML_ERROR, "strange, got assert from %u, MASTER " + "mle present here for %s:%.*s, but no lockres!\n", + assert->node_idx, dlm->name, namelen, name); + } + } + if (have_lockres_ref) { + /* let the master know we have a reference to the lockres */ + ret |= DLM_ASSERT_RESPONSE_MASTERY_REF; + mlog(0, "%s:%.*s: got assert from %u, need a ref\n", + dlm->name, namelen, name, assert->node_idx); } return ret; @@ -1929,11 +2079,25 @@ kill: __dlm_print_one_lock_resource(res); spin_unlock(&res->spinlock); spin_unlock(&dlm->spinlock); - dlm_lockres_put(res); + *ret_data = (void *)res; dlm_put(dlm); return -EINVAL; } +void dlm_assert_master_post_handler(int status, void *data, void *ret_data) +{ + struct dlm_lock_resource *res = (struct dlm_lock_resource *)ret_data; + + if (ret_data) { + spin_lock(&res->spinlock); + res->state &= ~DLM_LOCK_RES_SETREF_INPROG; + spin_unlock(&res->spinlock); + wake_up(&res->wq); + dlm_lockres_put(res); + } + return; +} + int dlm_dispatch_assert_master(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, int ignore_higher, u8 request_from, u32 flags) @@ -2023,9 +2187,7 @@ static void dlm_assert_master_worker(struct dlm_work_item *item, void *data) * even if one or more nodes die */ mlog(0, "worker about to master %.*s here, this=%u\n", res->lockname.len, res->lockname.name, dlm->node_num); - ret = dlm_do_assert_master(dlm, res->lockname.name, - res->lockname.len, - nodemap, flags); + ret = dlm_do_assert_master(dlm, res, nodemap, flags); if (ret < 0) { /* no need to restart, we are done */ if (!dlm_is_host_down(ret)) @@ -2097,14 +2259,180 @@ static int dlm_pre_master_reco_lockres(struct dlm_ctxt *dlm, return ret; } +/* + * DLM_DEREF_LOCKRES_MSG + */ + +int dlm_drop_lockres_ref(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) +{ + struct dlm_deref_lockres deref; + int ret = 0, r; + const char *lockname; + unsigned int namelen; + + lockname = res->lockname.name; + namelen = res->lockname.len; + BUG_ON(namelen > O2NM_MAX_NAME_LEN); + + mlog(0, "%s:%.*s: sending deref to %d\n", + dlm->name, namelen, lockname, res->owner); + memset(&deref, 0, sizeof(deref)); + deref.node_idx = dlm->node_num; + deref.namelen = namelen; + memcpy(deref.name, lockname, namelen); + + ret = o2net_send_message(DLM_DEREF_LOCKRES_MSG, dlm->key, + &deref, sizeof(deref), res->owner, &r); + if (ret < 0) + mlog_errno(ret); + else if (r < 0) { + /* BAD. other node says I did not have a ref. */ + mlog(ML_ERROR,"while dropping ref on %s:%.*s " + "(master=%u) got %d.\n", dlm->name, namelen, + lockname, res->owner, r); + dlm_print_one_lock_resource(res); + BUG(); + } + return ret; +} + +int dlm_deref_lockres_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) +{ + struct dlm_ctxt *dlm = data; + struct dlm_deref_lockres *deref = (struct dlm_deref_lockres *)msg->buf; + struct dlm_lock_resource *res = NULL; + char *name; + unsigned int namelen; + int ret = -EINVAL; + u8 node; + unsigned int hash; + struct dlm_work_item *item; + int cleared = 0; + int dispatch = 0; + + if (!dlm_grab(dlm)) + return 0; + + name = deref->name; + namelen = deref->namelen; + node = deref->node_idx; + + if (namelen > DLM_LOCKID_NAME_MAX) { + mlog(ML_ERROR, "Invalid name length!"); + goto done; + } + if (deref->node_idx >= O2NM_MAX_NODES) { + mlog(ML_ERROR, "Invalid node number: %u\n", node); + goto done; + } + + hash = dlm_lockid_hash(name, namelen); + + spin_lock(&dlm->spinlock); + res = __dlm_lookup_lockres_full(dlm, name, namelen, hash); + if (!res) { + spin_unlock(&dlm->spinlock); + mlog(ML_ERROR, "%s:%.*s: bad lockres name\n", + dlm->name, namelen, name); + goto done; + } + spin_unlock(&dlm->spinlock); + + spin_lock(&res->spinlock); + if (res->state & DLM_LOCK_RES_SETREF_INPROG) + dispatch = 1; + else { + BUG_ON(res->state & DLM_LOCK_RES_DROPPING_REF); + if (test_bit(node, res->refmap)) { + dlm_lockres_clear_refmap_bit(node, res); + cleared = 1; + } + } + spin_unlock(&res->spinlock); + + if (!dispatch) { + if (cleared) + dlm_lockres_calc_usage(dlm, res); + else { + mlog(ML_ERROR, "%s:%.*s: node %u trying to drop ref " + "but it is already dropped!\n", dlm->name, + res->lockname.len, res->lockname.name, node); + __dlm_print_one_lock_resource(res); + } + ret = 0; + goto done; + } + + item = kzalloc(sizeof(*item), GFP_NOFS); + if (!item) { + ret = -ENOMEM; + mlog_errno(ret); + goto done; + } + + dlm_init_work_item(dlm, item, dlm_deref_lockres_worker, NULL); + item->u.dl.deref_res = res; + item->u.dl.deref_node = node; + + spin_lock(&dlm->work_lock); + list_add_tail(&item->list, &dlm->work_list); + spin_unlock(&dlm->work_lock); + + queue_work(dlm->dlm_worker, &dlm->dispatched_work); + return 0; + +done: + if (res) + dlm_lockres_put(res); + dlm_put(dlm); + + return ret; +} + +static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data) +{ + struct dlm_ctxt *dlm; + struct dlm_lock_resource *res; + u8 node; + u8 cleared = 0; + + dlm = item->dlm; + res = item->u.dl.deref_res; + node = item->u.dl.deref_node; + + spin_lock(&res->spinlock); + BUG_ON(res->state & DLM_LOCK_RES_DROPPING_REF); + if (test_bit(node, res->refmap)) { + __dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG); + dlm_lockres_clear_refmap_bit(node, res); + cleared = 1; + } + spin_unlock(&res->spinlock); + + if (cleared) { + mlog(0, "%s:%.*s node %u ref dropped in dispatch\n", + dlm->name, res->lockname.len, res->lockname.name, node); + dlm_lockres_calc_usage(dlm, res); + } else { + mlog(ML_ERROR, "%s:%.*s: node %u trying to drop ref " + "but it is already dropped!\n", dlm->name, + res->lockname.len, res->lockname.name, node); + __dlm_print_one_lock_resource(res); + } + + dlm_lockres_put(res); +} + /* * DLM_MIGRATE_LOCKRES */ -int dlm_migrate_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, - u8 target) +static int dlm_migrate_lockres(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res, + u8 target) { struct dlm_master_list_entry *mle = NULL; struct dlm_master_list_entry *oldmle = NULL; @@ -2116,7 +2444,7 @@ int dlm_migrate_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, struct list_head *queue, *iter; int i; struct dlm_lock *lock; - int empty = 1; + int empty = 1, wake = 0; if (!dlm_grab(dlm)) return -EINVAL; @@ -2241,6 +2569,7 @@ int dlm_migrate_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, res->lockname.name, target); spin_lock(&res->spinlock); res->state &= ~DLM_LOCK_RES_MIGRATING; + wake = 1; spin_unlock(&res->spinlock); ret = -EINVAL; } @@ -2268,6 +2597,9 @@ fail: * the lockres */ + /* now that remote nodes are spinning on the MIGRATING flag, + * ensure that all assert_master work is flushed. */ + flush_workqueue(dlm->dlm_worker); /* get an extra reference on the mle. * otherwise the assert_master from the new @@ -2296,6 +2628,7 @@ fail: dlm_put_mle_inuse(mle); spin_lock(&res->spinlock); res->state &= ~DLM_LOCK_RES_MIGRATING; + wake = 1; spin_unlock(&res->spinlock); goto leave; } @@ -2322,7 +2655,8 @@ fail: res->owner == target) break; - mlog(0, "timed out during migration\n"); + mlog(0, "%s:%.*s: timed out during migration\n", + dlm->name, res->lockname.len, res->lockname.name); /* avoid hang during shutdown when migrating lockres * to a node which also goes down */ if (dlm_is_node_dead(dlm, target)) { @@ -2330,20 +2664,20 @@ fail: "target %u is no longer up, restarting\n", dlm->name, res->lockname.len, res->lockname.name, target); - ret = -ERESTARTSYS; + ret = -EINVAL; + /* migration failed, detach and clean up mle */ + dlm_mle_detach_hb_events(dlm, mle); + dlm_put_mle(mle); + dlm_put_mle_inuse(mle); + spin_lock(&res->spinlock); + res->state &= ~DLM_LOCK_RES_MIGRATING; + wake = 1; + spin_unlock(&res->spinlock); + goto leave; } - } - if (ret == -ERESTARTSYS) { - /* migration failed, detach and clean up mle */ - dlm_mle_detach_hb_events(dlm, mle); - dlm_put_mle(mle); - dlm_put_mle_inuse(mle); - spin_lock(&res->spinlock); - res->state &= ~DLM_LOCK_RES_MIGRATING; - spin_unlock(&res->spinlock); - goto leave; - } - /* TODO: if node died: stop, clean up, return error */ + } else + mlog(0, "%s:%.*s: caught signal during migration\n", + dlm->name, res->lockname.len, res->lockname.name); } /* all done, set the owner, clear the flag */ @@ -2366,6 +2700,11 @@ leave: if (ret < 0) dlm_kick_thread(dlm, res); + /* wake up waiters if the MIGRATING flag got set + * but migration failed */ + if (wake) + wake_up(&res->wq); + /* TODO: cleanup */ if (mres) free_page((unsigned long)mres); @@ -2376,6 +2715,53 @@ leave: return ret; } +#define DLM_MIGRATION_RETRY_MS 100 + +/* Should be called only after beginning the domain leave process. + * There should not be any remaining locks on nonlocal lock resources, + * and there should be no local locks left on locally mastered resources. + * + * Called with the dlm spinlock held, may drop it to do migration, but + * will re-acquire before exit. + * + * Returns: 1 if dlm->spinlock was dropped/retaken, 0 if never dropped */ +int dlm_empty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) +{ + int ret; + int lock_dropped = 0; + + if (res->owner != dlm->node_num) { + if (!__dlm_lockres_unused(res)) { + mlog(ML_ERROR, "%s:%.*s: this node is not master, " + "trying to free this but locks remain\n", + dlm->name, res->lockname.len, res->lockname.name); + } + goto leave; + } + + /* Wheee! Migrate lockres here! Will sleep so drop spinlock. */ + spin_unlock(&dlm->spinlock); + lock_dropped = 1; + while (1) { + ret = dlm_migrate_lockres(dlm, res, O2NM_MAX_NODES); + if (ret >= 0) + break; + if (ret == -ENOTEMPTY) { + mlog(ML_ERROR, "lockres %.*s still has local locks!\n", + res->lockname.len, res->lockname.name); + BUG(); + } + + mlog(0, "lockres %.*s: migrate failed, " + "retrying\n", res->lockname.len, + res->lockname.name); + msleep(DLM_MIGRATION_RETRY_MS); + } + spin_lock(&dlm->spinlock); +leave: + return lock_dropped; +} + int dlm_lock_basts_flushed(struct dlm_ctxt *dlm, struct dlm_lock *lock) { int ret; @@ -2405,7 +2791,8 @@ static int dlm_migration_can_proceed(struct dlm_ctxt *dlm, return can_proceed; } -int dlm_lockres_is_dirty(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) +static int dlm_lockres_is_dirty(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res) { int ret; spin_lock(&res->spinlock); @@ -2434,8 +2821,15 @@ static int dlm_mark_lockres_migrating(struct dlm_ctxt *dlm, __dlm_lockres_reserve_ast(res); spin_unlock(&res->spinlock); - /* now flush all the pending asts.. hang out for a bit */ + /* now flush all the pending asts */ dlm_kick_thread(dlm, res); + /* before waiting on DIRTY, block processes which may + * try to dirty the lockres before MIGRATING is set */ + spin_lock(&res->spinlock); + BUG_ON(res->state & DLM_LOCK_RES_BLOCK_DIRTY); + res->state |= DLM_LOCK_RES_BLOCK_DIRTY; + spin_unlock(&res->spinlock); + /* now wait on any pending asts and the DIRTY state */ wait_event(dlm->ast_wq, !dlm_lockres_is_dirty(dlm, res)); dlm_lockres_release_ast(dlm, res); @@ -2461,6 +2855,13 @@ again: mlog(0, "trying again...\n"); goto again; } + /* now that we are sure the MIGRATING state is there, drop + * the unneded state which blocked threads trying to DIRTY */ + spin_lock(&res->spinlock); + BUG_ON(!(res->state & DLM_LOCK_RES_BLOCK_DIRTY)); + BUG_ON(!(res->state & DLM_LOCK_RES_MIGRATING)); + res->state &= ~DLM_LOCK_RES_BLOCK_DIRTY; + spin_unlock(&res->spinlock); /* did the target go down or die? */ spin_lock(&dlm->spinlock); @@ -2490,7 +2891,7 @@ static void dlm_remove_nonlocal_locks(struct dlm_ctxt *dlm, { struct list_head *iter, *iter2; struct list_head *queue = &res->granted; - int i; + int i, bit; struct dlm_lock *lock; assert_spin_locked(&res->spinlock); @@ -2508,12 +2909,28 @@ static void dlm_remove_nonlocal_locks(struct dlm_ctxt *dlm, BUG_ON(!list_empty(&lock->bast_list)); BUG_ON(lock->ast_pending); BUG_ON(lock->bast_pending); + dlm_lockres_clear_refmap_bit(lock->ml.node, res); list_del_init(&lock->list); dlm_lock_put(lock); } } queue++; } + bit = 0; + while (1) { + bit = find_next_bit(res->refmap, O2NM_MAX_NODES, bit); + if (bit >= O2NM_MAX_NODES) + break; + /* do not clear the local node reference, if there is a + * process holding this, let it drop the ref itself */ + if (bit != dlm->node_num) { + mlog(0, "%s:%.*s: node %u had a ref to this " + "migrating lockres, clearing\n", dlm->name, + res->lockname.len, res->lockname.name, bit); + dlm_lockres_clear_refmap_bit(bit, res); + } + bit++; + } } /* for now this is not too intelligent. we will @@ -2601,6 +3018,16 @@ static int dlm_do_migrate_request(struct dlm_ctxt *dlm, mlog(0, "migrate request (node %u) returned %d!\n", nodenum, status); ret = status; + } else if (status == DLM_MIGRATE_RESPONSE_MASTERY_REF) { + /* during the migration request we short-circuited + * the mastery of the lockres. make sure we have + * a mastery ref for nodenum */ + mlog(0, "%s:%.*s: need ref for node %u\n", + dlm->name, res->lockname.len, res->lockname.name, + nodenum); + spin_lock(&res->spinlock); + dlm_lockres_set_refmap_bit(nodenum, res); + spin_unlock(&res->spinlock); } } @@ -2619,7 +3046,8 @@ static int dlm_do_migrate_request(struct dlm_ctxt *dlm, * we will have no mle in the list to start with. now we can add an mle for * the migration and this should be the only one found for those scanning the * list. */ -int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data) +int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_ctxt *dlm = data; struct dlm_lock_resource *res = NULL; @@ -2745,7 +3173,13 @@ static int dlm_add_migration_mle(struct dlm_ctxt *dlm, /* remove it from the list so that only one * mle will be found */ list_del_init(&tmp->list); - __dlm_mle_detach_hb_events(dlm, mle); + /* this was obviously WRONG. mle is uninited here. should be tmp. */ + __dlm_mle_detach_hb_events(dlm, tmp); + ret = DLM_MIGRATE_RESPONSE_MASTERY_REF; + mlog(0, "%s:%.*s: master=%u, newmaster=%u, " + "telling master to get ref for cleared out mle " + "during migration\n", dlm->name, namelen, name, + master, new_master); } spin_unlock(&tmp->spinlock); } @@ -2753,6 +3187,8 @@ static int dlm_add_migration_mle(struct dlm_ctxt *dlm, /* now add a migration mle to the tail of the list */ dlm_init_mle(mle, DLM_MLE_MIGRATION, dlm, res, name, namelen); mle->new_master = new_master; + /* the new master will be sending an assert master for this. + * at that point we will get the refmap reference */ mle->master = master; /* do this for consistency with other mle types */ set_bit(new_master, mle->maybe_map); @@ -2902,6 +3338,13 @@ int dlm_finish_migration(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, clear_bit(dlm->node_num, iter.node_map); spin_unlock(&dlm->spinlock); + /* ownership of the lockres is changing. account for the + * mastery reference here since old_master will briefly have + * a reference after the migration completes */ + spin_lock(&res->spinlock); + dlm_lockres_set_refmap_bit(old_master, res); + spin_unlock(&res->spinlock); + mlog(0, "now time to do a migrate request to other nodes\n"); ret = dlm_do_migrate_request(dlm, res, old_master, dlm->node_num, &iter); @@ -2914,8 +3357,7 @@ int dlm_finish_migration(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, res->lockname.len, res->lockname.name); /* this call now finishes out the nodemap * even if one or more nodes die */ - ret = dlm_do_assert_master(dlm, res->lockname.name, - res->lockname.len, iter.node_map, + ret = dlm_do_assert_master(dlm, res, iter.node_map, DLM_ASSERT_MASTER_FINISH_MIGRATION); if (ret < 0) { /* no longer need to retry. all living nodes contacted. */ @@ -2927,8 +3369,7 @@ int dlm_finish_migration(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, set_bit(old_master, iter.node_map); mlog(0, "doing assert master of %.*s back to %u\n", res->lockname.len, res->lockname.name, old_master); - ret = dlm_do_assert_master(dlm, res->lockname.name, - res->lockname.len, iter.node_map, + ret = dlm_do_assert_master(dlm, res, iter.node_map, DLM_ASSERT_MASTER_FINISH_MIGRATION); if (ret < 0) { mlog(0, "assert master to original master failed " diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index 367a11e9e2ed..6d4a83d50152 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -163,9 +163,6 @@ void dlm_dispatch_work(struct work_struct *work) dlm_workfunc_t *workfunc; int tot=0; - if (!dlm_joined(dlm)) - return; - spin_lock(&dlm->work_lock); list_splice_init(&dlm->work_list, &tmp_list); spin_unlock(&dlm->work_lock); @@ -821,7 +818,8 @@ static int dlm_request_all_locks(struct dlm_ctxt *dlm, u8 request_from, } -int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data) +int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_ctxt *dlm = data; struct dlm_lock_request *lr = (struct dlm_lock_request *)msg->buf; @@ -978,7 +976,8 @@ static int dlm_send_all_done_msg(struct dlm_ctxt *dlm, u8 dead_node, u8 send_to) } -int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data) +int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_ctxt *dlm = data; struct dlm_reco_data_done *done = (struct dlm_reco_data_done *)msg->buf; @@ -1129,6 +1128,11 @@ static int dlm_send_mig_lockres_msg(struct dlm_ctxt *dlm, if (total_locks == mres_total_locks) mres->flags |= DLM_MRES_ALL_DONE; + mlog(0, "%s:%.*s: sending mig lockres (%s) to %u\n", + dlm->name, res->lockname.len, res->lockname.name, + orig_flags & DLM_MRES_MIGRATION ? "migrate" : "recovery", + send_to); + /* send it */ ret = o2net_send_message(DLM_MIG_LOCKRES_MSG, dlm->key, mres, sz, send_to, &status); @@ -1213,6 +1217,34 @@ static int dlm_add_lock_to_array(struct dlm_lock *lock, return 0; } +static void dlm_add_dummy_lock(struct dlm_ctxt *dlm, + struct dlm_migratable_lockres *mres) +{ + struct dlm_lock dummy; + memset(&dummy, 0, sizeof(dummy)); + dummy.ml.cookie = 0; + dummy.ml.type = LKM_IVMODE; + dummy.ml.convert_type = LKM_IVMODE; + dummy.ml.highest_blocked = LKM_IVMODE; + dummy.lksb = NULL; + dummy.ml.node = dlm->node_num; + dlm_add_lock_to_array(&dummy, mres, DLM_BLOCKED_LIST); +} + +static inline int dlm_is_dummy_lock(struct dlm_ctxt *dlm, + struct dlm_migratable_lock *ml, + u8 *nodenum) +{ + if (unlikely(ml->cookie == 0 && + ml->type == LKM_IVMODE && + ml->convert_type == LKM_IVMODE && + ml->highest_blocked == LKM_IVMODE && + ml->list == DLM_BLOCKED_LIST)) { + *nodenum = ml->node; + return 1; + } + return 0; +} int dlm_send_one_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, struct dlm_migratable_lockres *mres, @@ -1260,6 +1292,14 @@ int dlm_send_one_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, goto error; } } + if (total_locks == 0) { + /* send a dummy lock to indicate a mastery reference only */ + mlog(0, "%s:%.*s: sending dummy lock to %u, %s\n", + dlm->name, res->lockname.len, res->lockname.name, + send_to, flags & DLM_MRES_RECOVERY ? "recovery" : + "migration"); + dlm_add_dummy_lock(dlm, mres); + } /* flush any remaining locks */ ret = dlm_send_mig_lockres_msg(dlm, mres, send_to, res, total_locks); if (ret < 0) @@ -1293,7 +1333,8 @@ error: * do we spin? returning an error only delays the problem really */ -int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data) +int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_ctxt *dlm = data; struct dlm_migratable_lockres *mres = @@ -1382,17 +1423,21 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data) spin_lock(&res->spinlock); res->state &= ~DLM_LOCK_RES_IN_PROGRESS; spin_unlock(&res->spinlock); + wake_up(&res->wq); /* add an extra ref for just-allocated lockres * otherwise the lockres will be purged immediately */ dlm_lockres_get(res); - } /* at this point we have allocated everything we need, * and we have a hashed lockres with an extra ref and * the proper res->state flags. */ ret = 0; + spin_lock(&res->spinlock); + /* drop this either when master requery finds a different master + * or when a lock is added by the recovery worker */ + dlm_lockres_grab_inflight_ref(dlm, res); if (mres->master == DLM_LOCK_RES_OWNER_UNKNOWN) { /* migration cannot have an unknown master */ BUG_ON(!(mres->flags & DLM_MRES_RECOVERY)); @@ -1400,10 +1445,11 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data) "unknown owner.. will need to requery: " "%.*s\n", mres->lockname_len, mres->lockname); } else { - spin_lock(&res->spinlock); + /* take a reference now to pin the lockres, drop it + * when locks are added in the worker */ dlm_change_lockres_owner(dlm, res, dlm->node_num); - spin_unlock(&res->spinlock); } + spin_unlock(&res->spinlock); /* queue up work for dlm_mig_lockres_worker */ dlm_grab(dlm); /* get an extra ref for the work item */ @@ -1459,6 +1505,9 @@ again: "this node will take it.\n", res->lockname.len, res->lockname.name); } else { + spin_lock(&res->spinlock); + dlm_lockres_drop_inflight_ref(dlm, res); + spin_unlock(&res->spinlock); mlog(0, "master needs to respond to sender " "that node %u still owns %.*s\n", real_master, res->lockname.len, @@ -1578,7 +1627,8 @@ int dlm_do_master_requery(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, /* this function cannot error, so unless the sending * or receiving of the message failed, the owner can * be trusted */ -int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data) +int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_ctxt *dlm = data; struct dlm_master_requery *req = (struct dlm_master_requery *)msg->buf; @@ -1660,21 +1710,38 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm, { struct dlm_migratable_lock *ml; struct list_head *queue; + struct list_head *tmpq = NULL; struct dlm_lock *newlock = NULL; struct dlm_lockstatus *lksb = NULL; int ret = 0; - int i, bad; + int i, j, bad; struct list_head *iter; struct dlm_lock *lock = NULL; + u8 from = O2NM_MAX_NODES; + unsigned int added = 0; mlog(0, "running %d locks for this lockres\n", mres->num_locks); for (i=0; inum_locks; i++) { ml = &(mres->ml[i]); + + if (dlm_is_dummy_lock(dlm, ml, &from)) { + /* placeholder, just need to set the refmap bit */ + BUG_ON(mres->num_locks != 1); + mlog(0, "%s:%.*s: dummy lock for %u\n", + dlm->name, mres->lockname_len, mres->lockname, + from); + spin_lock(&res->spinlock); + dlm_lockres_set_refmap_bit(from, res); + spin_unlock(&res->spinlock); + added++; + break; + } BUG_ON(ml->highest_blocked != LKM_IVMODE); newlock = NULL; lksb = NULL; queue = dlm_list_num_to_pointer(res, ml->list); + tmpq = NULL; /* if the lock is for the local node it needs to * be moved to the proper location within the queue. @@ -1684,11 +1751,16 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm, BUG_ON(!(mres->flags & DLM_MRES_MIGRATION)); spin_lock(&res->spinlock); - list_for_each(iter, queue) { - lock = list_entry (iter, struct dlm_lock, list); - if (lock->ml.cookie != ml->cookie) - lock = NULL; - else + for (j = DLM_GRANTED_LIST; j <= DLM_BLOCKED_LIST; j++) { + tmpq = dlm_list_idx_to_ptr(res, j); + list_for_each(iter, tmpq) { + lock = list_entry (iter, struct dlm_lock, list); + if (lock->ml.cookie != ml->cookie) + lock = NULL; + else + break; + } + if (lock) break; } @@ -1698,12 +1770,20 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm, u64 c = ml->cookie; mlog(ML_ERROR, "could not find local lock " "with cookie %u:%llu!\n", - dlm_get_lock_cookie_node(c), - dlm_get_lock_cookie_seq(c)); + dlm_get_lock_cookie_node(be64_to_cpu(c)), + dlm_get_lock_cookie_seq(be64_to_cpu(c))); + __dlm_print_one_lock_resource(res); BUG(); } BUG_ON(lock->ml.node != ml->node); + if (tmpq != queue) { + mlog(0, "lock was on %u instead of %u for %.*s\n", + j, ml->list, res->lockname.len, res->lockname.name); + spin_unlock(&res->spinlock); + continue; + } + /* see NOTE above about why we do not update * to match the master here */ @@ -1711,6 +1791,7 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm, /* do not alter lock refcount. switching lists. */ list_move_tail(&lock->list, queue); spin_unlock(&res->spinlock); + added++; mlog(0, "just reordered a local lock!\n"); continue; @@ -1799,14 +1880,14 @@ skip_lvb: mlog(ML_ERROR, "%s:%.*s: %u:%llu: lock already " "exists on this lockres!\n", dlm->name, res->lockname.len, res->lockname.name, - dlm_get_lock_cookie_node(c), - dlm_get_lock_cookie_seq(c)); + dlm_get_lock_cookie_node(be64_to_cpu(c)), + dlm_get_lock_cookie_seq(be64_to_cpu(c))); mlog(ML_NOTICE, "sent lock: type=%d, conv=%d, " "node=%u, cookie=%u:%llu, queue=%d\n", ml->type, ml->convert_type, ml->node, - dlm_get_lock_cookie_node(ml->cookie), - dlm_get_lock_cookie_seq(ml->cookie), + dlm_get_lock_cookie_node(be64_to_cpu(ml->cookie)), + dlm_get_lock_cookie_seq(be64_to_cpu(ml->cookie)), ml->list); __dlm_print_one_lock_resource(res); @@ -1817,12 +1898,22 @@ skip_lvb: if (!bad) { dlm_lock_get(newlock); list_add_tail(&newlock->list, queue); + mlog(0, "%s:%.*s: added lock for node %u, " + "setting refmap bit\n", dlm->name, + res->lockname.len, res->lockname.name, ml->node); + dlm_lockres_set_refmap_bit(ml->node, res); + added++; } spin_unlock(&res->spinlock); } mlog(0, "done running all the locks\n"); leave: + /* balance the ref taken when the work was queued */ + spin_lock(&res->spinlock); + dlm_lockres_drop_inflight_ref(dlm, res); + spin_unlock(&res->spinlock); + if (ret < 0) { mlog_errno(ret); if (newlock) @@ -1935,9 +2026,11 @@ static void dlm_finish_local_lockres_recovery(struct dlm_ctxt *dlm, if (res->owner == dead_node) { list_del_init(&res->recovering); spin_lock(&res->spinlock); + /* new_master has our reference from + * the lock state sent during recovery */ dlm_change_lockres_owner(dlm, res, new_master); res->state &= ~DLM_LOCK_RES_RECOVERING; - if (!__dlm_lockres_unused(res)) + if (__dlm_lockres_has_locks(res)) __dlm_dirty_lockres(dlm, res); spin_unlock(&res->spinlock); wake_up(&res->wq); @@ -1977,9 +2070,11 @@ static void dlm_finish_local_lockres_recovery(struct dlm_ctxt *dlm, dlm_lockres_put(res); } spin_lock(&res->spinlock); + /* new_master has our reference from + * the lock state sent during recovery */ dlm_change_lockres_owner(dlm, res, new_master); res->state &= ~DLM_LOCK_RES_RECOVERING; - if (!__dlm_lockres_unused(res)) + if (__dlm_lockres_has_locks(res)) __dlm_dirty_lockres(dlm, res); spin_unlock(&res->spinlock); wake_up(&res->wq); @@ -2048,6 +2143,7 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm, { struct list_head *iter, *tmpiter; struct dlm_lock *lock; + unsigned int freed = 0; /* this node is the lockres master: * 1) remove any stale locks for the dead node @@ -2062,6 +2158,7 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm, if (lock->ml.node == dead_node) { list_del_init(&lock->list); dlm_lock_put(lock); + freed++; } } list_for_each_safe(iter, tmpiter, &res->converting) { @@ -2069,6 +2166,7 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm, if (lock->ml.node == dead_node) { list_del_init(&lock->list); dlm_lock_put(lock); + freed++; } } list_for_each_safe(iter, tmpiter, &res->blocked) { @@ -2076,9 +2174,23 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm, if (lock->ml.node == dead_node) { list_del_init(&lock->list); dlm_lock_put(lock); + freed++; } } + if (freed) { + mlog(0, "%s:%.*s: freed %u locks for dead node %u, " + "dropping ref from lockres\n", dlm->name, + res->lockname.len, res->lockname.name, freed, dead_node); + BUG_ON(!test_bit(dead_node, res->refmap)); + dlm_lockres_clear_refmap_bit(dead_node, res); + } else if (test_bit(dead_node, res->refmap)) { + mlog(0, "%s:%.*s: dead node %u had a ref, but had " + "no locks and had not purged before dying\n", dlm->name, + res->lockname.len, res->lockname.name, dead_node); + dlm_lockres_clear_refmap_bit(dead_node, res); + } + /* do not kick thread yet */ __dlm_dirty_lockres(dlm, res); } @@ -2141,9 +2253,21 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node) spin_lock(&res->spinlock); /* zero the lvb if necessary */ dlm_revalidate_lvb(dlm, res, dead_node); - if (res->owner == dead_node) + if (res->owner == dead_node) { + if (res->state & DLM_LOCK_RES_DROPPING_REF) + mlog(0, "%s:%.*s: owned by " + "dead node %u, this node was " + "dropping its ref when it died. " + "continue, dropping the flag.\n", + dlm->name, res->lockname.len, + res->lockname.name, dead_node); + + /* the wake_up for this will happen when the + * RECOVERING flag is dropped later */ + res->state &= ~DLM_LOCK_RES_DROPPING_REF; + dlm_move_lockres_to_recovery_list(dlm, res); - else if (res->owner == dlm->node_num) { + } else if (res->owner == dlm->node_num) { dlm_free_dead_locks(dlm, res, dead_node); __dlm_lockres_calc_usage(dlm, res); } @@ -2480,7 +2604,8 @@ retry: return ret; } -int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data) +int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_ctxt *dlm = data; struct dlm_begin_reco *br = (struct dlm_begin_reco *)msg->buf; @@ -2608,7 +2733,8 @@ stage2: return ret; } -int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data) +int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_ctxt *dlm = data; struct dlm_finalize_reco *fr = (struct dlm_finalize_reco *)msg->buf; diff --git a/fs/ocfs2/dlm/dlmthread.c b/fs/ocfs2/dlm/dlmthread.c index 0c822f3ffb05..8ffa0916eb86 100644 --- a/fs/ocfs2/dlm/dlmthread.c +++ b/fs/ocfs2/dlm/dlmthread.c @@ -54,9 +54,6 @@ #include "cluster/masklog.h" static int dlm_thread(void *data); -static void dlm_purge_lockres_now(struct dlm_ctxt *dlm, - struct dlm_lock_resource *lockres); - static void dlm_flush_asts(struct dlm_ctxt *dlm); #define dlm_lock_is_remote(dlm, lock) ((lock)->ml.node != (dlm)->node_num) @@ -82,14 +79,33 @@ repeat: current->state = TASK_RUNNING; } - -int __dlm_lockres_unused(struct dlm_lock_resource *res) +int __dlm_lockres_has_locks(struct dlm_lock_resource *res) { if (list_empty(&res->granted) && list_empty(&res->converting) && - list_empty(&res->blocked) && - list_empty(&res->dirty)) - return 1; + list_empty(&res->blocked)) + return 0; + return 1; +} + +/* "unused": the lockres has no locks, is not on the dirty list, + * has no inflight locks (in the gap between mastery and acquiring + * the first lock), and has no bits in its refmap. + * truly ready to be freed. */ +int __dlm_lockres_unused(struct dlm_lock_resource *res) +{ + if (!__dlm_lockres_has_locks(res) && + (list_empty(&res->dirty) && !(res->state & DLM_LOCK_RES_DIRTY))) { + /* try not to scan the bitmap unless the first two + * conditions are already true */ + int bit = find_next_bit(res->refmap, O2NM_MAX_NODES, 0); + if (bit >= O2NM_MAX_NODES) { + /* since the bit for dlm->node_num is not + * set, inflight_locks better be zero */ + BUG_ON(res->inflight_locks != 0); + return 1; + } + } return 0; } @@ -106,46 +122,21 @@ void __dlm_lockres_calc_usage(struct dlm_ctxt *dlm, assert_spin_locked(&res->spinlock); if (__dlm_lockres_unused(res)){ - /* For now, just keep any resource we master */ - if (res->owner == dlm->node_num) - { - if (!list_empty(&res->purge)) { - mlog(0, "we master %s:%.*s, but it is on " - "the purge list. Removing\n", - dlm->name, res->lockname.len, - res->lockname.name); - list_del_init(&res->purge); - dlm->purge_count--; - } - return; - } - if (list_empty(&res->purge)) { - mlog(0, "putting lockres %.*s from purge list\n", - res->lockname.len, res->lockname.name); + mlog(0, "putting lockres %.*s:%p onto purge list\n", + res->lockname.len, res->lockname.name, res); res->last_used = jiffies; + dlm_lockres_get(res); list_add_tail(&res->purge, &dlm->purge_list); dlm->purge_count++; - - /* if this node is not the owner, there is - * no way to keep track of who the owner could be. - * unhash it to avoid serious problems. */ - if (res->owner != dlm->node_num) { - mlog(0, "%s:%.*s: doing immediate " - "purge of lockres owned by %u\n", - dlm->name, res->lockname.len, - res->lockname.name, res->owner); - - dlm_purge_lockres_now(dlm, res); - } } } else if (!list_empty(&res->purge)) { - mlog(0, "removing lockres %.*s from purge list, " - "owner=%u\n", res->lockname.len, res->lockname.name, - res->owner); + mlog(0, "removing lockres %.*s:%p from purge list, owner=%u\n", + res->lockname.len, res->lockname.name, res, res->owner); list_del_init(&res->purge); + dlm_lockres_put(res); dlm->purge_count--; } } @@ -163,68 +154,65 @@ void dlm_lockres_calc_usage(struct dlm_ctxt *dlm, spin_unlock(&dlm->spinlock); } -/* TODO: Eventual API: Called with the dlm spinlock held, may drop it - * to do migration, but will re-acquire before exit. */ -void dlm_purge_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *lockres) +static int dlm_purge_lockres(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res) { int master; - int ret; + int ret = 0; - spin_lock(&lockres->spinlock); - master = lockres->owner == dlm->node_num; - spin_unlock(&lockres->spinlock); - - mlog(0, "purging lockres %.*s, master = %d\n", lockres->lockname.len, - lockres->lockname.name, master); - - /* Non master is the easy case -- no migration required, just - * quit. */ + spin_lock(&res->spinlock); + if (!__dlm_lockres_unused(res)) { + spin_unlock(&res->spinlock); + mlog(0, "%s:%.*s: tried to purge but not unused\n", + dlm->name, res->lockname.len, res->lockname.name); + return -ENOTEMPTY; + } + master = (res->owner == dlm->node_num); if (!master) - goto finish; + res->state |= DLM_LOCK_RES_DROPPING_REF; + spin_unlock(&res->spinlock); - /* Wheee! Migrate lockres here! */ - spin_unlock(&dlm->spinlock); -again: + mlog(0, "purging lockres %.*s, master = %d\n", res->lockname.len, + res->lockname.name, master); - ret = dlm_migrate_lockres(dlm, lockres, O2NM_MAX_NODES); - if (ret == -ENOTEMPTY) { - mlog(ML_ERROR, "lockres %.*s still has local locks!\n", - lockres->lockname.len, lockres->lockname.name); - - BUG(); - } else if (ret < 0) { - mlog(ML_NOTICE, "lockres %.*s: migrate failed, retrying\n", - lockres->lockname.len, lockres->lockname.name); - msleep(100); - goto again; + if (!master) { + spin_lock(&res->spinlock); + /* This ensures that clear refmap is sent after the set */ + __dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG); + spin_unlock(&res->spinlock); + /* drop spinlock to do messaging, retake below */ + spin_unlock(&dlm->spinlock); + /* clear our bit from the master's refmap, ignore errors */ + ret = dlm_drop_lockres_ref(dlm, res); + if (ret < 0) { + mlog_errno(ret); + if (!dlm_is_host_down(ret)) + BUG(); + } + mlog(0, "%s:%.*s: dlm_deref_lockres returned %d\n", + dlm->name, res->lockname.len, res->lockname.name, ret); + spin_lock(&dlm->spinlock); } - spin_lock(&dlm->spinlock); - -finish: - if (!list_empty(&lockres->purge)) { - list_del_init(&lockres->purge); + if (!list_empty(&res->purge)) { + mlog(0, "removing lockres %.*s:%p from purgelist, " + "master = %d\n", res->lockname.len, res->lockname.name, + res, master); + list_del_init(&res->purge); + dlm_lockres_put(res); dlm->purge_count--; } - __dlm_unhash_lockres(lockres); -} + __dlm_unhash_lockres(res); -/* make an unused lockres go away immediately. - * as soon as the dlm spinlock is dropped, this lockres - * will not be found. kfree still happens on last put. */ -static void dlm_purge_lockres_now(struct dlm_ctxt *dlm, - struct dlm_lock_resource *lockres) -{ - assert_spin_locked(&dlm->spinlock); - assert_spin_locked(&lockres->spinlock); - - BUG_ON(!__dlm_lockres_unused(lockres)); - - if (!list_empty(&lockres->purge)) { - list_del_init(&lockres->purge); - dlm->purge_count--; + /* lockres is not in the hash now. drop the flag and wake up + * any processes waiting in dlm_get_lock_resource. */ + if (!master) { + spin_lock(&res->spinlock); + res->state &= ~DLM_LOCK_RES_DROPPING_REF; + spin_unlock(&res->spinlock); + wake_up(&res->wq); } - __dlm_unhash_lockres(lockres); + return 0; } static void dlm_run_purge_list(struct dlm_ctxt *dlm, @@ -268,13 +256,17 @@ static void dlm_run_purge_list(struct dlm_ctxt *dlm, break; } + mlog(0, "removing lockres %.*s:%p from purgelist\n", + lockres->lockname.len, lockres->lockname.name, lockres); list_del_init(&lockres->purge); + dlm_lockres_put(lockres); dlm->purge_count--; /* This may drop and reacquire the dlm spinlock if it * has to do migration. */ mlog(0, "calling dlm_purge_lockres!\n"); - dlm_purge_lockres(dlm, lockres); + if (dlm_purge_lockres(dlm, lockres)) + BUG(); mlog(0, "DONE calling dlm_purge_lockres!\n"); /* Avoid adding any scheduling latencies */ @@ -467,12 +459,17 @@ void __dlm_dirty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) assert_spin_locked(&res->spinlock); /* don't shuffle secondary queues */ - if ((res->owner == dlm->node_num) && - !(res->state & DLM_LOCK_RES_DIRTY)) { - /* ref for dirty_list */ - dlm_lockres_get(res); - list_add_tail(&res->dirty, &dlm->dirty_list); - res->state |= DLM_LOCK_RES_DIRTY; + if ((res->owner == dlm->node_num)) { + if (res->state & (DLM_LOCK_RES_MIGRATING | + DLM_LOCK_RES_BLOCK_DIRTY)) + return; + + if (list_empty(&res->dirty)) { + /* ref for dirty_list */ + dlm_lockres_get(res); + list_add_tail(&res->dirty, &dlm->dirty_list); + res->state |= DLM_LOCK_RES_DIRTY; + } } } @@ -651,7 +648,7 @@ static int dlm_thread(void *data) dlm_lockres_get(res); spin_lock(&res->spinlock); - res->state &= ~DLM_LOCK_RES_DIRTY; + /* We clear the DLM_LOCK_RES_DIRTY state once we shuffle lists below */ list_del_init(&res->dirty); spin_unlock(&res->spinlock); spin_unlock(&dlm->spinlock); @@ -675,10 +672,11 @@ static int dlm_thread(void *data) /* it is now ok to move lockreses in these states * to the dirty list, assuming that they will only be * dirty for a short while. */ + BUG_ON(res->state & DLM_LOCK_RES_MIGRATING); if (res->state & (DLM_LOCK_RES_IN_PROGRESS | - DLM_LOCK_RES_MIGRATING | DLM_LOCK_RES_RECOVERING)) { /* move it to the tail and keep going */ + res->state &= ~DLM_LOCK_RES_DIRTY; spin_unlock(&res->spinlock); mlog(0, "delaying list shuffling for in-" "progress lockres %.*s, state=%d\n", @@ -699,6 +697,7 @@ static int dlm_thread(void *data) /* called while holding lockres lock */ dlm_shuffle_lists(dlm, res); + res->state &= ~DLM_LOCK_RES_DIRTY; spin_unlock(&res->spinlock); dlm_lockres_calc_usage(dlm, res); @@ -709,11 +708,8 @@ in_progress: /* if the lock was in-progress, stick * it on the back of the list */ if (delay) { - /* ref for dirty_list */ - dlm_lockres_get(res); spin_lock(&res->spinlock); - list_add_tail(&res->dirty, &dlm->dirty_list); - res->state |= DLM_LOCK_RES_DIRTY; + __dlm_dirty_lockres(dlm, res); spin_unlock(&res->spinlock); } dlm_lockres_put(res); diff --git a/fs/ocfs2/dlm/dlmunlock.c b/fs/ocfs2/dlm/dlmunlock.c index 37be4b2e0d4a..86ca085ef324 100644 --- a/fs/ocfs2/dlm/dlmunlock.c +++ b/fs/ocfs2/dlm/dlmunlock.c @@ -147,6 +147,10 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm, goto leave; } + if (res->state & DLM_LOCK_RES_MIGRATING) { + status = DLM_MIGRATING; + goto leave; + } /* see above for what the spec says about * LKM_CANCEL and the lock queue state */ @@ -244,8 +248,8 @@ leave: /* this should always be coupled with list removal */ BUG_ON(!(actions & DLM_UNLOCK_REMOVE_LOCK)); mlog(0, "lock %u:%llu should be gone now! refs=%d\n", - dlm_get_lock_cookie_node(lock->ml.cookie), - dlm_get_lock_cookie_seq(lock->ml.cookie), + dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), + dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)), atomic_read(&lock->lock_refs.refcount)-1); dlm_lock_put(lock); } @@ -379,7 +383,8 @@ static enum dlm_status dlm_send_remote_unlock_request(struct dlm_ctxt *dlm, * returns: DLM_NORMAL, DLM_BADARGS, DLM_IVLOCKID, * return value from dlmunlock_master */ -int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data) +int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data, + void **ret_data) { struct dlm_ctxt *dlm = data; struct dlm_unlock_lock *unlock = (struct dlm_unlock_lock *)msg->buf; @@ -502,8 +507,8 @@ not_found: if (!found) mlog(ML_ERROR, "failed to find lock to unlock! " "cookie=%u:%llu\n", - dlm_get_lock_cookie_node(unlock->cookie), - dlm_get_lock_cookie_seq(unlock->cookie)); + dlm_get_lock_cookie_node(be64_to_cpu(unlock->cookie)), + dlm_get_lock_cookie_seq(be64_to_cpu(unlock->cookie))); else dlm_lock_put(lock); diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index e1216364d191..d026b4f27757 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h @@ -306,8 +306,8 @@ int ocfs2_journal_dirty_data(handle_t *handle, * for the dinode, one for the new block. */ #define OCFS2_SIMPLE_DIR_EXTEND_CREDITS (2) -/* file update (nlink, etc) + dir entry block */ -#define OCFS2_LINK_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) +/* file update (nlink, etc) + directory mtime/ctime + dir entry block */ +#define OCFS2_LINK_CREDITS (2*OCFS2_INODE_UPDATE_CREDITS + 1) /* inode + dir inode (if we unlink a dir), + dir entry block + orphan * dir inode link */ diff --git a/fs/ocfs2/vote.c b/fs/ocfs2/vote.c index 0afd8b9af70f..f30e63b9910c 100644 --- a/fs/ocfs2/vote.c +++ b/fs/ocfs2/vote.c @@ -887,7 +887,7 @@ static inline int ocfs2_translate_response(int response) static int ocfs2_handle_response_message(struct o2net_msg *msg, u32 len, - void *data) + void *data, void **ret_data) { unsigned int response_id, node_num; int response_status; @@ -943,7 +943,7 @@ bail: static int ocfs2_handle_vote_message(struct o2net_msg *msg, u32 len, - void *data) + void *data, void **ret_data) { int status; struct ocfs2_super *osb = data; @@ -1007,7 +1007,7 @@ int ocfs2_register_net_handlers(struct ocfs2_super *osb) osb->net_key, sizeof(struct ocfs2_response_msg), ocfs2_handle_response_message, - osb, &osb->osb_net_handlers); + osb, NULL, &osb->osb_net_handlers); if (status) { mlog_errno(status); goto bail; @@ -1017,7 +1017,7 @@ int ocfs2_register_net_handlers(struct ocfs2_super *osb) osb->net_key, sizeof(struct ocfs2_vote_msg), ocfs2_handle_vote_message, - osb, &osb->osb_net_handlers); + osb, NULL, &osb->osb_net_handlers); if (status) { mlog_errno(status); goto bail; diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index e8f540d38d48..d3b9f5f07db1 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -16,6 +16,7 @@ #include #include +#include #include "sysfs.h" @@ -146,7 +147,7 @@ static int open(struct inode * inode, struct file * file) Error: module_put(attr->attr.owner); Done: - if (error && kobj) + if (error) kobject_put(kobj); return error; } @@ -157,8 +158,7 @@ static int release(struct inode * inode, struct file * file) struct bin_attribute * attr = to_bin_attr(file->f_path.dentry); u8 * buffer = file->private_data; - if (kobj) - kobject_put(kobj); + kobject_put(kobj); module_put(attr->attr.owner); kfree(buffer); return 0; diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 511edef8b321..9dcdf556c99c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "sysfs.h" DECLARE_RWSEM(sysfs_rename_sem); @@ -32,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; @@ -45,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 @@ -77,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; @@ -94,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) @@ -165,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; @@ -177,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; @@ -298,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; @@ -333,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); @@ -366,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; @@ -378,12 +427,10 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent) struct sysfs_dirent *new_parent_sd, *sd; int error; - if (!new_parent) - return -EINVAL; - old_parent_dentry = kobj->parent ? kobj->parent->dentry : sysfs_mount->mnt_sb->s_root; - new_parent_dentry = new_parent->dentry; + new_parent_dentry = new_parent ? + new_parent->dentry : sysfs_mount->mnt_sb->s_root; again: mutex_lock(&old_parent_dentry->d_inode->i_mutex); @@ -547,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/file.c b/fs/sysfs/file.c index 9cfe53e1e00d..c0e117649a4d 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -50,17 +51,29 @@ static struct sysfs_ops subsys_sysfs_ops = { .store = subsys_attr_store, }; +/** + * add_to_collection - add buffer to a collection + * @buffer: buffer to be added + * @node inode of set to add to + */ -struct sysfs_buffer { - size_t count; - loff_t pos; - char * page; - struct sysfs_ops * ops; - struct semaphore sem; - int needs_read_fill; - int event; -}; +static inline void +add_to_collection(struct sysfs_buffer *buffer, struct inode *node) +{ + struct sysfs_buffer_collection *set = node->i_private; + mutex_lock(&node->i_mutex); + list_add(&buffer->associates, &set->associates); + mutex_unlock(&node->i_mutex); +} + +static inline void +remove_from_collection(struct sysfs_buffer *buffer, struct inode *node) +{ + mutex_lock(&node->i_mutex); + list_del(&buffer->associates); + mutex_unlock(&node->i_mutex); +} /** * fill_read_buffer - allocate and fill buffer from object. @@ -70,7 +83,8 @@ struct sysfs_buffer { * Allocate @buffer->page, if it hasn't been already, then call the * kobject's show() method to fill the buffer with this attribute's * data. - * This is called only once, on the file's first read. + * This is called only once, on the file's first read unless an error + * is returned. */ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) { @@ -88,12 +102,13 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer buffer->event = atomic_read(&sd->s_event); count = ops->show(kobj,attr,buffer->page); - buffer->needs_read_fill = 0; BUG_ON(count > (ssize_t)PAGE_SIZE); - if (count >= 0) + if (count >= 0) { + buffer->needs_read_fill = 0; buffer->count = count; - else + } else { ret = count; + } return ret; } @@ -153,6 +168,10 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) ssize_t retval = 0; down(&buffer->sem); + if (buffer->orphaned) { + retval = -ENODEV; + goto out; + } if (buffer->needs_read_fill) { if ((retval = fill_read_buffer(file->f_path.dentry,buffer))) goto out; @@ -165,7 +184,6 @@ out: return retval; } - /** * fill_write_buffer - copy buffer from userspace. * @buffer: data buffer for file. @@ -243,19 +261,25 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t ssize_t len; down(&buffer->sem); + if (buffer->orphaned) { + len = -ENODEV; + goto out; + } len = fill_write_buffer(buffer, buf, count); if (len > 0) len = flush_write_buffer(file->f_path.dentry, buffer, len); if (len > 0) *ppos += len; +out: up(&buffer->sem); return len; } -static int check_perm(struct inode * inode, struct file * file) +static int sysfs_open_file(struct inode *inode, struct file *file) { struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent); struct attribute * attr = to_attr(file->f_path.dentry); + struct sysfs_buffer_collection *set; struct sysfs_buffer * buffer; struct sysfs_ops * ops = NULL; int error = 0; @@ -285,6 +309,18 @@ static int check_perm(struct inode * inode, struct file * file) if (!ops) goto Eaccess; + /* make sure we have a collection to add our buffers to */ + mutex_lock(&inode->i_mutex); + if (!(set = inode->i_private)) { + if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) { + error = -ENOMEM; + goto Done; + } else { + INIT_LIST_HEAD(&set->associates); + } + } + mutex_unlock(&inode->i_mutex); + /* File needs write support. * The inode's perms must say it's ok, * and we must have a store method. @@ -310,9 +346,11 @@ static int check_perm(struct inode * inode, struct file * file) */ buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); if (buffer) { + INIT_LIST_HEAD(&buffer->associates); init_MUTEX(&buffer->sem); buffer->needs_read_fill = 1; buffer->ops = ops; + add_to_collection(buffer, inode); file->private_data = buffer; } else error = -ENOMEM; @@ -325,16 +363,11 @@ static int check_perm(struct inode * inode, struct file * file) error = -EACCES; module_put(attr->owner); Done: - if (error && kobj) + if (error) kobject_put(kobj); return error; } -static int sysfs_open_file(struct inode * inode, struct file * filp) -{ - return check_perm(inode,filp); -} - static int sysfs_release(struct inode * inode, struct file * filp) { struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent); @@ -342,8 +375,9 @@ static int sysfs_release(struct inode * inode, struct file * filp) struct module * owner = attr->owner; struct sysfs_buffer * buffer = filp->private_data; - if (kobj) - kobject_put(kobj); + if (buffer) + remove_from_collection(buffer, inode); + kobject_put(kobj); /* After this point, attr should not be accessed. */ module_put(owner); @@ -548,7 +582,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file); void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) { - sysfs_hash_and_remove(kobj->dentry,attr->name); + sysfs_hash_and_remove(kobj->dentry, attr->name); } diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 122145b0895c..b20951c93761 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include "sysfs.h" diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index e79e38d52c00..542d2bcc73df 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "sysfs.h" extern struct super_block * sysfs_sb; @@ -32,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; @@ -209,6 +220,22 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd) return NULL; } +static inline void orphan_all_buffers(struct inode *node) +{ + struct sysfs_buffer_collection *set = node->i_private; + struct sysfs_buffer *buf; + + mutex_lock_nested(&node->i_mutex, I_MUTEX_CHILD); + if (node->i_private) { + list_for_each_entry(buf, &set->associates, associates) { + down(&buf->sem); + buf->orphaned = 1; + up(&buf->sem); + } + } + mutex_unlock(&node->i_mutex); +} + /* * Unhashes the dentry corresponding to given sysfs_dirent @@ -217,16 +244,23 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd) void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) { struct dentry * dentry = sd->s_dentry; + struct inode *inode; if (dentry) { spin_lock(&dcache_lock); spin_lock(&dentry->d_lock); if (!(d_unhashed(dentry) && dentry->d_inode)) { + inode = dentry->d_inode; + spin_lock(&inode->i_lock); + __iget(inode); + spin_unlock(&inode->i_lock); dget_locked(dentry); __d_drop(dentry); spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock); simple_unlink(parent->d_inode, dentry); + orphan_all_buffers(inode); + iput(inode); } else { spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock); @@ -248,7 +282,7 @@ int sysfs_hash_and_remove(struct dentry * dir, const char * name) return -ENOENT; parent_sd = dir->d_fsdata; - mutex_lock(&dir->d_inode->i_mutex); + mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { if (!sd->s_element) continue; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index e503f858fba8..f6a87a824883 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "sysfs.h" @@ -18,9 +19,12 @@ struct vfsmount *sysfs_mount; struct super_block * sysfs_sb = NULL; struct kmem_cache *sysfs_dir_cachep; +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, }; static struct sysfs_dirent sysfs_root = { @@ -31,6 +35,11 @@ static struct sysfs_dirent sysfs_root = { .s_iattr = NULL, }; +static void sysfs_clear_inode(struct inode *inode) +{ + kfree(inode->i_private); +} + static int sysfs_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index f50e3cc2ded8..4869f611192f 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "sysfs.h" diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index bd7cec295dab..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 *)); @@ -33,6 +34,22 @@ struct sysfs_symlink { struct kobject * target_kobj; }; +struct sysfs_buffer { + struct list_head associates; + size_t count; + loff_t pos; + char * page; + struct sysfs_ops * ops; + struct semaphore sem; + int orphaned; + int needs_read_fill; + int event; +}; + +struct sysfs_buffer_collection { + struct list_head associates; +}; + static inline struct kobject * to_kobj(struct dentry * dentry) { struct sysfs_dirent * sd = dentry->d_fsdata; @@ -96,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/acpi/acconfig.h b/include/acpi/acconfig.h index ebc1f697615a..422f29c06c77 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,7 +63,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20060707 +#define ACPI_CA_VERSION 0x20070126 /* * OS name, used for the _OS object. The _OS object is essentially obsolete, @@ -115,6 +115,10 @@ #define ACPI_NUM_OWNERID_MASKS 8 +/* Size of the root table array is increased by this increment */ + +#define ACPI_ROOT_TABLE_SIZE_INCREMENT 4 + /****************************************************************************** * * ACPI Specification constants (Do not change unless the specification changes) @@ -152,6 +156,11 @@ #define ACPI_PATH_SEGMENT_LENGTH 5 /* 4 chars for name + 1 char for separator */ #define ACPI_PATH_SEPARATOR '.' +/* Sizes for ACPI table headers */ + +#define ACPI_OEM_ID_SIZE 6 +#define ACPI_OEM_TABLE_ID_SIZE 8 + /* Constants used in searching for the RSDP in low memory */ #define ACPI_EBDA_PTR_LOCATION 0x0000040E /* Physical Address */ diff --git a/include/acpi/acdebug.h b/include/acpi/acdebug.h index d8167095caf3..d626bb1d2973 100644 --- a/include/acpi/acdebug.h +++ b/include/acpi/acdebug.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -159,6 +159,10 @@ void acpi_db_create_execution_threads(char *num_threads_arg, char *num_loops_arg, char *method_name_arg); +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +u32 acpi_db_get_cache_info(struct acpi_memory_list *cache); +#endif + /* * dbfileio - Debugger file I/O commands */ @@ -214,4 +218,6 @@ void acpi_db_prep_namestring(char *name); struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name); +void acpi_db_uint32_to_hex_string(u32 value, char *buffer); + #endif /* __ACDEBUG_H__ */ diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h index 9a7d6921f534..389d772c7d5b 100644 --- a/include/acpi/acdisasm.h +++ b/include/acpi/acdisasm.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -97,9 +97,11 @@ typedef const struct acpi_dmtable_info { #define ACPI_DMT_CHKSUM 20 #define ACPI_DMT_SPACEID 21 #define ACPI_DMT_GAS 22 -#define ACPI_DMT_MADT 23 -#define ACPI_DMT_SRAT 24 -#define ACPI_DMT_EXIT 25 +#define ACPI_DMT_DMAR 23 +#define ACPI_DMT_MADT 24 +#define ACPI_DMT_SRAT 25 +#define ACPI_DMT_EXIT 26 +#define ACPI_DMT_SIG 27 typedef void (*ACPI_TABLE_HANDLER) (struct acpi_table_header * table); @@ -108,6 +110,7 @@ struct acpi_dmtable_data { char *signature; struct acpi_dmtable_info *table_info; ACPI_TABLE_HANDLER table_handler; + char *name; }; struct acpi_op_walk_info { @@ -139,7 +142,9 @@ extern const char *acpi_gbl_match_ops[]; extern struct acpi_dmtable_info acpi_dm_table_info_asf0[]; extern struct acpi_dmtable_info acpi_dm_table_info_asf1[]; +extern struct acpi_dmtable_info acpi_dm_table_info_asf1a[]; extern struct acpi_dmtable_info acpi_dm_table_info_asf2[]; +extern struct acpi_dmtable_info acpi_dm_table_info_asf2a[]; extern struct acpi_dmtable_info acpi_dm_table_info_asf3[]; extern struct acpi_dmtable_info acpi_dm_table_info_asf4[]; extern struct acpi_dmtable_info acpi_dm_table_info_asf_hdr[]; @@ -147,6 +152,11 @@ extern struct acpi_dmtable_info acpi_dm_table_info_boot[]; extern struct acpi_dmtable_info acpi_dm_table_info_cpep[]; extern struct acpi_dmtable_info acpi_dm_table_info_cpep0[]; extern struct acpi_dmtable_info acpi_dm_table_info_dbgp[]; +extern struct acpi_dmtable_info acpi_dm_table_info_dmar[]; +extern struct acpi_dmtable_info acpi_dm_table_info_dmar_hdr[]; +extern struct acpi_dmtable_info acpi_dm_table_info_dmar_scope[]; +extern struct acpi_dmtable_info acpi_dm_table_info_dmar0[]; +extern struct acpi_dmtable_info acpi_dm_table_info_dmar1[]; extern struct acpi_dmtable_info acpi_dm_table_info_ecdt[]; extern struct acpi_dmtable_info acpi_dm_table_info_facs[]; extern struct acpi_dmtable_info acpi_dm_table_info_fadt1[]; @@ -201,6 +211,8 @@ void acpi_dm_dump_asf(struct acpi_table_header *table); void acpi_dm_dump_cpep(struct acpi_table_header *table); +void acpi_dm_dump_dmar(struct acpi_table_header *table); + void acpi_dm_dump_fadt(struct acpi_table_header *table); void acpi_dm_dump_srat(struct acpi_table_header *table); @@ -314,7 +326,7 @@ acpi_dm_resource_template(struct acpi_op_walk_info *info, union acpi_parse_object *op, u8 * byte_data, u32 byte_count); -u8 acpi_dm_is_resource_template(union acpi_parse_object *op); +acpi_status acpi_dm_is_resource_template(union acpi_parse_object *op); void acpi_dm_indent(u32 level); diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h index a22fe9cf8493..cb8d2868c8ac 100644 --- a/include/acpi/acdispat.h +++ b/include/acpi/acdispat.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -210,7 +210,7 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state); * dsinit */ acpi_status -acpi_ds_initialize_objects(struct acpi_table_desc *table_desc, +acpi_ds_initialize_objects(acpi_native_uint table_index, struct acpi_namespace_node *start_node); /* diff --git a/include/acpi/acevents.h b/include/acpi/acevents.h index 234142828e1a..d23cdf326808 100644 --- a/include/acpi/acevents.h +++ b/include/acpi/acevents.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h index 797ca1ea5214..b73f18a48785 100644 --- a/include/acpi/acexcep.h +++ b/include/acpi/acexcep.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -178,8 +178,10 @@ #define AE_CTRL_BREAK (acpi_status) (0x0009 | AE_CODE_CONTROL) #define AE_CTRL_CONTINUE (acpi_status) (0x000A | AE_CODE_CONTROL) #define AE_CTRL_SKIP (acpi_status) (0x000B | AE_CODE_CONTROL) +#define AE_CTRL_PARSE_CONTINUE (acpi_status) (0x000C | AE_CODE_CONTROL) +#define AE_CTRL_PARSE_PENDING (acpi_status) (0x000D | AE_CODE_CONTROL) -#define AE_CODE_CTRL_MAX 0x000B +#define AE_CODE_CTRL_MAX 0x000D #ifdef DEFINE_ACPI_GLOBALS @@ -291,7 +293,9 @@ char const *acpi_gbl_exception_names_ctrl[] = { "AE_CTRL_TRANSFER", "AE_CTRL_BREAK", "AE_CTRL_CONTINUE", - "AE_CTRL_SKIP" + "AE_CTRL_SKIP", + "AE_CTRL_PARSE_CONTINUE", + "AE_CTRL_PARSE_PENDING" }; #endif /* ACPI GLOBALS */ diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h index 06972e6637de..24c3f05ab367 100644 --- a/include/acpi/acglobal.h +++ b/include/acpi/acglobal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -58,37 +58,6 @@ #define ACPI_INIT_GLOBAL(a,b) a #endif -/* - * Keep local copies of these FADT-based registers. NOTE: These globals - * are first in this file for alignment reasons on 64-bit systems. - */ -ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; -ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; - -/***************************************************************************** - * - * Debug support - * - ****************************************************************************/ - -/* Runtime configuration of debug print levels */ - -extern u32 acpi_dbg_level; -extern u32 acpi_dbg_layer; - -/* Procedure nesting level for debug output */ - -extern u32 acpi_gbl_nesting_level; - -/* Support for dynamic control method tracing mechanism */ - -ACPI_EXTERN u32 acpi_gbl_original_dbg_level; -ACPI_EXTERN u32 acpi_gbl_original_dbg_layer; -ACPI_EXTERN acpi_name acpi_gbl_trace_method_name; -ACPI_EXTERN u32 acpi_gbl_trace_dbg_level; -ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer; -ACPI_EXTERN u32 acpi_gbl_trace_flags; - /***************************************************************************** * * Runtime configuration (static defaults that can be overriden at runtime) @@ -133,6 +102,34 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE); */ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE); +/***************************************************************************** + * + * Debug support + * + ****************************************************************************/ + +/* Runtime configuration of debug print levels */ + +extern u32 acpi_dbg_level; +extern u32 acpi_dbg_layer; + +/* Procedure nesting level for debug output */ + +extern u32 acpi_gbl_nesting_level; + +/* Event counters */ + +ACPI_EXTERN u32 acpi_gpe_count; + +/* Support for dynamic control method tracing mechanism */ + +ACPI_EXTERN u32 acpi_gbl_original_dbg_level; +ACPI_EXTERN u32 acpi_gbl_original_dbg_layer; +ACPI_EXTERN acpi_name acpi_gbl_trace_method_name; +ACPI_EXTERN u32 acpi_gbl_trace_dbg_level; +ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer; +ACPI_EXTERN u32 acpi_gbl_trace_flags; + /***************************************************************************** * * ACPI Table globals @@ -140,47 +137,29 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE); ****************************************************************************/ /* - * Table pointers. - * Although these pointers are somewhat redundant with the global acpi_table, - * they are convenient because they are typed pointers. + * acpi_gbl_root_table_list is the master list of ACPI tables found in the + * RSDT/XSDT. * - * These tables are single-table only; meaning that there can be at most one - * of each in the system. Each global points to the actual table. - */ -ACPI_EXTERN u32 acpi_gbl_table_flags; -ACPI_EXTERN u32 acpi_gbl_rsdt_table_count; -ACPI_EXTERN struct rsdp_descriptor *acpi_gbl_RSDP; -ACPI_EXTERN struct xsdt_descriptor *acpi_gbl_XSDT; -ACPI_EXTERN struct fadt_descriptor *acpi_gbl_FADT; -ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT; -ACPI_EXTERN struct facs_descriptor *acpi_gbl_FACS; -ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS; -/* - * Since there may be multiple SSDTs and PSDTs, a single pointer is not - * sufficient; Therefore, there isn't one! + * acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */ +ACPI_EXTERN struct acpi_internal_rsdt acpi_gbl_root_table_list; +ACPI_EXTERN struct acpi_table_fadt acpi_gbl_FADT; +extern acpi_native_uint acpi_gbl_permanent_mmap; -/* The root table can be either an RSDT or an XSDT */ +/* These addresses are calculated from FADT address values */ -ACPI_EXTERN u8 acpi_gbl_root_table_type; -#define ACPI_TABLE_TYPE_RSDT 'R' -#define ACPI_TABLE_TYPE_XSDT 'X' +ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; +ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; /* - * Handle both ACPI 1.0 and ACPI 2.0 Integer widths: - * If we are executing a method that exists in a 32-bit ACPI table, - * use only the lower 32 bits of the (internal) 64-bit Integer. + * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is + * determined by the revision of the DSDT: If the DSDT revision is less than + * 2, use only the lower 32 bits of the internal 64-bit Integer. */ ACPI_EXTERN u8 acpi_gbl_integer_bit_width; ACPI_EXTERN u8 acpi_gbl_integer_byte_width; ACPI_EXTERN u8 acpi_gbl_integer_nybble_width; -/* - * ACPI Table info arrays - */ -extern struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1]; -extern struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1]; - /***************************************************************************** * * Mutual exlusion within ACPICA subsystem @@ -188,7 +167,7 @@ extern struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1]; ****************************************************************************/ /* - * Predefined mutex objects. This array contains the + * Predefined mutex objects. This array contains the * actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs. * (The table maps local handles to the real OS handles) */ @@ -197,6 +176,7 @@ ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[ACPI_NUM_MUTEX]; /* * Global lock semaphore works in conjunction with the actual HW global lock */ +ACPI_EXTERN acpi_mutex acpi_gbl_global_lock_mutex; ACPI_EXTERN acpi_semaphore acpi_gbl_global_lock_semaphore; /* @@ -220,6 +200,7 @@ ACPI_EXTERN spinlock_t _acpi_gbl_hardware_lock; /* For ACPI H/W except GPE regis ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list; ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list; +ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats; #endif /* Object caches */ @@ -240,7 +221,6 @@ ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk; /* Misc */ -ACPI_EXTERN u32 acpi_gbl_global_lock_thread_count; ACPI_EXTERN u32 acpi_gbl_original_mode; ACPI_EXTERN u32 acpi_gbl_rsdp_original_location; ACPI_EXTERN u32 acpi_gbl_ns_lookup_count; @@ -260,12 +240,19 @@ ACPI_EXTERN u8 acpi_gbl_system_awake_and_running; extern u8 acpi_gbl_shutdown; extern u32 acpi_gbl_startup_flags; -extern const u8 acpi_gbl_decode_to8bit[8]; extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT]; extern const char *acpi_gbl_highest_dstate_names[4]; extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS]; +/* Exception codes */ + +extern char const *acpi_gbl_exception_names_env[]; +extern char const *acpi_gbl_exception_names_pgm[]; +extern char const *acpi_gbl_exception_names_tbl[]; +extern char const *acpi_gbl_exception_names_aml[]; +extern char const *acpi_gbl_exception_names_ctrl[]; + /***************************************************************************** * * Namespace globals diff --git a/include/acpi/achware.h b/include/acpi/achware.h index 29b60a8c0593..9df275cf7bc1 100644 --- a/include/acpi/achware.h +++ b/include/acpi/achware.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -61,8 +61,6 @@ /* * hwacpi - high level functions */ -acpi_status acpi_hw_initialize(void); - acpi_status acpi_hw_set_mode(u32 mode); u32 acpi_hw_get_mode(void); @@ -84,7 +82,7 @@ acpi_hw_low_level_read(u32 width, acpi_status acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address *reg); -acpi_status acpi_hw_clear_acpi_status(u32 flags); +acpi_status acpi_hw_clear_acpi_status(void); /* * hwgpe - GPE support diff --git a/include/acpi/acinterp.h b/include/acpi/acinterp.h index 91586d0d5bb5..ce7c9d653910 100644 --- a/include/acpi/acinterp.h +++ b/include/acpi/acinterp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -277,12 +277,6 @@ acpi_status acpi_ex_system_do_suspend(acpi_integer time); acpi_status acpi_ex_system_do_stall(u32 time); -acpi_status -acpi_ex_system_acquire_mutex(union acpi_operand_object *time, - union acpi_operand_object *obj_desc); - -acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc); - acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc); acpi_status @@ -451,10 +445,14 @@ acpi_ex_copy_integer_to_buffer_field(union acpi_operand_object *source_desc, /* * exutils - interpreter/scanner utilities */ -acpi_status acpi_ex_enter_interpreter(void); +void acpi_ex_enter_interpreter(void); void acpi_ex_exit_interpreter(void); +void acpi_ex_reacquire_interpreter(void); + +void acpi_ex_relinquish_interpreter(void); + void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc); u8 acpi_ex_acquire_global_lock(u32 rule); diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h index 063c4b54290f..6f83ddbed3af 100644 --- a/include/acpi/aclocal.h +++ b/include/acpi/aclocal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -80,8 +80,8 @@ union acpi_parse_object; * table below also! */ #define ACPI_MTX_INTERPRETER 0 /* AML Interpreter, main lock */ -#define ACPI_MTX_TABLES 1 /* Data for ACPI tables */ -#define ACPI_MTX_NAMESPACE 2 /* ACPI Namespace */ +#define ACPI_MTX_NAMESPACE 1 /* ACPI Namespace */ +#define ACPI_MTX_TABLES 2 /* Data for ACPI tables */ #define ACPI_MTX_EVENTS 3 /* Data for ACPI events */ #define ACPI_MTX_CACHES 4 /* Internal caches, general purposes */ #define ACPI_MTX_MEMORY 5 /* Debug memory tracking lists */ @@ -162,7 +162,7 @@ struct acpi_mutex_info { typedef enum { ACPI_IMODE_LOAD_PASS1 = 0x01, ACPI_IMODE_LOAD_PASS2 = 0x02, - ACPI_IMODE_EXECUTE = 0x0E + ACPI_IMODE_EXECUTE = 0x03 } acpi_interpreter_mode; union acpi_name_union { @@ -204,7 +204,7 @@ struct acpi_namespace_node { /* Namespace Node flags */ #define ANOBJ_END_OF_PEER_LIST 0x01 /* End-of-list, Peer field points to parent */ -#define ANOBJ_RESERVED 0x02 /* Available for future use */ +#define ANOBJ_TEMPORARY 0x02 /* Node is create by a method and is temporary */ #define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */ #define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ #define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ @@ -219,25 +219,42 @@ struct acpi_namespace_node { * ACPI Table Descriptor. One per ACPI table */ struct acpi_table_desc { - struct acpi_table_desc *prev; - struct acpi_table_desc *next; - struct acpi_table_desc *installed_desc; + acpi_physical_address address; struct acpi_table_header *pointer; - u8 *aml_start; - u64 physical_address; - acpi_size length; - u32 aml_length; + u32 length; /* Length fixed at 32 bits */ + union acpi_name_union signature; acpi_owner_id owner_id; - u8 type; - u8 allocation; - u8 loaded_into_namespace; + u8 flags; }; -struct acpi_table_list { - struct acpi_table_desc *next; +/* Flags for above */ + +#define ACPI_TABLE_ORIGIN_UNKNOWN (0) +#define ACPI_TABLE_ORIGIN_MAPPED (1) +#define ACPI_TABLE_ORIGIN_ALLOCATED (2) +#define ACPI_TABLE_ORIGIN_MASK (3) +#define ACPI_TABLE_IS_LOADED (4) + +/* One internal RSDT for table management */ + +struct acpi_internal_rsdt { + struct acpi_table_desc *tables; u32 count; + u32 size; + u8 flags; }; +/* Flags for above */ + +#define ACPI_ROOT_ORIGIN_UNKNOWN (0) /* ~ORIGIN_ALLOCATED */ +#define ACPI_ROOT_ORIGIN_ALLOCATED (1) +#define ACPI_ROOT_ALLOW_RESIZE (2) + +/* Predefined (fixed) table indexes */ + +#define ACPI_TABLE_INDEX_DSDT (0) +#define ACPI_TABLE_INDEX_FACS (1) + struct acpi_find_context { char *search_for; acpi_handle *list; @@ -350,7 +367,7 @@ struct acpi_gpe_event_info { union acpi_gpe_dispatch_info dispatch; /* Either Method or Handler */ struct acpi_gpe_register_info *register_info; /* Backpointer to register info */ u8 flags; /* Misc info about this GPE */ - u8 register_bit; /* This GPE bit within the register */ + u8 gpe_number; /* This GPE */ }; /* Information about a GPE register pair, one per each status/enable pair in an array */ @@ -855,12 +872,30 @@ struct acpi_bit_register_info { ****************************************************************************/ struct acpi_db_method_info { - acpi_handle thread_gate; + acpi_handle main_thread_gate; + acpi_handle thread_complete_gate; + u32 *threads; + u32 num_threads; + u32 num_created; + u32 num_completed; + char *name; - char **args; u32 flags; u32 num_loops; char pathname[128]; + char **args; + + /* + * Arguments to be passed to method for the command + * Threads - + * the Number of threads, ID of current thread and + * Index of current thread inside all them created. + */ + char init_args; + char *arguments[4]; + char num_threads_str[11]; + char id_of_thread_str[11]; + char index_of_thread_str[11]; }; struct acpi_integrity_info { @@ -919,6 +954,8 @@ struct acpi_memory_list { u32 total_allocated; u32 total_freed; + u32 max_occupied; + u32 total_size; u32 current_total_size; u32 requests; u32 hits; diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h index 192fa095a515..8948a6461834 100644 --- a/include/acpi/acmacros.h +++ b/include/acpi/acmacros.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,25 +55,12 @@ #define ACPI_SET_BIT(target,bit) ((target) |= (bit)) #define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit)) #define ACPI_MIN(a,b) (((a)<(b))?(a):(b)) +#define ACPI_MAX(a,b) (((a)>(b))?(a):(b)) /* Size calculation */ #define ACPI_ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0])) -#if ACPI_MACHINE_WIDTH == 16 - -/* - * For 16-bit addresses, we have to assume that the upper 32 bits - * (out of 64) are zero. - */ -#define ACPI_LODWORD(l) ((u32)(l)) -#define ACPI_HIDWORD(l) ((u32)(0)) - -#define ACPI_GET_ADDRESS(a) ((a).lo) -#define ACPI_STORE_ADDRESS(a,b) {(a).hi=0;(a).lo=(u32)(b);} -#define ACPI_VALID_ADDRESS(a) ((a).hi | (a).lo) - -#else #ifdef ACPI_NO_INTEGER64_SUPPORT /* * acpi_integer is 32-bits, no 64-bit support on this platform @@ -81,10 +68,6 @@ #define ACPI_LODWORD(l) ((u32)(l)) #define ACPI_HIDWORD(l) ((u32)(0)) -#define ACPI_GET_ADDRESS(a) (a) -#define ACPI_STORE_ADDRESS(a,b) ((a)=(b)) -#define ACPI_VALID_ADDRESS(a) (a) - #else /* @@ -92,11 +75,6 @@ */ #define ACPI_LODWORD(l) ((u32)(u64)(l)) #define ACPI_HIDWORD(l) ((u32)(((*(struct uint64_struct *)(void *)(&l))).hi)) - -#define ACPI_GET_ADDRESS(a) (a) -#define ACPI_STORE_ADDRESS(a,b) ((a)=(acpi_physical_address)(b)) -#define ACPI_VALID_ADDRESS(a) (a) -#endif #endif /* @@ -134,15 +112,8 @@ #define ACPI_TO_POINTER(i) ACPI_ADD_PTR (void,(void *) NULL,(acpi_native_uint) i) #define ACPI_TO_INTEGER(p) ACPI_PTR_DIFF (p,(void *) NULL) #define ACPI_OFFSET(d,f) (acpi_size) ACPI_PTR_DIFF (&(((d *)0)->f),(void *) NULL) - -#if ACPI_MACHINE_WIDTH == 16 -#define ACPI_STORE_POINTER(d,s) ACPI_MOVE_32_TO_32(d,s) -#define ACPI_PHYSADDR_TO_PTR(i) (void *)(i) -#define ACPI_PTR_TO_PHYSADDR(i) (u32) ACPI_CAST_PTR (u8,(i)) -#else #define ACPI_PHYSADDR_TO_PTR(i) ACPI_TO_POINTER(i) #define ACPI_PTR_TO_PHYSADDR(i) ACPI_TO_INTEGER(i) -#endif #ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED #define ACPI_COMPARE_NAME(a,b) (*ACPI_CAST_PTR (u32,(a)) == *ACPI_CAST_PTR (u32,(b))) @@ -223,28 +194,6 @@ /* The hardware supports unaligned transfers, just do the little-endian move */ -#if ACPI_MACHINE_WIDTH == 16 - -/* No 64-bit integers */ -/* 16-bit source, 16/32/64 destination */ - -#define ACPI_MOVE_16_TO_16(d,s) *(u16 *)(void *)(d) = *(u16 *)(void *)(s) -#define ACPI_MOVE_16_TO_32(d,s) *(u32 *)(void *)(d) = *(u16 *)(void *)(s) -#define ACPI_MOVE_16_TO_64(d,s) ACPI_MOVE_16_TO_32(d,s) - -/* 32-bit source, 16/32/64 destination */ - -#define ACPI_MOVE_32_TO_16(d,s) ACPI_MOVE_16_TO_16(d,s) /* Truncate to 16 */ -#define ACPI_MOVE_32_TO_32(d,s) *(u32 *)(void *)(d) = *(u32 *)(void *)(s) -#define ACPI_MOVE_32_TO_64(d,s) ACPI_MOVE_32_TO_32(d,s) - -/* 64-bit source, 16/32/64 destination */ - -#define ACPI_MOVE_64_TO_16(d,s) ACPI_MOVE_16_TO_16(d,s) /* Truncate to 16 */ -#define ACPI_MOVE_64_TO_32(d,s) ACPI_MOVE_32_TO_32(d,s) /* Truncate to 32 */ -#define ACPI_MOVE_64_TO_64(d,s) ACPI_MOVE_32_TO_32(d,s) - -#else /* 16-bit source, 16/32/64 destination */ #define ACPI_MOVE_16_TO_16(d,s) *(u16 *)(void *)(d) = *(u16 *)(void *)(s) @@ -262,7 +211,6 @@ #define ACPI_MOVE_64_TO_16(d,s) ACPI_MOVE_16_TO_16(d,s) /* Truncate to 16 */ #define ACPI_MOVE_64_TO_32(d,s) ACPI_MOVE_32_TO_32(d,s) /* Truncate to 32 */ #define ACPI_MOVE_64_TO_64(d,s) *(u64 *)(void *)(d) = *(u64 *)(void *)(s) -#endif #else /* @@ -307,10 +255,7 @@ /* Macros based on machine integer width */ -#if ACPI_MACHINE_WIDTH == 16 -#define ACPI_MOVE_SIZE_TO_16(d,s) ACPI_MOVE_16_TO_16(d,s) - -#elif ACPI_MACHINE_WIDTH == 32 +#if ACPI_MACHINE_WIDTH == 32 #define ACPI_MOVE_SIZE_TO_16(d,s) ACPI_MOVE_32_TO_16(d,s) #elif ACPI_MACHINE_WIDTH == 64 @@ -695,16 +640,6 @@ #define ACPI_DEBUGGER_EXEC(a) #endif -/* - * For 16-bit code, we want to shrink some things even though - * we are using ACPI_DEBUG_OUTPUT to get the debug output - */ -#if ACPI_MACHINE_WIDTH == 16 -#undef ACPI_DEBUG_ONLY_MEMBERS -#undef _VERBOSE_STRUCTURES -#define ACPI_DEBUG_ONLY_MEMBERS(a) -#endif - #ifdef ACPI_DEBUG_OUTPUT /* * 1) Set name to blanks diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h index b67da3636899..34bfae8a05f3 100644 --- a/include/acpi/acnames.h +++ b/include/acpi/acnames.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acnamesp.h b/include/acpi/acnamesp.h index 83b52f9f899a..535b7e1c41bc 100644 --- a/include/acpi/acnamesp.h +++ b/include/acpi/acnamesp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -65,9 +65,13 @@ #define ACPI_NS_ERROR_IF_FOUND 0x08 #define ACPI_NS_PREFIX_IS_SCOPE 0x10 #define ACPI_NS_EXTERNAL 0x20 +#define ACPI_NS_TEMPORARY 0x40 -#define ACPI_NS_WALK_UNLOCK TRUE -#define ACPI_NS_WALK_NO_UNLOCK FALSE +/* Flags for acpi_ns_walk_namespace */ + +#define ACPI_NS_WALK_NO_UNLOCK 0 +#define ACPI_NS_WALK_UNLOCK 0x01 +#define ACPI_NS_WALK_TEMP_NODES 0x02 /* * nsinit - Namespace initialization @@ -82,7 +86,7 @@ acpi_status acpi_ns_initialize_devices(void); acpi_status acpi_ns_load_namespace(void); acpi_status -acpi_ns_load_table(struct acpi_table_desc *table_desc, +acpi_ns_load_table(acpi_native_uint table_index, struct acpi_namespace_node *node); /* @@ -92,7 +96,7 @@ acpi_status acpi_ns_walk_namespace(acpi_object_type type, acpi_handle start_object, u32 max_depth, - u8 unlock_before_callback, + u32 flags, acpi_walk_callback user_function, void *context, void **return_value); @@ -106,11 +110,12 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, * nsparse - table parsing */ acpi_status -acpi_ns_parse_table(struct acpi_table_desc *table_desc, - struct acpi_namespace_node *scope); +acpi_ns_parse_table(acpi_native_uint table_index, + struct acpi_namespace_node *start_node); acpi_status -acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc); +acpi_ns_one_complete_parse(acpi_native_uint pass_number, + acpi_native_uint table_index); /* * nsaccess - Top-level namespace access diff --git a/include/acpi/acobject.h b/include/acpi/acobject.h index 8fdee31119f3..04e9735a6742 100644 --- a/include/acpi/acobject.h +++ b/include/acpi/acobject.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,7 +52,15 @@ * to the interpreter, and to keep track of the various handlers such as * address space handlers and notify handlers. The object is a constant * size in order to allow it to be cached and reused. + * + * Note: The object is optimized to be aligned and will not work if it is + * byte-packed. */ +#if ACPI_MACHINE_WIDTH == 64 +#pragma pack(8) +#else +#pragma pack(4) +#endif /******************************************************************************* * @@ -101,7 +109,8 @@ struct acpi_object_common { ACPI_OBJECT_COMMON_HEADER}; struct acpi_object_integer { - ACPI_OBJECT_COMMON_HEADER acpi_integer value; + ACPI_OBJECT_COMMON_HEADER u8 fill[3]; /* Prevent warning on some compilers */ + acpi_integer value; }; /* @@ -203,7 +212,9 @@ struct acpi_object_power_resource { }; struct acpi_object_processor { - ACPI_OBJECT_COMMON_HEADER u8 proc_id; + ACPI_OBJECT_COMMON_HEADER + /* The next two fields take advantage of the 3-byte space before NOTIFY_INFO */ + u8 proc_id; u8 length; ACPI_COMMON_NOTIFY_INFO acpi_io_address address; }; @@ -406,4 +417,6 @@ union acpi_descriptor { union acpi_parse_object op; }; +#pragma pack() + #endif /* _ACOBJECT_H */ diff --git a/include/acpi/acopcode.h b/include/acpi/acopcode.h index 7659a46bc432..e6f76a280a94 100644 --- a/include/acpi/acopcode.h +++ b/include/acpi/acopcode.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -257,7 +257,7 @@ #define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE #define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER) #define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE -#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_FIELD,ARGI_TARGETREF) +#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_BUFFER,ARGI_TARGETREF) #define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_ANYTYPE) #define ARGI_LOCAL0 ARG_NONE #define ARGI_LOCAL1 ARG_NONE diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index 8d5039d0b430..7812267b577f 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acparser.h b/include/acpi/acparser.h index 9d49d3c41cd9..85c358e21014 100644 --- a/include/acpi/acparser.h +++ b/include/acpi/acparser.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h index b9a39d1009bd..2e5f00d3ea0d 100644 --- a/include/acpi/acpi.h +++ b/include/acpi/acpi.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index fdd10953b2b6..0d9f984a60a1 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, @@ -92,13 +91,12 @@ typedef int (*acpi_op_remove) (struct acpi_device * device, int type); typedef int (*acpi_op_lock) (struct acpi_device * device, int type); typedef int (*acpi_op_start) (struct acpi_device * device); typedef int (*acpi_op_stop) (struct acpi_device * device, int type); -typedef int (*acpi_op_suspend) (struct acpi_device * device, int state); -typedef int (*acpi_op_resume) (struct acpi_device * device, int state); +typedef int (*acpi_op_suspend) (struct acpi_device * device, pm_message_t state); +typedef int (*acpi_op_resume) (struct acpi_device * device); typedef int (*acpi_op_scan) (struct acpi_device * device); typedef int (*acpi_op_bind) (struct acpi_device * device); typedef int (*acpi_op_unbind) (struct acpi_device * device); -typedef int (*acpi_op_match) (struct acpi_device * device, - struct acpi_driver * driver); +typedef int (*acpi_op_shutdown) (struct acpi_device * device); struct acpi_bus_ops { u32 acpi_op_add:1; @@ -111,7 +109,7 @@ struct acpi_bus_ops { u32 acpi_op_scan:1; u32 acpi_op_bind:1; u32 acpi_op_unbind:1; - u32 acpi_op_match:1; + u32 acpi_op_shutdown:1; u32 reserved:21; }; @@ -126,16 +124,16 @@ struct acpi_device_ops { acpi_op_scan scan; acpi_op_bind bind; acpi_op_unbind unbind; - acpi_op_match match; + acpi_op_shutdown shutdown; }; struct acpi_driver { - struct list_head node; char name[80]; char class[80]; - atomic_t references; char *ids; /* Supported Hardware IDs */ struct acpi_device_ops ops; + struct device_driver drv; + struct module *owner; }; /* @@ -185,7 +183,7 @@ struct acpi_device_dir { typedef char acpi_bus_id[5]; typedef unsigned long acpi_bus_address; -typedef char acpi_hardware_id[9]; +typedef char acpi_hardware_id[15]; typedef char acpi_unique_id[9]; typedef char acpi_device_name[40]; typedef char acpi_device_class[20]; @@ -296,11 +294,14 @@ struct acpi_device { struct acpi_device_ops ops; struct acpi_driver *driver; void *driver_data; - struct kobject kobj; struct device dev; + struct acpi_bus_ops bus_ops; /* workaround for different code path for hotplug */ + enum acpi_bus_removal_type removal_type; /* indicate for different removal type */ }; #define acpi_driver_data(d) ((d)->driver_data) +#define to_acpi_device(d) container_of(d, struct acpi_device, dev) +#define to_acpi_driver(d) container_of(d, struct acpi_driver, drv) /* * Events diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 6a5bdcefec64..4dc8a5043ef0 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -36,13 +36,14 @@ /* _HID definitions */ -#define ACPI_POWER_HID "ACPI_PWR" -#define ACPI_PROCESSOR_HID "ACPI_CPU" -#define ACPI_SYSTEM_HID "ACPI_SYS" -#define ACPI_THERMAL_HID "ACPI_THM" -#define ACPI_BUTTON_HID_POWERF "ACPI_FPB" -#define ACPI_BUTTON_HID_SLEEPF "ACPI_FSB" - +#define ACPI_POWER_HID "power_resource" +#define ACPI_PROCESSOR_HID "ACPI0007" +#define ACPI_SYSTEM_HID "acpi_system" +#define ACPI_THERMAL_HID "thermal" +#define ACPI_BUTTON_HID_POWERF "button_power" +#define ACPI_BUTTON_HID_SLEEPF "button_sleep" +#define ACPI_VIDEO_HID "video" +#define ACPI_BAY_HID "bay" /* -------------------------------------------------------------------------- PCI -------------------------------------------------------------------------- */ diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 0cd63bce0ae4..781394b9efe0 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -8,7 +8,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -85,7 +85,7 @@ acpi_status acpi_os_terminate(void); /* * ACPI Table interfaces */ -acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *address); +acpi_physical_address acpi_os_get_root_pointer(void); acpi_status acpi_os_predefined_override(const struct acpi_predefined_names *init_val, @@ -143,9 +143,7 @@ void acpi_os_release_mutex(acpi_mutex handle); */ void *acpi_os_allocate(acpi_size size); -acpi_status -acpi_os_map_memory(acpi_physical_address physical_address, - acpi_size size, void __iomem ** logical_address); +void __iomem *acpi_os_map_memory(acpi_physical_address where, acpi_native_uint length); void acpi_os_unmap_memory(void __iomem * logical_address, acpi_size size); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 81458767a90e..e08f7df85a4f 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -51,6 +51,10 @@ /* * Global interfaces */ +acpi_status +acpi_initialize_tables(struct acpi_table_desc *initial_storage, + u32 initial_table_count, u8 allow_resize); + acpi_status acpi_initialize_subsystem(void); acpi_status acpi_enable_subsystem(u32 flags); @@ -92,30 +96,28 @@ void acpi_free(void *address); /* * ACPI table manipulation interfaces */ -acpi_status -acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address); +acpi_status acpi_reallocate_root_table(void); + +acpi_status acpi_find_root_pointer(acpi_native_uint * rsdp_address); acpi_status acpi_load_tables(void); acpi_status acpi_load_table(struct acpi_table_header *table_ptr); -acpi_status acpi_unload_table_id(acpi_table_type table_type, acpi_owner_id id); - -#ifdef ACPI_FUTURE_USAGE -acpi_status acpi_unload_table(acpi_table_type table_type); -acpi_status -acpi_get_table_header(acpi_table_type table_type, - u32 instance, struct acpi_table_header *out_table_header); -#endif /* ACPI_FUTURE_USAGE */ +acpi_status acpi_unload_table_id(acpi_owner_id id); acpi_status -acpi_get_table(acpi_table_type table_type, - u32 instance, struct acpi_buffer *ret_buffer); +acpi_get_table_header(acpi_string signature, + acpi_native_uint instance, + struct acpi_table_header *out_table_header); acpi_status -acpi_get_firmware_table(acpi_string signature, - u32 instance, - u32 flags, struct acpi_table_header **table_pointer); +acpi_get_table(acpi_string signature, + acpi_native_uint instance, struct acpi_table_header **out_table); + +acpi_status +acpi_get_table_by_index(acpi_native_uint table_index, + struct acpi_table_header **out_table); /* * Namespace and name interfaces @@ -310,9 +312,9 @@ acpi_resource_to_address64(struct acpi_resource *resource, /* * Hardware (ACPI device) interfaces */ -acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags); +acpi_status acpi_get_register(u32 register_id, u32 * return_value); -acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags); +acpi_status acpi_set_register(u32 register_id, u32 value); acpi_status acpi_set_firmware_waking_vector(acpi_physical_address physical_address); diff --git a/include/acpi/acresrc.h b/include/acpi/acresrc.h index 80a3b33571b4..9486ab266a5e 100644 --- a/include/acpi/acresrc.h +++ b/include/acpi/acresrc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/acstruct.h b/include/acpi/acstruct.h index 5e8095f0f78f..aeb4498e5e06 100644 --- a/include/acpi/acstruct.h +++ b/include/acpi/acstruct.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -139,7 +139,8 @@ struct acpi_init_walk_info { u16 buffer_init; u16 package_init; u16 object_count; - struct acpi_table_desc *table_desc; + acpi_owner_id owner_id; + acpi_native_uint table_index; }; struct acpi_get_devices_info { diff --git a/include/acpi/actables.h b/include/acpi/actables.h index 4dbaf02fe526..2b9f46f9da4d 100644 --- a/include/acpi/actables.h +++ b/include/acpi/actables.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,105 +44,75 @@ #ifndef __ACTABLES_H__ #define __ACTABLES_H__ -/* Used in acpi_tb_map_acpi_table for size parameter if table header is to be used */ - -#define SIZE_IN_HEADER 0 +acpi_status acpi_allocate_root_table(u32 initial_table_count); /* - * tbconvrt - Table conversion routines + * tbfadt - FADT parse/convert/validate */ -acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info); +void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags); -acpi_status acpi_tb_convert_table_fadt(void); - -acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info); - -u32 -acpi_tb_get_table_count(struct rsdp_descriptor *RSDP, - struct acpi_table_header *RSDT); +void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length); /* - * tbget - Table "get" routines - */ -acpi_status -acpi_tb_get_table(struct acpi_pointer *address, - struct acpi_table_desc *table_info); - -acpi_status -acpi_tb_get_table_header(struct acpi_pointer *address, - struct acpi_table_header *return_header); - -acpi_status -acpi_tb_get_table_body(struct acpi_pointer *address, - struct acpi_table_header *header, - struct acpi_table_desc *table_info); - -acpi_status -acpi_tb_get_table_ptr(acpi_table_type table_type, - u32 instance, struct acpi_table_header **table_ptr_loc); - -acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address); - -void acpi_tb_get_rsdt_address(struct acpi_pointer *out_address); - -acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr); - -/* - * tbgetall - get multiple required tables - */ -acpi_status acpi_tb_get_required_tables(void); - -/* - * tbinstall - Table installation - */ -acpi_status acpi_tb_install_table(struct acpi_table_desc *table_info); - -acpi_status -acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type); - -acpi_status -acpi_tb_init_table_descriptor(acpi_table_type table_type, - struct acpi_table_desc *table_info); - -/* - * tbremove - Table removal and deletion - */ -void acpi_tb_delete_all_tables(void); - -void acpi_tb_delete_tables_by_type(acpi_table_type type); - -void acpi_tb_delete_single_table(struct acpi_table_desc *table_desc); - -struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc - *table_desc); - -/* - * tbxfroot - RSDP, RSDT utilities + * tbfind - find ACPI table */ acpi_status acpi_tb_find_table(char *signature, char *oem_id, - char *oem_table_id, struct acpi_table_header **table_ptr); - -acpi_status acpi_tb_get_table_rsdt(void); - -acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp); + char *oem_table_id, acpi_native_uint * table_index); /* - * tbutils - common table utilities + * tbinstal - Table removal and deletion */ -acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc); +acpi_status acpi_tb_resize_root_table_list(void); + +acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc); acpi_status -acpi_tb_verify_table_checksum(struct acpi_table_header *table_header); - -u8 acpi_tb_sum_table(void *buffer, u32 length); - -u8 acpi_tb_generate_checksum(struct acpi_table_header *table); - -void acpi_tb_set_checksum(struct acpi_table_header *table); +acpi_tb_add_table(struct acpi_table_desc *table_desc, + acpi_native_uint * table_index); acpi_status -acpi_tb_validate_table_header(struct acpi_table_header *table_header); +acpi_tb_store_table(acpi_physical_address address, + struct acpi_table_header *table, + u32 length, u8 flags, acpi_native_uint * table_index); + +void acpi_tb_delete_table(struct acpi_table_desc *table_desc); + +void acpi_tb_terminate(void); + +void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index); + +acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index); + +acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index); + +acpi_status +acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id); + +u8 acpi_tb_is_table_loaded(acpi_native_uint table_index); + +void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded); + +/* + * tbutils - table manager utilities + */ +u8 acpi_tb_tables_loaded(void); + +void +acpi_tb_print_table_header(acpi_physical_address address, + struct acpi_table_header *header); + +u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length); + +acpi_status +acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length); + +void +acpi_tb_install_table(acpi_physical_address address, + u8 flags, char *signature, acpi_native_uint table_index); + +acpi_status +acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags); #endif /* __ACTABLES_H__ */ diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index b125ceed9cb7..09469e7db6a5 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,15 +48,15 @@ * Values for description table header signatures. Useful because they make * it more difficult to inadvertently type in the wrong signature. */ -#define DSDT_SIG "DSDT" /* Differentiated System Description Table */ -#define FADT_SIG "FACP" /* Fixed ACPI Description Table */ -#define FACS_SIG "FACS" /* Firmware ACPI Control Structure */ -#define PSDT_SIG "PSDT" /* Persistent System Description Table */ -#define RSDP_SIG "RSD PTR " /* Root System Description Pointer */ -#define RSDT_SIG "RSDT" /* Root System Description Table */ -#define XSDT_SIG "XSDT" /* Extended System Description Table */ -#define SSDT_SIG "SSDT" /* Secondary System Description Table */ -#define RSDP_NAME "RSDP" +#define ACPI_SIG_DSDT "DSDT" /* Differentiated System Description Table */ +#define ACPI_SIG_FADT "FACP" /* Fixed ACPI Description Table */ +#define ACPI_SIG_FACS "FACS" /* Firmware ACPI Control Structure */ +#define ACPI_SIG_PSDT "PSDT" /* Persistent System Description Table */ +#define ACPI_SIG_RSDP "RSD PTR " /* Root System Description Pointer */ +#define ACPI_SIG_RSDT "RSDT" /* Root System Description Table */ +#define ACPI_SIG_XSDT "XSDT" /* Extended System Description Table */ +#define ACPI_SIG_SSDT "SSDT" /* Secondary System Description Table */ +#define ACPI_RSDP_NAME "RSDP" /* Short name for RSDP, not signature */ /* * All tables and structures must be byte-packed to match the ACPI @@ -83,27 +83,29 @@ * ******************************************************************************/ -#define ACPI_TABLE_HEADER_DEF \ - char signature[4]; /* ASCII table signature */\ - u32 length; /* Length of table in bytes, including this header */\ - u8 revision; /* ACPI Specification minor version # */\ - u8 checksum; /* To make sum of entire table == 0 */\ - char oem_id[6]; /* ASCII OEM identification */\ - char oem_table_id[8]; /* ASCII OEM table identification */\ - u32 oem_revision; /* OEM revision number */\ - char asl_compiler_id[4]; /* ASCII ASL compiler vendor ID */\ - u32 asl_compiler_revision; /* ASL compiler version */ - struct acpi_table_header { -ACPI_TABLE_HEADER_DEF}; + char signature[ACPI_NAME_SIZE]; /* ASCII table signature */ + u32 length; /* Length of table in bytes, including this header */ + u8 revision; /* ACPI Specification minor version # */ + u8 checksum; /* To make sum of entire table == 0 */ + char oem_id[ACPI_OEM_ID_SIZE]; /* ASCII OEM identification */ + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE]; /* ASCII OEM table identification */ + u32 oem_revision; /* OEM revision number */ + char asl_compiler_id[ACPI_NAME_SIZE]; /* ASCII ASL compiler vendor ID */ + u32 asl_compiler_revision; /* ASL compiler version */ +}; /* * GAS - Generic Address Structure (ACPI 2.0+) + * + * Note: Since this structure is used in the ACPI tables, it is byte aligned. + * If misalignment is not supported, access to the Address field must be + * performed with care. */ struct acpi_generic_address { - u8 address_space_id; /* Address space where struct or register exists */ - u8 register_bit_width; /* Size in bits of given register */ - u8 register_bit_offset; /* Bit offset within the register */ + u8 space_id; /* Address space where struct or register exists */ + u8 bit_width; /* Size in bits of given register */ + u8 bit_offset; /* Bit offset within the register */ u8 access_width; /* Minimum Access size (ACPI 3.0) */ u64 address; /* 64-bit address of struct or register */ }; @@ -114,10 +116,10 @@ struct acpi_generic_address { * ******************************************************************************/ -struct rsdp_descriptor { +struct acpi_table_rsdp { char signature[8]; /* ACPI signature, contains "RSD PTR " */ u8 checksum; /* ACPI 1.0 checksum */ - char oem_id[6]; /* OEM identification */ + char oem_id[ACPI_OEM_ID_SIZE]; /* OEM identification */ u8 revision; /* Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+ */ u32 rsdt_physical_address; /* 32-bit physical address of the RSDT */ u32 length; /* Table length in bytes, including header (ACPI 2.0+) */ @@ -134,12 +136,14 @@ struct rsdp_descriptor { * ******************************************************************************/ -struct rsdt_descriptor { - ACPI_TABLE_HEADER_DEF u32 table_offset_entry[1]; /* Array of pointers to ACPI tables */ +struct acpi_table_rsdt { + struct acpi_table_header header; /* Common ACPI table header */ + u32 table_offset_entry[1]; /* Array of pointers to ACPI tables */ }; -struct xsdt_descriptor { - ACPI_TABLE_HEADER_DEF u64 table_offset_entry[1]; /* Array of pointers to ACPI tables */ +struct acpi_table_xsdt { + struct acpi_table_header header; /* Common ACPI table header */ + u64 table_offset_entry[1]; /* Array of pointers to ACPI tables */ }; /******************************************************************************* @@ -148,36 +152,27 @@ struct xsdt_descriptor { * ******************************************************************************/ -struct facs_descriptor { +struct acpi_table_facs { char signature[4]; /* ASCII table signature */ u32 length; /* Length of structure, in bytes */ u32 hardware_signature; /* Hardware configuration signature */ u32 firmware_waking_vector; /* 32-bit physical address of the Firmware Waking Vector */ u32 global_lock; /* Global Lock for shared hardware resources */ - - /* Flags (32 bits) */ - - u8 S4bios_f:1; /* 00: S4BIOS support is present */ - u8:7; /* 01-07: Reserved, must be zero */ - u8 reserved1[3]; /* 08-31: Reserved, must be zero */ - + u32 flags; u64 xfirmware_waking_vector; /* 64-bit version of the Firmware Waking Vector (ACPI 2.0+) */ u8 version; /* Version of this table (ACPI 2.0+) */ u8 reserved[31]; /* Reserved, must be zero */ }; +/* Flag macros */ + +#define ACPI_FACS_S4_BIOS_PRESENT (1) /* 00: S4BIOS support is present */ + +/* Global lock flags */ + #define ACPI_GLOCK_PENDING 0x01 /* 00: Pending global lock ownership */ #define ACPI_GLOCK_OWNED 0x02 /* 01: Global lock is owned */ -/* - * Common FACS - This is a version-independent FACS structure used for internal use only - */ -struct acpi_common_facs { - u32 *global_lock; - u64 *firmware_waking_vector; - u8 vector_width; -}; - /******************************************************************************* * * FADT - Fixed ACPI Description Table (Signature "FACP") @@ -186,121 +181,98 @@ struct acpi_common_facs { /* Fields common to all versions of the FADT */ -#define ACPI_FADT_COMMON \ - ACPI_TABLE_HEADER_DEF \ - u32 V1_firmware_ctrl; /* 32-bit physical address of FACS */ \ - u32 V1_dsdt; /* 32-bit physical address of DSDT */ \ - u8 reserved1; /* System Interrupt Model isn't used in ACPI 2.0*/ \ - u8 prefer_PM_profile; /* Conveys preferred power management profile to OSPM. */ \ - u16 sci_int; /* System vector of SCI interrupt */ \ - u32 smi_cmd; /* Port address of SMI command port */ \ - 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 pstate_cnt; /* Processor performance state control*/ \ - u32 V1_pm1a_evt_blk; /* Port address of Power Mgt 1a Event Reg Blk */ \ - u32 V1_pm1b_evt_blk; /* Port address of Power Mgt 1b Event Reg Blk */ \ - u32 V1_pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ \ - u32 V1_pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ \ - u32 V1_pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ \ - u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ \ - u32 V1_gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ \ - u32 V1_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 cst_cnt; /* Support for the _CST object and C States change notification.*/ \ - u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ \ - u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ \ - u16 flush_size; /* Processor's memory cache line width, in bytes */ \ - u16 flush_stride; /* Number of flush strides that need to be read */ \ - u8 duty_offset; /* Processor's duty cycle index in processor's P_CNT reg*/ \ - u8 duty_width; /* Processor's duty cycle value bit width in P_CNT register.*/ \ - 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 */ \ - u16 iapc_boot_arch; /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ \ - u8 reserved2; /* Reserved, must be zero */ - -/* - * ACPI 2.0+ FADT - */ -struct fadt_descriptor { - ACPI_FADT_COMMON - /* Flags (32 bits) */ - u8 wb_invd:1; /* 00: The wbinvd instruction works properly */ - u8 wb_invd_flush:1; /* 01: The wbinvd flushes but does not invalidate */ - u8 proc_c1:1; /* 02: All processors support C1 state */ - u8 plvl2_up:1; /* 03: C2 state works on MP system */ - u8 pwr_button:1; /* 04: Power button is handled as a generic feature */ - u8 sleep_button:1; /* 05: Sleep button is handled as a generic feature, or not present */ - u8 fixed_rTC:1; /* 06: RTC wakeup stat not in fixed register space */ - u8 rtcs4:1; /* 07: RTC wakeup stat not possible from S4 */ - u8 tmr_val_ext:1; /* 08: tmr_val is 32 bits 0=24-bits */ - u8 dock_cap:1; /* 09: Docking supported */ - u8 reset_reg_sup:1; /* 10: System reset via the FADT RESET_REG supported */ - u8 sealed_case:1; /* 11: No internal expansion capabilities and case is sealed */ - u8 headless:1; /* 12: No local video capabilities or local input devices */ - u8 cpu_sw_sleep:1; /* 13: Must execute native instruction after writing SLP_TYPx register */ - - u8 pci_exp_wak:1; /* 14: System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */ - u8 use_platform_clock:1; /* 15: OSPM should use platform-provided timer (ACPI 3.0) */ - u8 S4rtc_sts_valid:1; /* 16: Contents of RTC_STS valid after S4 wake (ACPI 3.0) */ - u8 remote_power_on_capable:1; /* 17: System is compatible with remote power on (ACPI 3.0) */ - u8 force_apic_cluster_model:1; /* 18: All local APICs must use cluster model (ACPI 3.0) */ - u8 force_apic_physical_destination_mode:1; /* 19: All local x_aPICs must use physical dest mode (ACPI 3.0) */ - u8:4; /* 20-23: Reserved, must be zero */ - u8 reserved3; /* 24-31: Reserved, must be zero */ - - struct acpi_generic_address reset_register; /* Reset register address in GAS format */ +struct acpi_table_fadt { + struct acpi_table_header header; /* Common ACPI table header */ + u32 facs; /* 32-bit physical address of FACS */ + u32 dsdt; /* 32-bit physical address of DSDT */ + u8 model; /* System Interrupt Model (ACPI 1.0) - not used in ACPI 2.0+ */ + u8 preferred_profile; /* Conveys preferred power management profile to OSPM. */ + u16 sci_interrupt; /* System vector of SCI interrupt */ + u32 smi_command; /* 32-bit Port address of SMI command port */ + 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_request; /* Value to write to SMI CMD to enter S4BIOS state */ + u8 pstate_control; /* Processor performance state control */ + u32 pm1a_event_block; /* 32-bit Port address of Power Mgt 1a Event Reg Blk */ + u32 pm1b_event_block; /* 32-bit Port address of Power Mgt 1b Event Reg Blk */ + u32 pm1a_control_block; /* 32-bit Port address of Power Mgt 1a Control Reg Blk */ + u32 pm1b_control_block; /* 32-bit Port address of Power Mgt 1b Control Reg Blk */ + u32 pm2_control_block; /* 32-bit Port address of Power Mgt 2 Control Reg Blk */ + u32 pm_timer_block; /* 32-bit Port address of Power Mgt Timer Ctrl Reg Blk */ + u32 gpe0_block; /* 32-bit Port address of General Purpose Event 0 Reg Blk */ + u32 gpe1_block; /* 32-bit Port address of General Purpose Event 1 Reg Blk */ + u8 pm1_event_length; /* Byte Length of ports at pm1x_event_block */ + u8 pm1_control_length; /* Byte Length of ports at pm1x_control_block */ + u8 pm2_control_length; /* Byte Length of ports at pm2_control_block */ + u8 pm_timer_length; /* Byte Length of ports at pm_timer_block */ + u8 gpe0_block_length; /* Byte Length of ports at gpe0_block */ + u8 gpe1_block_length; /* Byte Length of ports at gpe1_block */ + u8 gpe1_base; /* Offset in GPE number space where GPE1 events start */ + u8 cst_control; /* Support for the _CST object and C States change notification */ + u16 C2latency; /* Worst case HW latency to enter/exit C2 state */ + u16 C3latency; /* Worst case HW latency to enter/exit C3 state */ + u16 flush_size; /* Processor's memory cache line width, in bytes */ + u16 flush_stride; /* Number of flush strides that need to be read */ + u8 duty_offset; /* Processor duty cycle index in processor's P_CNT reg */ + u8 duty_width; /* Processor duty cycle value bit width in P_CNT register. */ + u8 day_alarm; /* Index to day-of-month alarm in RTC CMOS RAM */ + u8 month_alarm; /* Index to month-of-year alarm in RTC CMOS RAM */ + u8 century; /* Index to century in RTC CMOS RAM */ + u16 boot_flags; /* IA-PC Boot Architecture Flags. See Table 5-10 for description */ + u8 reserved; /* Reserved, must be zero */ + u32 flags; /* Miscellaneous flag bits (see below for individual flags) */ + struct acpi_generic_address reset_register; /* 64-bit address of the Reset register */ u8 reset_value; /* Value to write to the reset_register port to reset the system */ - u8 reserved4[3]; /* These three bytes must be zero */ - u64 xfirmware_ctrl; /* 64-bit physical address of FACS */ + u8 reserved4[3]; /* Reserved, must be zero */ + u64 Xfacs; /* 64-bit physical address of FACS */ u64 Xdsdt; /* 64-bit physical address of DSDT */ - struct acpi_generic_address xpm1a_evt_blk; /* Extended Power Mgt 1a acpi_event Reg Blk address */ - struct acpi_generic_address xpm1b_evt_blk; /* Extended Power Mgt 1b acpi_event Reg Blk address */ - struct acpi_generic_address xpm1a_cnt_blk; /* Extended Power Mgt 1a Control Reg Blk address */ - struct acpi_generic_address xpm1b_cnt_blk; /* Extended Power Mgt 1b Control Reg Blk address */ - struct acpi_generic_address xpm2_cnt_blk; /* Extended Power Mgt 2 Control Reg Blk address */ - struct acpi_generic_address xpm_tmr_blk; /* Extended Power Mgt Timer Ctrl Reg Blk address */ - struct acpi_generic_address xgpe0_blk; /* Extended General Purpose acpi_event 0 Reg Blk address */ - struct acpi_generic_address xgpe1_blk; /* Extended General Purpose acpi_event 1 Reg Blk address */ + struct acpi_generic_address xpm1a_event_block; /* 64-bit Extended Power Mgt 1a Event Reg Blk address */ + struct acpi_generic_address xpm1b_event_block; /* 64-bit Extended Power Mgt 1b Event Reg Blk address */ + struct acpi_generic_address xpm1a_control_block; /* 64-bit Extended Power Mgt 1a Control Reg Blk address */ + struct acpi_generic_address xpm1b_control_block; /* 64-bit Extended Power Mgt 1b Control Reg Blk address */ + struct acpi_generic_address xpm2_control_block; /* 64-bit Extended Power Mgt 2 Control Reg Blk address */ + struct acpi_generic_address xpm_timer_block; /* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */ + struct acpi_generic_address xgpe0_block; /* 64-bit Extended General Purpose Event 0 Reg Blk address */ + struct acpi_generic_address xgpe1_block; /* 64-bit Extended General Purpose Event 1 Reg Blk address */ }; +/* FADT flags */ + +#define ACPI_FADT_WBINVD (1) /* 00: The wbinvd instruction works properly */ +#define ACPI_FADT_WBINVD_FLUSH (1<<1) /* 01: The wbinvd flushes but does not invalidate */ +#define ACPI_FADT_C1_SUPPORTED (1<<2) /* 02: All processors support C1 state */ +#define ACPI_FADT_C2_MP_SUPPORTED (1<<3) /* 03: C2 state works on MP system */ +#define ACPI_FADT_POWER_BUTTON (1<<4) /* 04: Power button is handled as a generic feature */ +#define ACPI_FADT_SLEEP_BUTTON (1<<5) /* 05: Sleep button is handled as a generic feature, or not present */ +#define ACPI_FADT_FIXED_RTC (1<<6) /* 06: RTC wakeup stat not in fixed register space */ +#define ACPI_FADT_S4_RTC_WAKE (1<<7) /* 07: RTC wakeup stat not possible from S4 */ +#define ACPI_FADT_32BIT_TIMER (1<<8) /* 08: tmr_val is 32 bits 0=24-bits */ +#define ACPI_FADT_DOCKING_SUPPORTED (1<<9) /* 09: Docking supported */ +#define ACPI_FADT_RESET_REGISTER (1<<10) /* 10: System reset via the FADT RESET_REG supported */ +#define ACPI_FADT_SEALED_CASE (1<<11) /* 11: No internal expansion capabilities and case is sealed */ +#define ACPI_FADT_HEADLESS (1<<12) /* 12: No local video capabilities or local input devices */ +#define ACPI_FADT_SLEEP_TYPE (1<<13) /* 13: Must execute native instruction after writing SLP_TYPx register */ +#define ACPI_FADT_PCI_EXPRESS_WAKE (1<<14) /* 14: System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */ +#define ACPI_FADT_PLATFORM_CLOCK (1<<15) /* 15: OSPM should use platform-provided timer (ACPI 3.0) */ +#define ACPI_FADT_S4_RTC_VALID (1<<16) /* 16: Contents of RTC_STS valid after S4 wake (ACPI 3.0) */ +#define ACPI_FADT_REMOTE_POWER_ON (1<<17) /* 17: System is compatible with remote power on (ACPI 3.0) */ +#define ACPI_FADT_APIC_CLUSTER (1<<18) /* 18: All local APICs must use cluster model (ACPI 3.0) */ +#define ACPI_FADT_APIC_PHYSICAL (1<<19) /* 19: All local x_aPICs must use physical dest mode (ACPI 3.0) */ + /* - * "Down-revved" ACPI 2.0 FADT descriptor - * Defined here to allow compiler to generate the length of the struct + * FADT Prefered Power Management Profiles */ -struct fadt_descriptor_rev2_minus { - ACPI_FADT_COMMON u32 flags; - struct acpi_generic_address reset_register; /* Reset register address in GAS format */ - u8 reset_value; /* Value to write to the reset_register port to reset the system. */ - u8 reserved7[3]; /* Reserved, must be zero */ +enum acpi_prefered_pm_profiles { + PM_UNSPECIFIED = 0, + PM_DESKTOP = 1, + PM_MOBILE = 2, + PM_WORKSTATION = 3, + PM_ENTERPRISE_SERVER = 4, + PM_SOHO_SERVER = 5, + PM_APPLIANCE_PC = 6 }; -/* - * ACPI 1.0 FADT - * Defined here to allow compiler to generate the length of the struct - */ -struct fadt_descriptor_rev1 { - ACPI_FADT_COMMON u32 flags; -}; - -/* FADT: Prefered Power Management Profiles */ - -#define PM_UNSPECIFIED 0 -#define PM_DESKTOP 1 -#define PM_MOBILE 2 -#define PM_WORKSTATION 3 -#define PM_ENTERPRISE_SERVER 4 -#define PM_SOHO_SERVER 5 -#define PM_APPLIANCE_PC 6 - -/* FADT: Boot Arch Flags */ +/* FADT Boot Arch Flags */ #define BAF_LEGACY_DEVICES 0x0001 #define BAF_8042_KEYBOARD_CONTROLLER 0x0002 @@ -312,59 +284,12 @@ struct fadt_descriptor_rev1 { #pragma pack() -/* - * This macro is temporary until the table bitfield flag definitions - * are removed and replaced by a Flags field. - */ -#define ACPI_FLAG_OFFSET(d,f,o) (u8) (ACPI_OFFSET (d,f) + \ - sizeof(((d *)0)->f) + o) +#define ACPI_FADT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_fadt, f) + /* * Get the remaining ACPI tables */ -#include "actbl1.h" -/* - * ACPI Table information. We save the table address, length, - * and type of memory allocation (mapped or allocated) for each - * table for 1) when we exit, and 2) if a new table is installed - */ -#define ACPI_MEM_NOT_ALLOCATED 0 -#define ACPI_MEM_ALLOCATED 1 -#define ACPI_MEM_MAPPED 2 - -/* Definitions for the Flags bitfield member of struct acpi_table_support */ - -#define ACPI_TABLE_SINGLE 0x00 -#define ACPI_TABLE_MULTIPLE 0x01 -#define ACPI_TABLE_EXECUTABLE 0x02 - -#define ACPI_TABLE_ROOT 0x00 -#define ACPI_TABLE_PRIMARY 0x10 -#define ACPI_TABLE_SECONDARY 0x20 -#define ACPI_TABLE_ALL 0x30 -#define ACPI_TABLE_TYPE_MASK 0x30 - -/* Data about each known table type */ - -struct acpi_table_support { - char *name; - char *signature; - void **global_ptr; - u8 sig_length; - u8 flags; -}; - -extern u8 acpi_fadt_is_v1; /* is set to 1 if FADT is revision 1, - * needed for certain workarounds */ -/* Macros used to generate offsets to specific table fields */ - -#define ACPI_FACS_OFFSET(f) (u8) ACPI_OFFSET (struct facs_descriptor,f) -#define ACPI_FADT_OFFSET(f) (u8) ACPI_OFFSET (struct fadt_descriptor, f) -#define ACPI_GAS_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_generic_address,f) -#define ACPI_HDR_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_header,f) -#define ACPI_RSDP_OFFSET(f) (u8) ACPI_OFFSET (struct rsdp_descriptor,f) - -#define ACPI_FADT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct fadt_descriptor,f,o) -#define ACPI_FACS_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct facs_descriptor,f,o) +#include #endif /* __ACTBL_H__ */ diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index 745a6445a4f9..4e5d3ca53a8e 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -61,6 +61,7 @@ #define ACPI_SIG_BOOT "BOOT" /* Simple Boot Flag Table */ #define ACPI_SIG_CPEP "CPEP" /* Corrected Platform Error Polling table */ #define ACPI_SIG_DBGP "DBGP" /* Debug Port table */ +#define ACPI_SIG_DMAR "DMAR" /* DMA Remapping table */ #define ACPI_SIG_ECDT "ECDT" /* Embedded Controller Boot Resources Table */ #define ACPI_SIG_HPET "HPET" /* High Precision Event Timer table */ #define ACPI_SIG_MADT "APIC" /* Multiple APIC Description Table */ @@ -73,12 +74,6 @@ #define ACPI_SIG_TCPA "TCPA" /* Trusted Computing Platform Alliance table */ #define ACPI_SIG_WDRT "WDRT" /* Watchdog Resource Table */ -/* Legacy names */ - -#define APIC_SIG "APIC" /* Multiple APIC Description Table */ -#define BOOT_SIG "BOOT" /* Simple Boot Flag Table */ -#define SBST_SIG "SBST" /* Smart Battery Specification Table */ - /* * All tables must be byte-packed to match the ACPI specification, since * the tables are provided by the system BIOS. @@ -91,31 +86,43 @@ * portable, so do not use any other bitfield types. */ +/* Common Sub-table header (used in MADT, SRAT, etc.) */ + +struct acpi_subtable_header { + u8 type; + u8 length; +}; + /******************************************************************************* * * ASF - Alert Standard Format table (Signature "ASF!") * + * Conforms to the Alert Standard Format Specification V2.0, 23 April 2003 + * ******************************************************************************/ struct acpi_table_asf { -ACPI_TABLE_HEADER_DEF}; + struct acpi_table_header header; /* Common ACPI table header */ +}; -#define ACPI_ASF_HEADER_DEF \ - u8 type; \ - u8 reserved; \ - u16 length; +/* ASF subtable header */ struct acpi_asf_header { -ACPI_ASF_HEADER_DEF}; + u8 type; + u8 reserved; + u16 length; +}; -/* Values for Type field */ +/* Values for Type field above */ -#define ASF_INFO 0 -#define ASF_ALERT 1 -#define ASF_CONTROL 2 -#define ASF_BOOT 3 -#define ASF_ADDRESS 4 -#define ASF_RESERVED 5 +enum acpi_asf_type { + ACPI_ASF_TYPE_INFO = 0, + ACPI_ASF_TYPE_ALERT = 1, + ACPI_ASF_TYPE_CONTROL = 2, + ACPI_ASF_TYPE_BOOT = 3, + ACPI_ASF_TYPE_ADDRESS = 4, + ACPI_ASF_TYPE_RESERVED = 5 +}; /* * ASF subtables @@ -124,7 +131,8 @@ ACPI_ASF_HEADER_DEF}; /* 0: ASF Information */ struct acpi_asf_info { - ACPI_ASF_HEADER_DEF u8 min_reset_value; + struct acpi_asf_header header; + u8 min_reset_value; u8 min_poll_interval; u16 system_id; u32 mfg_id; @@ -135,26 +143,49 @@ struct acpi_asf_info { /* 1: ASF Alerts */ struct acpi_asf_alert { - ACPI_ASF_HEADER_DEF u8 assert_mask; + struct acpi_asf_header header; + u8 assert_mask; u8 deassert_mask; u8 alerts; u8 data_length; - u8 array[1]; +}; + +struct acpi_asf_alert_data { + u8 address; + u8 command; + u8 mask; + u8 value; + u8 sensor_type; + u8 type; + u8 offset; + u8 source_type; + u8 severity; + u8 sensor_number; + u8 entity; + u8 instance; }; /* 2: ASF Remote Control */ struct acpi_asf_remote { - ACPI_ASF_HEADER_DEF u8 controls; + struct acpi_asf_header header; + u8 controls; u8 data_length; u16 reserved2; - u8 array[1]; +}; + +struct acpi_asf_control_data { + u8 function; + u8 address; + u8 command; + u8 value; }; /* 3: ASF RMCP Boot Options */ struct acpi_asf_rmcp { - ACPI_ASF_HEADER_DEF u8 capabilities[7]; + struct acpi_asf_header header; + u8 capabilities[7]; u8 completion_code; u32 enterprise_id; u8 command; @@ -166,9 +197,9 @@ struct acpi_asf_rmcp { /* 4: ASF Address */ struct acpi_asf_address { - ACPI_ASF_HEADER_DEF u8 eprom_address; + struct acpi_asf_header header; + u8 eprom_address; u8 devices; - u8 smbus_addresses[1]; }; /******************************************************************************* @@ -178,7 +209,8 @@ struct acpi_asf_address { ******************************************************************************/ struct acpi_table_boot { - ACPI_TABLE_HEADER_DEF u8 cmos_index; /* Index in CMOS RAM for the boot register */ + struct acpi_table_header header; /* Common ACPI table header */ + u8 cmos_index; /* Index in CMOS RAM for the boot register */ u8 reserved[3]; }; @@ -189,7 +221,8 @@ struct acpi_table_boot { ******************************************************************************/ struct acpi_table_cpep { - ACPI_TABLE_HEADER_DEF u64 reserved; + struct acpi_table_header header; /* Common ACPI table header */ + u64 reserved; }; /* Subtable */ @@ -197,9 +230,9 @@ struct acpi_table_cpep { struct acpi_cpep_polling { u8 type; u8 length; - u8 processor_id; /* Processor ID */ - u8 processor_eid; /* Processor EID */ - u32 polling_interval; /* Polling interval (msec) */ + u8 id; /* Processor ID */ + u8 eid; /* Processor EID */ + u32 interval; /* Polling interval (msec) */ }; /******************************************************************************* @@ -209,23 +242,97 @@ struct acpi_cpep_polling { ******************************************************************************/ struct acpi_table_dbgp { - ACPI_TABLE_HEADER_DEF u8 interface_type; /* 0=full 16550, 1=subset of 16550 */ + struct acpi_table_header header; /* Common ACPI table header */ + u8 type; /* 0=full 16550, 1=subset of 16550 */ u8 reserved[3]; struct acpi_generic_address debug_port; }; +/******************************************************************************* + * + * DMAR - DMA Remapping table + * + ******************************************************************************/ + +struct acpi_table_dmar { + struct acpi_table_header header; /* Common ACPI table header */ + u8 width; /* Host Address Width */ + u8 reserved[11]; +}; + +/* DMAR subtable header */ + +struct acpi_dmar_header { + u16 type; + u16 length; + u8 flags; + u8 reserved[3]; +}; + +/* Values for subtable type in struct acpi_dmar_header */ + +enum acpi_dmar_type { + ACPI_DMAR_TYPE_HARDWARE_UNIT = 0, + ACPI_DMAR_TYPE_RESERVED_MEMORY = 1, + ACPI_DMAR_TYPE_RESERVED = 2 /* 2 and greater are reserved */ +}; + +struct acpi_dmar_device_scope { + u8 entry_type; + u8 length; + u8 segment; + u8 bus; +}; + +/* Values for entry_type in struct acpi_dmar_device_scope */ + +enum acpi_dmar_scope_type { + ACPI_DMAR_SCOPE_TYPE_NOT_USED = 0, + ACPI_DMAR_SCOPE_TYPE_ENDPOINT = 1, + ACPI_DMAR_SCOPE_TYPE_BRIDGE = 2, + ACPI_DMAR_SCOPE_TYPE_RESERVED = 3 /* 3 and greater are reserved */ +}; + +/* + * DMAR Sub-tables, correspond to Type in struct acpi_dmar_header + */ + +/* 0: Hardware Unit Definition */ + +struct acpi_dmar_hardware_unit { + struct acpi_dmar_header header; + u64 address; /* Register Base Address */ +}; + +/* Flags */ + +#define ACPI_DMAR_INCLUDE_ALL (1) + +/* 1: Reserved Memory Defininition */ + +struct acpi_dmar_reserved_memory { + struct acpi_dmar_header header; + u64 address; /* 4_k aligned base address */ + u64 end_address; /* 4_k aligned limit address */ +}; + +/* Flags */ + +#define ACPI_DMAR_ALLOW_ALL (1) + /******************************************************************************* * * ECDT - Embedded Controller Boot Resources Table * ******************************************************************************/ -struct ec_boot_resources { - ACPI_TABLE_HEADER_DEF struct acpi_generic_address ec_control; /* Address of EC command/status register */ - struct acpi_generic_address ec_data; /* Address of EC data register */ +struct acpi_table_ecdt { + struct acpi_table_header header; /* Common ACPI table header */ + struct acpi_generic_address control; /* Address of EC command/status register */ + struct acpi_generic_address data; /* Address of EC data register */ u32 uid; /* Unique ID - must be same as the EC _UID method */ - u8 gpe_bit; /* The GPE for the EC */ - u8 ec_id[1]; /* Full namepath of the EC in the ACPI namespace */ + u8 gpe; /* The GPE for the EC */ + u8 id[1]; /* Full namepath of the EC in the ACPI namespace */ }; /******************************************************************************* @@ -234,22 +341,22 @@ struct ec_boot_resources { * ******************************************************************************/ -struct acpi_hpet_table { - ACPI_TABLE_HEADER_DEF u32 hardware_id; /* Hardware ID of event timer block */ - struct acpi_generic_address base_address; /* Address of event timer block */ - u8 hpet_number; /* HPET sequence number */ - u16 clock_tick; /* Main counter min tick, periodic mode */ - u8 attributes; +struct acpi_table_hpet { + struct acpi_table_header header; /* Common ACPI table header */ + u32 id; /* Hardware ID of event timer block */ + struct acpi_generic_address address; /* Address of event timer block */ + u8 sequence; /* HPET sequence number */ + u16 minimum_tick; /* Main counter min tick, periodic mode */ + u8 flags; }; -#if 0 /* HPET flags to be converted to macros */ -struct { /* Flags (8 bits) */ - u8 page_protect:1; /* 00: No page protection */ - u8 page_protect4:1; /* 01: 4_kB page protected */ - u8 page_protect64:1; /* 02: 64_kB page protected */ - u8:5; /* 03-07: Reserved, must be zero */ -} flags; -#endif +/*! Flags */ + +#define ACPI_HPET_PAGE_PROTECT (1) /* 00: No page protection */ +#define ACPI_HPET_PAGE_PROTECT_4 (1<<1) /* 01: 4KB page protected */ +#define ACPI_HPET_PAGE_PROTECT_64 (1<<2) /* 02: 64KB page protected */ + +/*! [End] no source code translation !*/ /******************************************************************************* * @@ -257,148 +364,159 @@ struct { /* Flags (8 bits) */ * ******************************************************************************/ -struct multiple_apic_table { - ACPI_TABLE_HEADER_DEF u32 local_apic_address; /* Physical address of local APIC */ - - /* Flags (32 bits) */ - - u8 PCATcompat:1; /* 00: System also has dual 8259s */ - u8:7; /* 01-07: Reserved, must be zero */ - u8 reserved1[3]; /* 08-31: Reserved, must be zero */ +struct acpi_table_madt { + struct acpi_table_header header; /* Common ACPI table header */ + u32 address; /* Physical address of local APIC */ + u32 flags; }; -/* Values for MADT PCATCompat */ +/* Flags */ -#define DUAL_PIC 0 -#define MULTIPLE_APIC 1 +#define ACPI_MADT_PCAT_COMPAT (1) /* 00: System also has dual 8259s */ -/* Common MADT Sub-table header */ +/* Values for PCATCompat flag */ -#define APIC_HEADER_DEF \ - u8 type; \ - u8 length; +#define ACPI_MADT_DUAL_PIC 0 +#define ACPI_MADT_MULTIPLE_APIC 1 -struct apic_header { -APIC_HEADER_DEF}; +/* Values for subtable type in struct acpi_subtable_header */ -/* Values for Type in struct apic_header */ - -#define APIC_PROCESSOR 0 -#define APIC_IO 1 -#define APIC_XRUPT_OVERRIDE 2 -#define APIC_NMI 3 -#define APIC_LOCAL_NMI 4 -#define APIC_ADDRESS_OVERRIDE 5 -#define APIC_IO_SAPIC 6 -#define APIC_LOCAL_SAPIC 7 -#define APIC_XRUPT_SOURCE 8 -#define APIC_RESERVED 9 /* 9 and greater are reserved */ - -/* Flag definitions for MADT sub-tables */ - -#define ACPI_MADT_IFLAGS /* INTI flags (16 bits) */ \ - u8 polarity : 2; /* 00-01: Polarity of APIC I/O input signals */\ - u8 trigger_mode : 2; /* 02-03: Trigger mode of APIC input signals */\ - u8 : 4; /* 04-07: Reserved, must be zero */\ - u8 reserved1; /* 08-15: Reserved, must be zero */ - -#define ACPI_MADT_LFLAGS /* Local Sapic flags (32 bits) */ \ - u8 processor_enabled: 1; /* 00: Processor is usable if set */\ - u8 : 7; /* 01-07: Reserved, must be zero */\ - u8 reserved2[3]; /* 08-31: Reserved, must be zero */ - -/* Values for MPS INTI flags */ - -#define POLARITY_CONFORMS 0 -#define POLARITY_ACTIVE_HIGH 1 -#define POLARITY_RESERVED 2 -#define POLARITY_ACTIVE_LOW 3 - -#define TRIGGER_CONFORMS 0 -#define TRIGGER_EDGE 1 -#define TRIGGER_RESERVED 2 -#define TRIGGER_LEVEL 3 +enum acpi_madt_type { + ACPI_MADT_TYPE_LOCAL_APIC = 0, + ACPI_MADT_TYPE_IO_APIC = 1, + ACPI_MADT_TYPE_INTERRUPT_OVERRIDE = 2, + ACPI_MADT_TYPE_NMI_SOURCE = 3, + ACPI_MADT_TYPE_LOCAL_APIC_NMI = 4, + ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE = 5, + ACPI_MADT_TYPE_IO_SAPIC = 6, + ACPI_MADT_TYPE_LOCAL_SAPIC = 7, + ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8, + ACPI_MADT_TYPE_RESERVED = 9 /* 9 and greater are reserved */ +}; /* - * MADT Sub-tables, correspond to Type in struct apic_header + * MADT Sub-tables, correspond to Type in struct acpi_subtable_header */ -/* 0: processor APIC */ +/* 0: Processor Local APIC */ -struct madt_processor_apic { - APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */ - u8 local_apic_id; /* Processor's local APIC id */ - ACPI_MADT_LFLAGS}; +struct acpi_madt_local_apic { + struct acpi_subtable_header header; + u8 processor_id; /* ACPI processor id */ + u8 id; /* Processor's local APIC id */ + u32 lapic_flags; +}; /* 1: IO APIC */ -struct madt_io_apic { - APIC_HEADER_DEF u8 io_apic_id; /* I/O APIC ID */ +struct acpi_madt_io_apic { + struct acpi_subtable_header header; + u8 id; /* I/O APIC ID */ u8 reserved; /* Reserved - must be zero */ u32 address; /* APIC physical address */ - u32 interrupt; /* Global system interrupt where INTI lines start */ + u32 global_irq_base; /* Global system interrupt where INTI lines start */ }; /* 2: Interrupt Override */ -struct madt_interrupt_override { - APIC_HEADER_DEF u8 bus; /* 0 - ISA */ - u8 source; /* Interrupt source (IRQ) */ - u32 interrupt; /* Global system interrupt */ - ACPI_MADT_IFLAGS}; +struct acpi_madt_interrupt_override { + struct acpi_subtable_header header; + u8 bus; /* 0 - ISA */ + u8 source_irq; /* Interrupt source (IRQ) */ + u32 global_irq; /* Global system interrupt */ + u16 inti_flags; +}; -/* 3: NMI Sources */ +/* 3: NMI Source */ -struct madt_nmi_source { - APIC_HEADER_DEF ACPI_MADT_IFLAGS u32 interrupt; /* Global system interrupt */ +struct acpi_madt_nmi_source { + struct acpi_subtable_header header; + u16 inti_flags; + u32 global_irq; /* Global system interrupt */ }; /* 4: Local APIC NMI */ -struct madt_local_apic_nmi { - APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */ - ACPI_MADT_IFLAGS u8 lint; /* LINTn to which NMI is connected */ +struct acpi_madt_local_apic_nmi { + struct acpi_subtable_header header; + u8 processor_id; /* ACPI processor id */ + u16 inti_flags; + u8 lint; /* LINTn to which NMI is connected */ }; /* 5: Address Override */ -struct madt_address_override { - APIC_HEADER_DEF u16 reserved; /* Reserved, must be zero */ +struct acpi_madt_local_apic_override { + struct acpi_subtable_header header; + u16 reserved; /* Reserved, must be zero */ u64 address; /* APIC physical address */ }; /* 6: I/O Sapic */ -struct madt_io_sapic { - APIC_HEADER_DEF u8 io_sapic_id; /* I/O SAPIC ID */ +struct acpi_madt_io_sapic { + struct acpi_subtable_header header; + u8 id; /* I/O SAPIC ID */ u8 reserved; /* Reserved, must be zero */ - u32 interrupt_base; /* Glocal interrupt for SAPIC start */ + u32 global_irq_base; /* Global interrupt for SAPIC start */ u64 address; /* SAPIC physical address */ }; /* 7: Local Sapic */ -struct madt_local_sapic { - APIC_HEADER_DEF u8 processor_id; /* ACPI processor id */ - u8 local_sapic_id; /* SAPIC ID */ - u8 local_sapic_eid; /* SAPIC EID */ +struct acpi_madt_local_sapic { + struct acpi_subtable_header header; + u8 processor_id; /* ACPI processor id */ + u8 id; /* SAPIC ID */ + u8 eid; /* SAPIC EID */ u8 reserved[3]; /* Reserved, must be zero */ - ACPI_MADT_LFLAGS u32 processor_uID; /* Numeric UID - ACPI 3.0 */ - char processor_uIDstring[1]; /* String UID - ACPI 3.0 */ + u32 lapic_flags; + u32 uid; /* Numeric UID - ACPI 3.0 */ + char uid_string[1]; /* String UID - ACPI 3.0 */ }; /* 8: Platform Interrupt Source */ -struct madt_interrupt_source { - APIC_HEADER_DEF ACPI_MADT_IFLAGS u8 interrupt_type; /* 1=PMI, 2=INIT, 3=corrected */ - u8 processor_id; /* Processor ID */ - u8 processor_eid; /* Processor EID */ +struct acpi_madt_interrupt_source { + struct acpi_subtable_header header; + u16 inti_flags; + u8 type; /* 1=PMI, 2=INIT, 3=corrected */ + u8 id; /* Processor ID */ + u8 eid; /* Processor EID */ u8 io_sapic_vector; /* Vector value for PMI interrupts */ - u32 interrupt; /* Global system interrupt */ + u32 global_irq; /* Global system interrupt */ u32 flags; /* Interrupt Source Flags */ }; -#ifdef DUPLICATE_DEFINITION_WITH_LINUX_ACPI_H +/* Flags field above */ + +#define ACPI_MADT_CPEI_OVERRIDE (1) + +/* + * Common flags fields for MADT subtables + */ + +/* MADT Local APIC flags (lapic_flags) */ + +#define ACPI_MADT_ENABLED (1) /* 00: Processor is usable if set */ + +/* MADT MPS INTI flags (inti_flags) */ + +#define ACPI_MADT_POLARITY_MASK (3) /* 00-01: Polarity of APIC I/O input signals */ +#define ACPI_MADT_TRIGGER_MASK (3<<2) /* 02-03: Trigger mode of APIC input signals */ + +/* Values for MPS INTI flags */ + +#define ACPI_MADT_POLARITY_CONFORMS 0 +#define ACPI_MADT_POLARITY_ACTIVE_HIGH 1 +#define ACPI_MADT_POLARITY_RESERVED 2 +#define ACPI_MADT_POLARITY_ACTIVE_LOW 3 + +#define ACPI_MADT_TRIGGER_CONFORMS (0) +#define ACPI_MADT_TRIGGER_EDGE (1<<2) +#define ACPI_MADT_TRIGGER_RESERVED (2<<2) +#define ACPI_MADT_TRIGGER_LEVEL (3<<2) + /******************************************************************************* * * MCFG - PCI Memory Mapped Configuration table and sub-table @@ -406,17 +524,19 @@ struct madt_interrupt_source { ******************************************************************************/ struct acpi_table_mcfg { - ACPI_TABLE_HEADER_DEF u8 reserved[8]; + struct acpi_table_header header; /* Common ACPI table header */ + u8 reserved[8]; }; +/* Subtable */ + struct acpi_mcfg_allocation { - u64 base_address; /* Base address, processor-relative */ + u64 address; /* Base address, processor-relative */ u16 pci_segment; /* PCI segment group number */ u8 start_bus_number; /* Starting PCI Bus number */ u8 end_bus_number; /* Final PCI Bus number */ u32 reserved; }; -#endif /******************************************************************************* * @@ -424,8 +544,9 @@ struct acpi_mcfg_allocation { * ******************************************************************************/ -struct smart_battery_table { - ACPI_TABLE_HEADER_DEF u32 warning_level; +struct acpi_table_sbst { + struct acpi_table_header header; /* Common ACPI table header */ + u32 warning_level; u32 low_level; u32 critical_level; }; @@ -436,9 +557,10 @@ struct smart_battery_table { * ******************************************************************************/ -struct system_locality_info { - ACPI_TABLE_HEADER_DEF u64 locality_count; - u8 entry[1][1]; +struct acpi_table_slit { + struct acpi_table_header header; /* Common ACPI table header */ + u64 locality_count; + u8 entry[1]; /* Real size = localities^2 */ }; /******************************************************************************* @@ -448,7 +570,8 @@ struct system_locality_info { ******************************************************************************/ struct acpi_table_spcr { - ACPI_TABLE_HEADER_DEF u8 interface_type; /* 0=full 16550, 1=subset of 16550 */ + struct acpi_table_header header; /* Common ACPI table header */ + u8 interface_type; /* 0=full 16550, 1=subset of 16550 */ u8 reserved[3]; struct acpi_generic_address serial_port; u8 interrupt_type; @@ -459,7 +582,7 @@ struct acpi_table_spcr { u8 stop_bits; u8 flow_control; u8 terminal_type; - u8 reserved2; + u8 reserved1; u16 pci_device_id; u16 pci_vendor_id; u8 pci_bus; @@ -467,7 +590,7 @@ struct acpi_table_spcr { u8 pci_function; u32 pci_flags; u8 pci_segment; - u32 reserved3; + u32 reserved2; }; /******************************************************************************* @@ -477,12 +600,13 @@ struct acpi_table_spcr { ******************************************************************************/ struct acpi_table_spmi { - ACPI_TABLE_HEADER_DEF u8 reserved; + struct acpi_table_header header; /* Common ACPI table header */ + u8 reserved; u8 interface_type; u16 spec_revision; /* Version of IPMI */ u8 interrupt_type; u8 gpe_number; /* GPE assigned */ - u8 reserved2; + u8 reserved1; u8 pci_device_flag; u32 interrupt; struct acpi_generic_address ipmi_register; @@ -498,58 +622,53 @@ struct acpi_table_spmi { * ******************************************************************************/ -struct system_resource_affinity { - ACPI_TABLE_HEADER_DEF u32 reserved1; /* Must be value '1' */ - u64 reserved2; /* Reserved, must be zero */ +struct acpi_table_srat { + struct acpi_table_header header; /* Common ACPI table header */ + u32 table_revision; /* Must be value '1' */ + u64 reserved; /* Reserved, must be zero */ }; -/* SRAT common sub-table header */ +/* Values for subtable type in struct acpi_subtable_header */ -#define SRAT_SUBTABLE_HEADER \ - u8 type; \ - u8 length; - -/* Values for Type above */ - -#define SRAT_CPU_AFFINITY 0 -#define SRAT_MEMORY_AFFINITY 1 -#define SRAT_RESERVED 2 +enum acpi_srat_type { + ACPI_SRAT_TYPE_CPU_AFFINITY = 0, + ACPI_SRAT_TYPE_MEMORY_AFFINITY = 1, + ACPI_SRAT_TYPE_RESERVED = 2 +}; /* SRAT sub-tables */ -struct static_resource_alloc { - SRAT_SUBTABLE_HEADER u8 proximity_domain_lo; +struct acpi_srat_cpu_affinity { + struct acpi_subtable_header header; + u8 proximity_domain_lo; u8 apic_id; - - /* Flags (32 bits) */ - - u8 enabled:1; /* 00: Use affinity structure */ - u8:7; /* 01-07: Reserved, must be zero */ - u8 reserved3[3]; /* 08-31: Reserved, must be zero */ - + u32 flags; u8 local_sapic_eid; u8 proximity_domain_hi[3]; - u32 reserved4; /* Reserved, must be zero */ + u32 reserved; /* Reserved, must be zero */ }; -struct memory_affinity { - SRAT_SUBTABLE_HEADER u32 proximity_domain; - u16 reserved3; +/* Flags */ + +#define ACPI_SRAT_CPU_ENABLED (1) /* 00: Use affinity structure */ + +struct acpi_srat_mem_affinity { + struct acpi_subtable_header header; + u32 proximity_domain; + u16 reserved; /* Reserved, must be zero */ u64 base_address; - u64 address_length; - u32 reserved4; - - /* Flags (32 bits) */ - - u8 enabled:1; /* 00: Use affinity structure */ - u8 hot_pluggable:1; /* 01: Memory region is hot pluggable */ - u8 non_volatile:1; /* 02: Memory is non-volatile */ - u8:5; /* 03-07: Reserved, must be zero */ - u8 reserved5[3]; /* 08-31: Reserved, must be zero */ - - u64 reserved6; /* Reserved, must be zero */ + u64 length; + u32 memory_type; /* See acpi_address_range_id */ + u32 flags; + u64 reserved1; /* Reserved, must be zero */ }; +/* Flags */ + +#define ACPI_SRAT_MEM_ENABLED (1) /* 00: Use affinity structure */ +#define ACPI_SRAT_MEM_HOT_PLUGGABLE (1<<1) /* 01: Memory region is hot pluggable */ +#define ACPI_SRAT_MEM_NON_VOLATILE (1<<2) /* 02: Memory region is non-volatile */ + /******************************************************************************* * * TCPA - Trusted Computing Platform Alliance table @@ -557,7 +676,8 @@ struct memory_affinity { ******************************************************************************/ struct acpi_table_tcpa { - ACPI_TABLE_HEADER_DEF u16 reserved; + struct acpi_table_header header; /* Common ACPI table header */ + u16 reserved; u32 max_log_length; /* Maximum length for the event log area */ u64 log_address; /* Address of the event log area */ }; @@ -569,7 +689,8 @@ struct acpi_table_tcpa { ******************************************************************************/ struct acpi_table_wdrt { - ACPI_TABLE_HEADER_DEF u32 header_length; /* Watchdog Header Length */ + struct acpi_table_header header; /* Common ACPI table header */ + u32 header_length; /* Watchdog Header Length */ u8 pci_segment; /* PCI Segment number */ u8 pci_bus; /* PCI Bus number */ u8 pci_device; /* PCI Device number */ @@ -582,58 +703,9 @@ struct acpi_table_wdrt { u32 entries; /* Number of watchdog entries that follow */ }; -#if 0 /* Flags, will be converted to macros */ -u8 enabled:1; /* 00: Timer enabled */ -u8:6; /* 01-06: Reserved */ -u8 sleep_stop:1; /* 07: Timer stopped in sleep state */ -#endif +/* Flags */ -/* Macros used to generate offsets to specific table fields */ - -#define ACPI_ASF0_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_info,f) -#define ACPI_ASF1_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_alert,f) -#define ACPI_ASF2_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_remote,f) -#define ACPI_ASF3_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_rmcp,f) -#define ACPI_ASF4_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_asf_address,f) -#define ACPI_BOOT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_boot,f) -#define ACPI_CPEP_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_cpep,f) -#define ACPI_CPEP0_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_cpep_polling,f) -#define ACPI_DBGP_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_dbgp,f) -#define ACPI_ECDT_OFFSET(f) (u8) ACPI_OFFSET (struct ec_boot_resources,f) -#define ACPI_HPET_OFFSET(f) (u8) ACPI_OFFSET (struct hpet_table,f) -#define ACPI_MADT_OFFSET(f) (u8) ACPI_OFFSET (struct multiple_apic_table,f) -#define ACPI_MADT0_OFFSET(f) (u8) ACPI_OFFSET (struct madt_processor_apic,f) -#define ACPI_MADT1_OFFSET(f) (u8) ACPI_OFFSET (struct madt_io_apic,f) -#define ACPI_MADT2_OFFSET(f) (u8) ACPI_OFFSET (struct madt_interrupt_override,f) -#define ACPI_MADT3_OFFSET(f) (u8) ACPI_OFFSET (struct madt_nmi_source,f) -#define ACPI_MADT4_OFFSET(f) (u8) ACPI_OFFSET (struct madt_local_apic_nmi,f) -#define ACPI_MADT5_OFFSET(f) (u8) ACPI_OFFSET (struct madt_address_override,f) -#define ACPI_MADT6_OFFSET(f) (u8) ACPI_OFFSET (struct madt_io_sapic,f) -#define ACPI_MADT7_OFFSET(f) (u8) ACPI_OFFSET (struct madt_local_sapic,f) -#define ACPI_MADT8_OFFSET(f) (u8) ACPI_OFFSET (struct madt_interrupt_source,f) -#define ACPI_MADTH_OFFSET(f) (u8) ACPI_OFFSET (struct apic_header,f) -#define ACPI_MCFG_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_mcfg,f) -#define ACPI_MCFG0_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_mcfg_allocation,f) -#define ACPI_SBST_OFFSET(f) (u8) ACPI_OFFSET (struct smart_battery_table,f) -#define ACPI_SLIT_OFFSET(f) (u8) ACPI_OFFSET (struct system_locality_info,f) -#define ACPI_SPCR_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_spcr,f) -#define ACPI_SPMI_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_spmi,f) -#define ACPI_SRAT_OFFSET(f) (u8) ACPI_OFFSET (struct system_resource_affinity,f) -#define ACPI_SRAT0_OFFSET(f) (u8) ACPI_OFFSET (struct static_resource_alloc,f) -#define ACPI_SRAT1_OFFSET(f) (u8) ACPI_OFFSET (struct memory_affinity,f) -#define ACPI_TCPA_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_tcpa,f) -#define ACPI_WDRT_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_table_wdrt,f) - -#define ACPI_HPET_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct hpet_table,f,o) -#define ACPI_SRAT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct static_resource_alloc,f,o) -#define ACPI_SRAT1_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct memory_affinity,f,o) -#define ACPI_MADT_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct multiple_apic_table,f,o) -#define ACPI_MADT0_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_processor_apic,f,o) -#define ACPI_MADT2_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_interrupt_override,f,o) -#define ACPI_MADT3_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_nmi_source,f,o) -#define ACPI_MADT4_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_local_apic_nmi,f,o) -#define ACPI_MADT7_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_local_sapic,f,o) -#define ACPI_MADT8_FLAG_OFFSET(f,o) ACPI_FLAG_OFFSET (struct madt_interrupt_source,f,o) +#define ACPI_WDRT_TIMER_ENABLED (1) /* 00: Timer enabled */ /* Reset to default packing */ 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/acpi/actypes.h b/include/acpi/actypes.h index 64b603cfe92e..72a6e2c3a536 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,7 +48,8 @@ /* * ACPI_MACHINE_WIDTH must be specified in an OS- or compiler-dependent header - * and must be either 16, 32, or 64 + * and must be either 32 or 64. 16-bit ACPICA is no longer supported, as of + * 12/2006. */ #ifndef ACPI_MACHINE_WIDTH #error ACPI_MACHINE_WIDTH not defined @@ -149,7 +150,6 @@ typedef int INT32; typedef u64 acpi_native_uint; typedef s64 acpi_native_int; -typedef u64 acpi_table_ptr; typedef u64 acpi_io_address; typedef u64 acpi_physical_address; @@ -189,48 +189,15 @@ typedef int INT32; typedef u32 acpi_native_uint; typedef s32 acpi_native_int; -typedef u64 acpi_table_ptr; typedef u32 acpi_io_address; -typedef u64 acpi_physical_address; +typedef u32 acpi_physical_address; #define ACPI_MAX_PTR ACPI_UINT32_MAX #define ACPI_SIZE_MAX ACPI_UINT32_MAX -/******************************************************************************* - * - * Types specific to 16-bit targets - * - ******************************************************************************/ - -#elif ACPI_MACHINE_WIDTH == 16 - -/*! [Begin] no source code translation (keep the typedefs as-is) */ - -typedef unsigned long UINT32; -typedef short INT16; -typedef long INT32; - -/*! [End] no source code translation !*/ - -typedef u16 acpi_native_uint; -typedef s16 acpi_native_int; - -typedef u32 acpi_table_ptr; -typedef u32 acpi_io_address; -typedef char *acpi_physical_address; - -#define ACPI_MAX_PTR ACPI_UINT16_MAX -#define ACPI_SIZE_MAX ACPI_UINT16_MAX - -#define ACPI_USE_NATIVE_DIVIDE /* No 64-bit integers, ok to use native divide */ - -/* 64-bit integers cannot be supported */ - -#define ACPI_NO_INTEGER64_SUPPORT - #else -/* ACPI_MACHINE_WIDTH must be either 64, 32, or 16 */ +/* ACPI_MACHINE_WIDTH must be either 64 or 32 */ #error unknown ACPI_MACHINE_WIDTH #endif @@ -311,36 +278,6 @@ typedef acpi_native_uint acpi_size; * ******************************************************************************/ -/* - * Pointer overlays to avoid lots of typecasting for - * code that accepts both physical and logical pointers. - */ -union acpi_pointers { - acpi_physical_address physical; - void *logical; - acpi_table_ptr value; -}; - -struct acpi_pointer { - u32 pointer_type; - union acpi_pointers pointer; -}; - -/* pointer_types for above */ - -#define ACPI_PHYSICAL_POINTER 0x01 -#define ACPI_LOGICAL_POINTER 0x02 - -/* Processor mode */ - -#define ACPI_PHYSICAL_ADDRESSING 0x04 -#define ACPI_LOGICAL_ADDRESSING 0x08 -#define ACPI_MEMORY_MODE 0x0C - -#define ACPI_PHYSMODE_PHYSPTR ACPI_PHYSICAL_ADDRESSING | ACPI_PHYSICAL_POINTER -#define ACPI_LOGMODE_PHYSPTR ACPI_LOGICAL_ADDRESSING | ACPI_PHYSICAL_POINTER -#define ACPI_LOGMODE_LOGPTR ACPI_LOGICAL_ADDRESSING | ACPI_LOGICAL_POINTER - /* Logical defines and NULL */ #ifdef FALSE @@ -442,7 +379,8 @@ typedef u64 acpi_integer; /* * Initialization state */ -#define ACPI_INITIALIZED_OK 0x01 +#define ACPI_SUBSYSTEM_INITIALIZE 0x01 +#define ACPI_INITIALIZED_OK 0x02 /* * Power state values @@ -490,21 +428,6 @@ typedef u64 acpi_integer; #define ACPI_NOTIFY_BUS_MODE_MISMATCH (u8) 6 #define ACPI_NOTIFY_POWER_FAULT (u8) 7 -/* - * Table types. These values are passed to the table related APIs - */ -typedef u32 acpi_table_type; - -#define ACPI_TABLE_ID_RSDP (acpi_table_type) 0 -#define ACPI_TABLE_ID_DSDT (acpi_table_type) 1 -#define ACPI_TABLE_ID_FADT (acpi_table_type) 2 -#define ACPI_TABLE_ID_FACS (acpi_table_type) 3 -#define ACPI_TABLE_ID_PSDT (acpi_table_type) 4 -#define ACPI_TABLE_ID_SSDT (acpi_table_type) 5 -#define ACPI_TABLE_ID_XSDT (acpi_table_type) 6 -#define ACPI_TABLE_ID_MAX 6 -#define ACPI_NUM_TABLE_TYPES (ACPI_TABLE_ID_MAX+1) - /* * Types associated with ACPI names and objects. The first group of * values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition @@ -637,7 +560,7 @@ typedef u32 acpi_event_status; * | | | +--- Type of dispatch -- to method, handler, or none * | | +--- Enabled for runtime? * | +--- Enabled for wake? - * +--- System state when GPE ocurred (running/waking) + * +--- Unused */ #define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x01 #define ACPI_GPE_LEVEL_TRIGGERED (u8) 0x01 @@ -663,10 +586,6 @@ typedef u32 acpi_event_status; #define ACPI_GPE_ENABLE_MASK (u8) 0x60 /* Both run/wake */ -#define ACPI_GPE_SYSTEM_MASK (u8) 0x80 -#define ACPI_GPE_SYSTEM_RUNNING (u8) 0x80 -#define ACPI_GPE_SYSTEM_WAKING (u8) 0x00 - /* * Flags for GPE and Lock interfaces */ @@ -815,13 +734,6 @@ struct acpi_buffer { #define ACPI_SYS_MODE_LEGACY 0x0002 #define ACPI_SYS_MODES_MASK 0x0003 -/* - * ACPI Table Info. One per ACPI table _type_ - */ -struct acpi_table_info { - u32 count; -}; - /* * System info returned by acpi_get_system_info() */ @@ -833,8 +745,6 @@ struct acpi_system_info { u32 reserved2; u32 debug_level; u32 debug_layer; - u32 num_table_types; - struct acpi_table_info table_info[ACPI_TABLE_ID_MAX + 1]; }; /* diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h index ba039ea1a057..883ffe92148f 100644 --- a/include/acpi/acutils.h +++ b/include/acpi/acutils.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -141,8 +141,6 @@ acpi_status acpi_ut_hardware_initialize(void); void acpi_ut_subsystem_shutdown(void); -acpi_status acpi_ut_validate_fadt(void); - /* * utclib - Local implementations of C library functions */ @@ -453,6 +451,8 @@ acpi_ut_short_divide(acpi_integer in_dividend, /* * utmisc */ +const char *acpi_ut_validate_exception(acpi_status status); + u8 acpi_ut_is_aml_table(struct acpi_table_header *table); acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id); @@ -470,7 +470,7 @@ void acpi_ut_print_string(char *string, u8 max_length); u8 acpi_ut_valid_acpi_name(u32 name); -acpi_name acpi_ut_repair_name(acpi_name name); +acpi_name acpi_ut_repair_name(char *name); u8 acpi_ut_valid_acpi_char(char character, acpi_native_uint position); diff --git a/include/acpi/amlcode.h b/include/acpi/amlcode.h index cf18426a87b1..da53a4ef287a 100644 --- a/include/acpi/amlcode.h +++ b/include/acpi/amlcode.h @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -273,7 +273,7 @@ #define ARGI_DATAOBJECT 0x12 /* Buffer, String, package or reference to a Node - Used only by size_of operator */ #define ARGI_COMPLEXOBJ 0x13 /* Buffer, String, or package (Used by INDEX op only) */ #define ARGI_REF_OR_STRING 0x14 /* Reference or String (Used by DEREFOF op only) */ -#define ARGI_REGION_OR_FIELD 0x15 /* Used by LOAD op only */ +#define ARGI_REGION_OR_BUFFER 0x15 /* Used by LOAD op only */ #define ARGI_DATAREFOBJ 0x16 /* Note: types above can expand to 0x1F maximum */ diff --git a/include/acpi/amlresrc.h b/include/acpi/amlresrc.h index be03818af9d1..f7d541239da4 100644 --- a/include/acpi/amlresrc.h +++ b/include/acpi/amlresrc.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index 453a469fd397..dab2ec59a3b0 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h index da80933963db..3bb50494a38a 100644 --- a/include/acpi/platform/acgcc.h +++ b/include/acpi/platform/acgcc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 7f1e92930b62..5f532d2ac180 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2006, R. Byron Moore + * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without 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/asm-i386/acpi.h b/include/asm-i386/acpi.h index 7cfad93edf10..5e657eb8946c 100644 --- a/include/asm-i386/acpi.h +++ b/include/asm-i386/acpi.h @@ -39,7 +39,7 @@ * Calling conventions: * * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) - * ACPI_EXTERNAL_XFACE - External ACPI interfaces + * ACPI_EXTERNAL_XFACE - External ACPI interfaces * ACPI_INTERNAL_XFACE - Internal ACPI interfaces * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces */ @@ -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 @@ -87,7 +87,7 @@ extern void check_acpi_pci(void); static inline void check_acpi_pci(void) { } #endif -#ifdef CONFIG_ACPI +#ifdef CONFIG_ACPI extern int acpi_lapic; extern int acpi_ioapic; extern int acpi_noirq; @@ -95,9 +95,9 @@ extern int acpi_strict; extern int acpi_disabled; extern int acpi_ht; extern int acpi_pci_disabled; -static inline void disable_acpi(void) -{ - acpi_disabled = 1; +static inline void disable_acpi(void) +{ + acpi_disabled = 1; acpi_ht = 0; acpi_pci_disabled = 1; acpi_noirq = 1; @@ -114,9 +114,9 @@ extern int acpi_use_timer_override; #endif static inline void acpi_noirq_set(void) { acpi_noirq = 1; } -static inline void acpi_disable_pci(void) +static inline void acpi_disable_pci(void) { - acpi_pci_disabled = 1; + acpi_pci_disabled = 1; acpi_noirq_set(); } extern int acpi_irq_balance_set(char *str); @@ -144,8 +144,6 @@ extern void acpi_reserve_bootmem(void); #endif /*CONFIG_ACPI_SLEEP*/ -extern u8 x86_acpiid_to_apicid[]; - #define ARCH_HAS_POWER_INIT 1 #endif /*__KERNEL__*/ 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/asm-ia64/acpi.h b/include/asm-ia64/acpi.h index 09a5dd0e44a8..5d03792d4f65 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 */ @@ -119,8 +119,6 @@ extern int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS]; extern int __initdata nid_to_pxm_map[MAX_NUMNODES]; #endif -extern u16 ia64_acpiid_to_sapicid[]; - /* * Refer Intel ACPI _PDC support document for bit definitions */ diff --git a/include/asm-ia64/dma.h b/include/asm-ia64/dma.h index dad3a735df8b..4d97f60f1ef5 100644 --- a/include/asm-ia64/dma.h +++ b/include/asm-ia64/dma.h @@ -19,4 +19,6 @@ extern unsigned long MAX_DMA_ADDRESS; #define free_dma(x) +void dma_mark_clean(void *addr, size_t size); + #endif /* _ASM_IA64_DMA_H */ diff --git a/include/asm-ia64/esi.h b/include/asm-ia64/esi.h index 84aac0e0b583..40991c6ba647 100644 --- a/include/asm-ia64/esi.h +++ b/include/asm-ia64/esi.h @@ -19,7 +19,6 @@ enum esi_proc_type { ESI_PROC_REENTRANT /* MP-safe and reentrant */ }; -extern int ia64_esi_init (void); extern struct ia64_sal_retval esi_call_phys (void *, u64 *); extern int ia64_esi_call(efi_guid_t, struct ia64_sal_retval *, enum esi_proc_type, 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/asm-ia64/meminit.h b/include/asm-ia64/meminit.h index c8df75901083..6dd476b652c6 100644 --- a/include/asm-ia64/meminit.h +++ b/include/asm-ia64/meminit.h @@ -51,12 +51,13 @@ extern void efi_memmap_init(unsigned long *, unsigned long *); #define IGNORE_PFN0 1 /* XXX fix me: ignore pfn 0 until TLB miss handler is updated... */ +extern int register_active_ranges(u64 start, u64 end, void *arg); + #ifdef CONFIG_VIRTUAL_MEM_MAP # define LARGE_GAP 0x40000000 /* Use virtual mem map if hole is > than this */ extern unsigned long vmalloc_end; extern struct page *vmem_map; extern int find_largest_hole (u64 start, u64 end, void *arg); - extern int register_active_ranges (u64 start, u64 end, void *arg); extern int create_mem_map_page_table (u64 start, u64 end, void *arg); extern int vmemmap_find_next_valid_pfn(int, int); #else diff --git a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h index 393e04c42a2c..560c287b1233 100644 --- a/include/asm-ia64/pgalloc.h +++ b/include/asm-ia64/pgalloc.h @@ -137,7 +137,8 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t * pmd_entry, pte_t * pte) static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long addr) { - return virt_to_page(pgtable_quicklist_alloc()); + void *pg = pgtable_quicklist_alloc(); + return pg ? virt_to_page(pg) : NULL; } static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, diff --git a/include/asm-ia64/sn/acpi.h b/include/asm-ia64/sn/acpi.h index 2850a7ef5e71..9ce2801cbd57 100644 --- a/include/asm-ia64/sn/acpi.h +++ b/include/asm-ia64/sn/acpi.h @@ -11,6 +11,7 @@ #include "acpi/acglobal.h" -#define SN_ACPI_BASE_SUPPORT() (acpi_gbl_DSDT->oem_revision >= 0x20101) +extern int sn_acpi_rev; +#define SN_ACPI_BASE_SUPPORT() (sn_acpi_rev >= 0x20101) #endif /* _ASM_IA64_SN_ACPI_H */ diff --git a/include/asm-ia64/sn/pcibr_provider.h b/include/asm-ia64/sn/pcibr_provider.h index da3eade0cae2..17cb6cc3f21a 100644 --- a/include/asm-ia64/sn/pcibr_provider.h +++ b/include/asm-ia64/sn/pcibr_provider.h @@ -142,7 +142,7 @@ extern int pcibr_ate_alloc(struct pcibus_info *, int); extern void pcibr_ate_free(struct pcibus_info *, int); extern void ate_write(struct pcibus_info *, int, int, u64); extern int sal_pcibr_slot_enable(struct pcibus_info *soft, int device, - void *resp); + void *resp, char **ssdt); extern int sal_pcibr_slot_disable(struct pcibus_info *soft, int device, int action, void *resp); extern u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus); diff --git a/include/asm-ia64/sn/pcidev.h b/include/asm-ia64/sn/pcidev.h index 9fe89a93d880..1c2382cea807 100644 --- a/include/asm-ia64/sn/pcidev.h +++ b/include/asm-ia64/sn/pcidev.h @@ -70,10 +70,16 @@ extern void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info); extern void sn_irq_unfixup(struct pci_dev *pci_dev); extern struct pcidev_info * sn_pcidev_info_get(struct pci_dev *); +extern void sn_bus_fixup(struct pci_bus *); +extern void sn_acpi_bus_fixup(struct pci_bus *); +extern void sn_common_bus_fixup(struct pci_bus *, struct pcibus_bussoft *); extern void sn_bus_store_sysdata(struct pci_dev *dev); extern void sn_bus_free_sysdata(void); extern void sn_generate_path(struct pci_bus *pci_bus, char *address); -extern void sn_pci_fixup_slot(struct pci_dev *dev); +extern void sn_io_slot_fixup(struct pci_dev *); +extern void sn_acpi_slot_fixup(struct pci_dev *); +extern void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *, + struct sn_irq_info *); extern void sn_pci_unfixup_slot(struct pci_dev *dev); extern void sn_irq_lh_init(void); #endif /* _ASM_IA64_SN_PCI_PCIDEV_H */ diff --git a/include/asm-ia64/swiotlb.h b/include/asm-ia64/swiotlb.h new file mode 100644 index 000000000000..452c162dee4e --- /dev/null +++ b/include/asm-ia64/swiotlb.h @@ -0,0 +1,9 @@ +#ifndef _ASM_SWIOTLB_H +#define _ASM_SWIOTLB_H 1 + +#include + +#define SWIOTLB_ARCH_NEED_LATE_INIT +#define SWIOTLB_ARCH_NEED_ALLOC + +#endif /* _ASM_SWIOTLB_H */ diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h index 9b505b25544f..91698599f918 100644 --- a/include/asm-ia64/thread_info.h +++ b/include/asm-ia64/thread_info.h @@ -84,6 +84,7 @@ struct thread_info { #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ #define TIF_SYSCALL_TRACE 3 /* syscall trace active */ #define TIF_SYSCALL_AUDIT 4 /* syscall auditing active */ +#define TIF_SINGLESTEP 5 /* restore singlestep on return to user mode */ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_MEMDIE 17 #define TIF_MCA_INIT 18 /* this task is processing MCA or INIT */ @@ -92,7 +93,8 @@ struct thread_info { #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) -#define _TIF_SYSCALL_TRACEAUDIT (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) +#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) +#define _TIF_SYSCALL_TRACEAUDIT (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h index 53c5c0ee122c..a9e1fa4cac4d 100644 --- a/include/asm-ia64/unistd.h +++ b/include/asm-ia64/unistd.h @@ -291,11 +291,13 @@ #define __NR_sync_file_range 1300 #define __NR_tee 1301 #define __NR_vmsplice 1302 +/* 1303 reserved for move_pages */ +#define __NR_getcpu 1304 #ifdef __KERNEL__ -#define NR_syscalls 279 /* length of syscall table */ +#define NR_syscalls 281 /* length of syscall table */ #define __ARCH_WANT_SYS_RT_SIGACTION diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h index 8e321f53a382..c7c945baf1ee 100644 --- a/include/asm-mips/bootinfo.h +++ b/include/asm-mips/bootinfo.h @@ -243,6 +243,10 @@ extern struct boot_mem_map boot_mem_map; extern void add_memory_region(phys_t start, phys_t size, long type); extern void prom_init(void); +extern void prom_free_prom_memory(void); + +extern void free_init_pages(const char *what, + unsigned long begin, unsigned long end); /* * Initial kernel command line, usually setup by prom_init() diff --git a/include/asm-mips/ddb5xxx/ddb5477.h b/include/asm-mips/ddb5xxx/ddb5477.h index c5af4b73fdd7..6cf177caf6d5 100644 --- a/include/asm-mips/ddb5xxx/ddb5477.h +++ b/include/asm-mips/ddb5xxx/ddb5477.h @@ -17,6 +17,7 @@ #ifndef __ASM_DDB5XXX_DDB5477_H #define __ASM_DDB5XXX_DDB5477_H +#include /* * This contains macros that are specific to DDB5477 or renamed from @@ -251,14 +252,10 @@ extern void ll_vrc5477_irq_disable(int vrc5477_irq); */ #define NUM_CPU_IRQ 8 -#define NUM_I8259_IRQ 16 #define NUM_VRC5477_IRQ 32 -#define DDB_IRQ_BASE 0 - -#define I8259_IRQ_BASE DDB_IRQ_BASE -#define VRC5477_IRQ_BASE (I8259_IRQ_BASE + NUM_I8259_IRQ) -#define CPU_IRQ_BASE (VRC5477_IRQ_BASE + NUM_VRC5477_IRQ) +#define CPU_IRQ_BASE MIPS_CPU_IRQ_BASE +#define VRC5477_IRQ_BASE (CPU_IRQ_BASE + NUM_CPU_IRQ) /* * vrc5477 irq defs @@ -300,22 +297,22 @@ extern void ll_vrc5477_irq_disable(int vrc5477_irq); /* * i2859 irq assignment */ -#define I8259_IRQ_RESERVED_0 (0 + I8259_IRQ_BASE) -#define I8259_IRQ_KEYBOARD (1 + I8259_IRQ_BASE) /* M1543 default */ -#define I8259_IRQ_CASCADE (2 + I8259_IRQ_BASE) -#define I8259_IRQ_UART_B (3 + I8259_IRQ_BASE) /* M1543 default, may conflict with RTC according to schematic diagram */ -#define I8259_IRQ_UART_A (4 + I8259_IRQ_BASE) /* M1543 default */ -#define I8259_IRQ_PARALLEL (5 + I8259_IRQ_BASE) /* M1543 default */ -#define I8259_IRQ_RESERVED_6 (6 + I8259_IRQ_BASE) -#define I8259_IRQ_RESERVED_7 (7 + I8259_IRQ_BASE) -#define I8259_IRQ_RTC (8 + I8259_IRQ_BASE) /* who set this? */ -#define I8259_IRQ_USB (9 + I8259_IRQ_BASE) /* ddb_setup */ -#define I8259_IRQ_PMU (10 + I8259_IRQ_BASE) /* ddb_setup */ -#define I8259_IRQ_RESERVED_11 (11 + I8259_IRQ_BASE) -#define I8259_IRQ_RESERVED_12 (12 + I8259_IRQ_BASE) /* m1543_irq_setup */ -#define I8259_IRQ_RESERVED_13 (13 + I8259_IRQ_BASE) -#define I8259_IRQ_HDC1 (14 + I8259_IRQ_BASE) /* default and ddb_setup */ -#define I8259_IRQ_HDC2 (15 + I8259_IRQ_BASE) /* default */ +#define I8259_IRQ_RESERVED_0 (0 + I8259A_IRQ_BASE) +#define I8259_IRQ_KEYBOARD (1 + I8259A_IRQ_BASE) /* M1543 default */ +#define I8259_IRQ_CASCADE (2 + I8259A_IRQ_BASE) +#define I8259_IRQ_UART_B (3 + I8259A_IRQ_BASE) /* M1543 default, may conflict with RTC according to schematic diagram */ +#define I8259_IRQ_UART_A (4 + I8259A_IRQ_BASE) /* M1543 default */ +#define I8259_IRQ_PARALLEL (5 + I8259A_IRQ_BASE) /* M1543 default */ +#define I8259_IRQ_RESERVED_6 (6 + I8259A_IRQ_BASE) +#define I8259_IRQ_RESERVED_7 (7 + I8259A_IRQ_BASE) +#define I8259_IRQ_RTC (8 + I8259A_IRQ_BASE) /* who set this? */ +#define I8259_IRQ_USB (9 + I8259A_IRQ_BASE) /* ddb_setup */ +#define I8259_IRQ_PMU (10 + I8259A_IRQ_BASE) /* ddb_setup */ +#define I8259_IRQ_RESERVED_11 (11 + I8259A_IRQ_BASE) +#define I8259_IRQ_RESERVED_12 (12 + I8259A_IRQ_BASE) /* m1543_irq_setup */ +#define I8259_IRQ_RESERVED_13 (13 + I8259A_IRQ_BASE) +#define I8259_IRQ_HDC1 (14 + I8259A_IRQ_BASE) /* default and ddb_setup */ +#define I8259_IRQ_HDC2 (15 + I8259A_IRQ_BASE) /* default */ /* diff --git a/include/asm-mips/dec/interrupts.h b/include/asm-mips/dec/interrupts.h index 273e4d65bfe6..e10d341067c8 100644 --- a/include/asm-mips/dec/interrupts.h +++ b/include/asm-mips/dec/interrupts.h @@ -14,6 +14,7 @@ #ifndef __ASM_DEC_INTERRUPTS_H #define __ASM_DEC_INTERRUPTS_H +#include #include @@ -87,7 +88,7 @@ #define DEC_CPU_INR_SW1 1 /* software #1 */ #define DEC_CPU_INR_SW0 0 /* software #0 */ -#define DEC_CPU_IRQ_BASE 0 /* first IRQ assigned to CPU */ +#define DEC_CPU_IRQ_BASE MIPS_CPU_IRQ_BASE /* first IRQ assigned to CPU */ #define DEC_CPU_IRQ_NR(n) ((n) + DEC_CPU_IRQ_BASE) #define DEC_CPU_IRQ_MASK(n) (1 << ((n) + CAUSEB_IP)) diff --git a/include/asm-mips/dma.h b/include/asm-mips/dma.h index 23f789c80845..e06ef0776d48 100644 --- a/include/asm-mips/dma.h +++ b/include/asm-mips/dma.h @@ -91,6 +91,7 @@ #else #define MAX_DMA_ADDRESS (PAGE_OFFSET + 0x01000000) #endif +#define MAX_DMA_PFN PFN_DOWN(virt_to_phys((void *)MAX_DMA_ADDRESS)) /* 8237 DMA controllers */ #define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ diff --git a/include/asm-mips/emma2rh/emma2rh.h b/include/asm-mips/emma2rh/emma2rh.h index 4fb8df71caa9..6a1af0af51e3 100644 --- a/include/asm-mips/emma2rh/emma2rh.h +++ b/include/asm-mips/emma2rh/emma2rh.h @@ -24,6 +24,8 @@ #ifndef __ASM_EMMA2RH_EMMA2RH_H #define __ASM_EMMA2RH_EMMA2RH_H +#include + /* * EMMA2RH registers */ @@ -104,7 +106,8 @@ #define NUM_EMMA2RH_IRQ 96 #define CPU_EMMA2RH_CASCADE 2 -#define EMMA2RH_IRQ_BASE 0 +#define CPU_IRQ_BASE MIPS_CPU_IRQ_BASE +#define EMMA2RH_IRQ_BASE (CPU_IRQ_BASE + NUM_CPU_IRQ) /* * emma2rh irq defs diff --git a/include/asm-mips/emma2rh/markeins.h b/include/asm-mips/emma2rh/markeins.h index 8fa766795078..973b0628490d 100644 --- a/include/asm-mips/emma2rh/markeins.h +++ b/include/asm-mips/emma2rh/markeins.h @@ -33,7 +33,6 @@ #define EMMA2RH_SW_IRQ_BASE (EMMA2RH_IRQ_BASE + NUM_EMMA2RH_IRQ) #define EMMA2RH_GPIO_IRQ_BASE (EMMA2RH_SW_IRQ_BASE + NUM_EMMA2RH_IRQ_SW) -#define CPU_IRQ_BASE (EMMA2RH_GPIO_IRQ_BASE + NUM_EMMA2RH_IRQ_GPIO) #define EMMA2RH_SW_IRQ_INT0 (0+EMMA2RH_SW_IRQ_BASE) #define EMMA2RH_SW_IRQ_INT1 (1+EMMA2RH_SW_IRQ_BASE) diff --git a/include/asm-mips/i8259.h b/include/asm-mips/i8259.h index 4df8d8b118c0..e88a01607fea 100644 --- a/include/asm-mips/i8259.h +++ b/include/asm-mips/i8259.h @@ -18,6 +18,7 @@ #include #include +#include /* i8259A PIC registers */ #define PIC_MASTER_CMD 0x20 @@ -42,8 +43,6 @@ extern void disable_8259A_irq(unsigned int irq); extern void init_i8259_irqs(void); -#define I8259A_IRQ_BASE 0 - /* * Do the traditional i8259 interrupt polling thing. This is for the few * cases where no better interrupt acknowledge method is available and we diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h index d77b657c09c7..67f081078904 100644 --- a/include/asm-mips/io.h +++ b/include/asm-mips/io.h @@ -115,7 +115,7 @@ static inline void set_io_port_base(unsigned long base) */ static inline unsigned long virt_to_phys(volatile const void *address) { - return (unsigned long)address - PAGE_OFFSET; + return (unsigned long)address - PAGE_OFFSET + PHYS_OFFSET; } /* @@ -132,7 +132,7 @@ static inline unsigned long virt_to_phys(volatile const void *address) */ static inline void * phys_to_virt(unsigned long address) { - return (void *)(address + PAGE_OFFSET); + return (void *)(address + PAGE_OFFSET - PHYS_OFFSET); } /* diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h index 386da82e5774..91803ba30ff2 100644 --- a/include/asm-mips/irq.h +++ b/include/asm-mips/irq.h @@ -18,7 +18,7 @@ #ifdef CONFIG_I8259 static inline int irq_canonicalize(int irq) { - return ((irq == 2) ? 9 : irq); + return ((irq == I8259A_IRQ_BASE + 2) ? I8259A_IRQ_BASE + 9 : irq); } #else #define irq_canonicalize(irq) (irq) /* Sane hardware, sane code ... */ diff --git a/include/asm-mips/irq_cpu.h b/include/asm-mips/irq_cpu.h index ed3d1e3d09ec..ef6a07cddb23 100644 --- a/include/asm-mips/irq_cpu.h +++ b/include/asm-mips/irq_cpu.h @@ -13,8 +13,8 @@ #ifndef _ASM_IRQ_CPU_H #define _ASM_IRQ_CPU_H -extern void mips_cpu_irq_init(int irq_base); -extern void rm7k_cpu_irq_init(int irq_base); -extern void rm9k_cpu_irq_init(int irq_base); +extern void mips_cpu_irq_init(void); +extern void rm7k_cpu_irq_init(void); +extern void rm9k_cpu_irq_init(void); #endif /* _ASM_IRQ_CPU_H */ diff --git a/include/asm-mips/mach-au1x00/au1000.h b/include/asm-mips/mach-au1x00/au1000.h index 582acd8adb81..58fca8a5a9a6 100644 --- a/include/asm-mips/mach-au1x00/au1000.h +++ b/include/asm-mips/mach-au1x00/au1000.h @@ -39,6 +39,7 @@ #ifndef _LANGUAGE_ASSEMBLY #include +#include #include /* cpu pipeline flush */ diff --git a/include/asm-mips/mach-cobalt/cobalt.h b/include/asm-mips/mach-cobalt/cobalt.h index 00b0fc68d5cb..24a8d51a55a3 100644 --- a/include/asm-mips/mach-cobalt/cobalt.h +++ b/include/asm-mips/mach-cobalt/cobalt.h @@ -12,6 +12,8 @@ #ifndef __ASM_COBALT_H #define __ASM_COBALT_H +#include + /* * i8259 legacy interrupts used on Cobalt: * @@ -25,7 +27,7 @@ /* * CPU IRQs are 16 ... 23 */ -#define COBALT_CPU_IRQ 16 +#define COBALT_CPU_IRQ MIPS_CPU_IRQ_BASE #define COBALT_GALILEO_IRQ (COBALT_CPU_IRQ + 2) #define COBALT_SCC_IRQ (COBALT_CPU_IRQ + 3) /* pre-production has 85C30 */ diff --git a/include/asm-mips/mach-emma2rh/irq.h b/include/asm-mips/mach-emma2rh/irq.h index bce64244b800..5439eb856461 100644 --- a/include/asm-mips/mach-emma2rh/irq.h +++ b/include/asm-mips/mach-emma2rh/irq.h @@ -10,4 +10,6 @@ #define NR_IRQS 256 +#include_next + #endif /* __ASM_MACH_EMMA2RH_IRQ_H */ diff --git a/include/asm-mips/mach-generic/irq.h b/include/asm-mips/mach-generic/irq.h index 500e10ff24de..70d9a25132c5 100644 --- a/include/asm-mips/mach-generic/irq.h +++ b/include/asm-mips/mach-generic/irq.h @@ -8,6 +8,38 @@ #ifndef __ASM_MACH_GENERIC_IRQ_H #define __ASM_MACH_GENERIC_IRQ_H +#ifndef NR_IRQS #define NR_IRQS 128 +#endif + +#ifdef CONFIG_I8259 +#ifndef I8259A_IRQ_BASE +#define I8259A_IRQ_BASE 0 +#endif +#endif + +#ifdef CONFIG_IRQ_CPU + +#ifndef MIPS_CPU_IRQ_BASE +#ifdef CONFIG_I8259 +#define MIPS_CPU_IRQ_BASE 16 +#else +#define MIPS_CPU_IRQ_BASE 0 +#endif /* CONFIG_I8259 */ +#endif + +#ifdef CONFIG_IRQ_CPU_RM7K +#ifndef RM7K_CPU_IRQ_BASE +#define RM7K_CPU_IRQ_BASE (MIPS_CPU_IRQ_BASE+8) +#endif +#endif + +#ifdef CONFIG_IRQ_CPU_RM9K +#ifndef RM9K_CPU_IRQ_BASE +#define RM9K_CPU_IRQ_BASE (MIPS_CPU_IRQ_BASE+12) +#endif +#endif + +#endif /* CONFIG_IRQ_CPU */ #endif /* __ASM_MACH_GENERIC_IRQ_H */ diff --git a/include/asm-mips/mach-mips/irq.h b/include/asm-mips/mach-mips/irq.h index e994b0c01227..9b9da26683c2 100644 --- a/include/asm-mips/mach-mips/irq.h +++ b/include/asm-mips/mach-mips/irq.h @@ -4,4 +4,6 @@ #define NR_IRQS 256 +#include_next + #endif /* __ASM_MACH_MIPS_IRQ_H */ diff --git a/include/asm-mips/mach-vr41xx/irq.h b/include/asm-mips/mach-vr41xx/irq.h new file mode 100644 index 000000000000..848812296052 --- /dev/null +++ b/include/asm-mips/mach-vr41xx/irq.h @@ -0,0 +1,11 @@ +#ifndef __ASM_MACH_VR41XX_IRQ_H +#define __ASM_MACH_VR41XX_IRQ_H + +#include /* for MIPS_CPU_IRQ_BASE */ +#ifdef CONFIG_NEC_CMBVR4133 +#include /* for I8259A_IRQ_BASE */ +#endif + +#include_next + +#endif /* __ASM_MACH_VR41XX_IRQ_H */ diff --git a/include/asm-mips/mips-boards/atlasint.h b/include/asm-mips/mips-boards/atlasint.h index b15e4ea0b091..76add42e486e 100644 --- a/include/asm-mips/mips-boards/atlasint.h +++ b/include/asm-mips/mips-boards/atlasint.h @@ -26,10 +26,12 @@ #ifndef _MIPS_ATLASINT_H #define _MIPS_ATLASINT_H +#include + /* * Interrupts 0..7 are used for Atlas CPU interrupts (nonEIC mode) */ -#define MIPSCPU_INT_BASE 0 +#define MIPSCPU_INT_BASE MIPS_CPU_IRQ_BASE /* CPU interrupt offsets */ #define MIPSCPU_INT_SW0 0 diff --git a/include/asm-mips/mips-boards/maltaint.h b/include/asm-mips/mips-boards/maltaint.h index da6cc2fbbc78..9180d6466113 100644 --- a/include/asm-mips/mips-boards/maltaint.h +++ b/include/asm-mips/mips-boards/maltaint.h @@ -25,6 +25,8 @@ #ifndef _MIPS_MALTAINT_H #define _MIPS_MALTAINT_H +#include + /* * Interrupts 0..15 are used for Malta ISA compatible interrupts */ @@ -33,7 +35,7 @@ /* * Interrupts 16..23 are used for Malta CPU interrupts (nonEIC mode) */ -#define MIPSCPU_INT_BASE 16 +#define MIPSCPU_INT_BASE MIPS_CPU_IRQ_BASE /* CPU interrupt offsets */ #define MIPSCPU_INT_SW0 0 diff --git a/include/asm-mips/mips-boards/prom.h b/include/asm-mips/mips-boards/prom.h index 4168c7fcd43e..7bf6f5f6ab9c 100644 --- a/include/asm-mips/mips-boards/prom.h +++ b/include/asm-mips/mips-boards/prom.h @@ -33,7 +33,6 @@ extern void prom_printf(char *fmt, ...); extern void prom_init_cmdline(void); extern void prom_meminit(void); extern void prom_fixup_mem_map(unsigned long start_mem, unsigned long end_mem); -extern unsigned long prom_free_prom_memory (void); extern void mips_display_message(const char *str); extern void mips_display_word(unsigned int num); extern int get_ethernet_addr(char *ethernet_addr); diff --git a/include/asm-mips/mips-boards/seadint.h b/include/asm-mips/mips-boards/seadint.h index 365c2a3c64f5..4f6a3933699d 100644 --- a/include/asm-mips/mips-boards/seadint.h +++ b/include/asm-mips/mips-boards/seadint.h @@ -20,10 +20,12 @@ #ifndef _MIPS_SEADINT_H #define _MIPS_SEADINT_H +#include + /* * Interrupts 0..7 are used for SEAD CPU interrupts */ -#define MIPSCPU_INT_BASE 0 +#define MIPSCPU_INT_BASE MIPS_CPU_IRQ_BASE #define MIPSCPU_INT_UART0 2 #define MIPSCPU_INT_UART1 3 diff --git a/include/asm-mips/mips-boards/simint.h b/include/asm-mips/mips-boards/simint.h index 4952e0b3bf11..54f2fe621d69 100644 --- a/include/asm-mips/mips-boards/simint.h +++ b/include/asm-mips/mips-boards/simint.h @@ -17,10 +17,11 @@ #ifndef _MIPS_SIMINT_H #define _MIPS_SIMINT_H +#include #define SIM_INT_BASE 0 #define MIPSCPU_INT_MB0 2 -#define MIPSCPU_INT_BASE 16 +#define MIPSCPU_INT_BASE MIPS_CPU_IRQ_BASE #define MIPS_CPU_TIMER_IRQ 7 diff --git a/include/asm-mips/mipsmtregs.h b/include/asm-mips/mipsmtregs.h index 3e9468f424f4..294bca12cd3f 100644 --- a/include/asm-mips/mipsmtregs.h +++ b/include/asm-mips/mipsmtregs.h @@ -165,8 +165,6 @@ #ifndef __ASSEMBLY__ -extern void mips_mt_regdump(unsigned long previous_mvpcontrol_value); - static inline unsigned int dvpe(void) { int res = 0; diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index 2f9e1a9ec51f..d3fbd83ff545 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h @@ -34,6 +34,20 @@ #ifndef __ASSEMBLY__ +/* + * This gives the physical RAM offset. + */ +#ifndef PHYS_OFFSET +#define PHYS_OFFSET 0UL +#endif + +/* + * It's normally defined only for FLATMEM config but it's + * used in our early mem init code for all memory models. + * So always define it. + */ +#define ARCH_PFN_OFFSET PFN_UP(PHYS_OFFSET) + #include #include @@ -132,20 +146,23 @@ typedef struct { unsigned long pgprot; } pgprot_t; /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +/* + * __pa()/__va() should be used only during mem init. + */ #if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64) #define __pa_page_offset(x) ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0) #else #define __pa_page_offset(x) PAGE_OFFSET #endif -#define __pa(x) ((unsigned long)(x) - __pa_page_offset(x)) -#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x),0)) -#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET)) +#define __pa(x) ((unsigned long)(x) - __pa_page_offset(x) + PHYS_OFFSET) +#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET)) +#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x),0)) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) #ifdef CONFIG_FLATMEM -#define pfn_valid(pfn) ((pfn) < max_mapnr) +#define pfn_valid(pfn) ((pfn) >= ARCH_PFN_OFFSET && (pfn) < max_mapnr) #elif defined(CONFIG_SPARSEMEM) diff --git a/include/asm-mips/rtlx.h b/include/asm-mips/rtlx.h index 76cd51c6be39..59162f74a798 100644 --- a/include/asm-mips/rtlx.h +++ b/include/asm-mips/rtlx.h @@ -6,9 +6,10 @@ #ifndef __ASM_RTLX_H #define __ASM_RTLX_H_ +#include + #define LX_NODE_BASE 10 -#define MIPSCPU_INT_BASE 16 #define MIPS_CPU_RTLX_IRQ 0 #define RTLX_VERSION 2 diff --git a/include/asm-mips/sections.h b/include/asm-mips/sections.h index f7016278b266..b7e37262c246 100644 --- a/include/asm-mips/sections.h +++ b/include/asm-mips/sections.h @@ -3,6 +3,4 @@ #include -extern char _fdata; - #endif /* _ASM_SECTIONS_H */ diff --git a/include/asm-mips/sgi/ip22.h b/include/asm-mips/sgi/ip22.h index bbfc05c3cab9..6592f3bd1999 100644 --- a/include/asm-mips/sgi/ip22.h +++ b/include/asm-mips/sgi/ip22.h @@ -21,15 +21,16 @@ * HAL2 driver). This will prevent many complications, trust me ;-) */ +#include #include #define SGINT_EISA 0 /* 16 EISA irq levels (Indigo2) */ -#define SGINT_CPU 16 /* MIPS CPU define 8 interrupt sources */ -#define SGINT_LOCAL0 24 /* 8 local0 irq levels */ -#define SGINT_LOCAL1 32 /* 8 local1 irq levels */ -#define SGINT_LOCAL2 40 /* 8 local2 vectored irq levels */ -#define SGINT_LOCAL3 48 /* 8 local3 vectored irq levels */ -#define SGINT_END 56 /* End of 'spaces' */ +#define SGINT_CPU MIPS_CPU_IRQ_BASE /* MIPS CPU define 8 interrupt sources */ +#define SGINT_LOCAL0 (SGINT_CPU+8) /* 8 local0 irq levels */ +#define SGINT_LOCAL1 (SGINT_CPU+16) /* 8 local1 irq levels */ +#define SGINT_LOCAL2 (SGINT_CPU+24) /* 8 local2 vectored irq levels */ +#define SGINT_LOCAL3 (SGINT_CPU+32) /* 8 local3 vectored irq levels */ +#define SGINT_END (SGINT_CPU+40) /* End of 'spaces' */ /* * Individual interrupt definitions for the Indy and Indigo2 diff --git a/include/asm-mips/smtc_ipi.h b/include/asm-mips/smtc_ipi.h index f22c3e2f993a..55f3419f6546 100644 --- a/include/asm-mips/smtc_ipi.h +++ b/include/asm-mips/smtc_ipi.h @@ -44,9 +44,6 @@ struct smtc_ipi_q { int depth; }; -extern struct smtc_ipi_q IPIQ[NR_CPUS]; -extern struct smtc_ipi_q freeIPIq; - static inline void smtc_ipi_nq(struct smtc_ipi_q *q, struct smtc_ipi *p) { long flags; diff --git a/include/asm-mips/uaccess.h b/include/asm-mips/uaccess.h index 1cdd4eeb2f73..c12ebc53ef31 100644 --- a/include/asm-mips/uaccess.h +++ b/include/asm-mips/uaccess.h @@ -488,7 +488,8 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n); }) /* - * __copy_from_user: - Copy a block of data from user space, with less checking. * @to: Destination address, in kernel space. + * __copy_from_user: - Copy a block of data from user space, with less checking. + * @to: Destination address, in kernel space. * @from: Source address, in user space. * @n: Number of bytes to copy. * diff --git a/include/asm-mips/vr41xx/cmbvr4133.h b/include/asm-mips/vr41xx/cmbvr4133.h index 9490ade58b46..42300037d593 100644 --- a/include/asm-mips/vr41xx/cmbvr4133.h +++ b/include/asm-mips/vr41xx/cmbvr4133.h @@ -35,8 +35,8 @@ #define CMBVR41XX_INTD_IRQ GIU_IRQ(CMBVR41XX_INTD_PIN) #define CMBVR41XX_INTE_IRQ GIU_IRQ(CMBVR41XX_INTE_PIN) -#define I8259_IRQ_BASE 72 -#define I8259_IRQ(x) (I8259_IRQ_BASE + (x)) +#define I8259A_IRQ_BASE 72 +#define I8259_IRQ(x) (I8259A_IRQ_BASE + (x)) #define TIMER_IRQ I8259_IRQ(0) #define KEYBOARD_IRQ I8259_IRQ(1) #define I8259_SLAVE_IRQ I8259_IRQ(2) @@ -52,6 +52,5 @@ #define AUX_IRQ I8259_IRQ(12) #define IDE_PRIMARY_IRQ I8259_IRQ(14) #define IDE_SECONDARY_IRQ I8259_IRQ(15) -#define I8259_IRQ_LAST IDE_SECONDARY_IRQ #endif /* __NEC_CMBVR4133_H */ diff --git a/include/asm-s390/compat.h b/include/asm-s390/compat.h index 356a0b183539..296f4f1a20e1 100644 --- a/include/asm-s390/compat.h +++ b/include/asm-s390/compat.h @@ -6,6 +6,34 @@ #include #include +#define PSW32_MASK_PER 0x40000000UL +#define PSW32_MASK_DAT 0x04000000UL +#define PSW32_MASK_IO 0x02000000UL +#define PSW32_MASK_EXT 0x01000000UL +#define PSW32_MASK_KEY 0x00F00000UL +#define PSW32_MASK_MCHECK 0x00040000UL +#define PSW32_MASK_WAIT 0x00020000UL +#define PSW32_MASK_PSTATE 0x00010000UL +#define PSW32_MASK_ASC 0x0000C000UL +#define PSW32_MASK_CC 0x00003000UL +#define PSW32_MASK_PM 0x00000f00UL + +#define PSW32_ADDR_AMODE31 0x80000000UL +#define PSW32_ADDR_INSN 0x7FFFFFFFUL + +#define PSW32_BASE_BITS 0x00080000UL + +#define PSW32_ASC_PRIMARY 0x00000000UL +#define PSW32_ASC_ACCREG 0x00004000UL +#define PSW32_ASC_SECONDARY 0x00008000UL +#define PSW32_ASC_HOME 0x0000C000UL + +#define PSW32_MASK_MERGE(CURRENT,NEW) \ + (((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \ + ((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM))) + +extern long psw32_user_bits; + #define COMPAT_USER_HZ 100 typedef u32 compat_size_t; diff --git a/include/asm-s390/etr.h b/include/asm-s390/etr.h new file mode 100644 index 000000000000..b498f19bb9a7 --- /dev/null +++ b/include/asm-s390/etr.h @@ -0,0 +1,219 @@ +/* + * include/asm-s390/etr.h + * + * Copyright IBM Corp. 2006 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + */ +#ifndef __S390_ETR_H +#define __S390_ETR_H + +/* ETR attachment control register */ +struct etr_eacr { + unsigned int e0 : 1; /* port 0 stepping control */ + unsigned int e1 : 1; /* port 1 stepping control */ + unsigned int _pad0 : 5; /* must be 00100 */ + unsigned int dp : 1; /* data port control */ + unsigned int p0 : 1; /* port 0 change recognition control */ + unsigned int p1 : 1; /* port 1 change recognition control */ + unsigned int _pad1 : 3; /* must be 000 */ + unsigned int ea : 1; /* ETR alert control */ + unsigned int es : 1; /* ETR sync check control */ + unsigned int sl : 1; /* switch to local control */ +} __attribute__ ((packed)); + +/* Port state returned by steai */ +enum etr_psc { + etr_psc_operational = 0, + etr_psc_semi_operational = 1, + etr_psc_protocol_error = 4, + etr_psc_no_symbols = 8, + etr_psc_no_signal = 12, + etr_psc_pps_mode = 13 +}; + +/* Logical port state returned by stetr */ +enum etr_lpsc { + etr_lpsc_operational_step = 0, + etr_lpsc_operational_alt = 1, + etr_lpsc_semi_operational = 2, + etr_lpsc_protocol_error = 4, + etr_lpsc_no_symbol_sync = 8, + etr_lpsc_no_signal = 12, + etr_lpsc_pps_mode = 13 +}; + +/* ETR status words */ +struct etr_esw { + struct etr_eacr eacr; /* attachment control register */ + unsigned int y : 1; /* stepping mode */ + unsigned int _pad0 : 5; /* must be 00000 */ + unsigned int p : 1; /* stepping port number */ + unsigned int q : 1; /* data port number */ + unsigned int psc0 : 4; /* port 0 state code */ + unsigned int psc1 : 4; /* port 1 state code */ +} __attribute__ ((packed)); + +/* Second level data register status word */ +struct etr_slsw { + unsigned int vv1 : 1; /* copy of validity bit data frame 1 */ + unsigned int vv2 : 1; /* copy of validity bit data frame 2 */ + unsigned int vv3 : 1; /* copy of validity bit data frame 3 */ + unsigned int vv4 : 1; /* copy of validity bit data frame 4 */ + unsigned int _pad0 : 19; /* must by all zeroes */ + unsigned int n : 1; /* EAF port number */ + unsigned int v1 : 1; /* validity bit ETR data frame 1 */ + unsigned int v2 : 1; /* validity bit ETR data frame 2 */ + unsigned int v3 : 1; /* validity bit ETR data frame 3 */ + unsigned int v4 : 1; /* validity bit ETR data frame 4 */ + unsigned int _pad1 : 4; /* must be 0000 */ +} __attribute__ ((packed)); + +/* ETR data frames */ +struct etr_edf1 { + unsigned int u : 1; /* untuned bit */ + unsigned int _pad0 : 1; /* must be 0 */ + unsigned int r : 1; /* service request bit */ + unsigned int _pad1 : 4; /* must be 0000 */ + unsigned int a : 1; /* time adjustment bit */ + unsigned int net_id : 8; /* ETR network id */ + unsigned int etr_id : 8; /* id of ETR which sends data frames */ + unsigned int etr_pn : 8; /* port number of ETR output port */ +} __attribute__ ((packed)); + +struct etr_edf2 { + unsigned int etv : 32; /* Upper 32 bits of TOD. */ +} __attribute__ ((packed)); + +struct etr_edf3 { + unsigned int rc : 8; /* failure reason code */ + unsigned int _pad0 : 3; /* must be 000 */ + unsigned int c : 1; /* ETR coupled bit */ + unsigned int tc : 4; /* ETR type code */ + unsigned int blto : 8; /* biased local time offset */ + /* (blto - 128) * 15 = minutes */ + unsigned int buo : 8; /* biased utc offset */ + /* (buo - 128) = leap seconds */ +} __attribute__ ((packed)); + +struct etr_edf4 { + unsigned int ed : 8; /* ETS device dependent data */ + unsigned int _pad0 : 1; /* must be 0 */ + unsigned int buc : 5; /* biased ut1 correction */ + /* (buc - 16) * 0.1 seconds */ + unsigned int em : 6; /* ETS error magnitude */ + unsigned int dc : 6; /* ETS drift code */ + unsigned int sc : 6; /* ETS steering code */ +} __attribute__ ((packed)); + +/* + * ETR attachment information block, two formats + * format 1 has 4 reserved words with a size of 64 bytes + * format 2 has 16 reserved words with a size of 96 bytes + */ +struct etr_aib { + struct etr_esw esw; + struct etr_slsw slsw; + unsigned long long tsp; + struct etr_edf1 edf1; + struct etr_edf2 edf2; + struct etr_edf3 edf3; + struct etr_edf4 edf4; + unsigned int reserved[16]; +} __attribute__ ((packed,aligned(8))); + +/* ETR interruption parameter */ +struct etr_interruption_parameter { + unsigned int _pad0 : 8; + unsigned int pc0 : 1; /* port 0 state change */ + unsigned int pc1 : 1; /* port 1 state change */ + unsigned int _pad1 : 3; + unsigned int eai : 1; /* ETR alert indication */ + unsigned int _pad2 : 18; +} __attribute__ ((packed)); + +/* Query TOD offset result */ +struct etr_ptff_qto { + unsigned long long physical_clock; + unsigned long long tod_offset; + unsigned long long logical_tod_offset; + unsigned long long tod_epoch_difference; +} __attribute__ ((packed)); + +/* Inline assembly helper functions */ +static inline int etr_setr(struct etr_eacr *ctrl) +{ + int rc = -ENOSYS; + + asm volatile( + " .insn s,0xb2160000,0(%2)\n" + "0: la %0,0\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (rc) : "m" (*ctrl), "a" (ctrl)); + return rc; +} + +/* Stores a format 1 aib with 64 bytes */ +static inline int etr_stetr(struct etr_aib *aib) +{ + int rc = -ENOSYS; + + asm volatile( + " .insn s,0xb2170000,0(%2)\n" + "0: la %0,0\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (rc) : "m" (*aib), "a" (aib)); + return rc; +} + +/* Stores a format 2 aib with 96 bytes for specified port */ +static inline int etr_steai(struct etr_aib *aib, unsigned int func) +{ + register unsigned int reg0 asm("0") = func; + int rc = -ENOSYS; + + asm volatile( + " .insn s,0xb2b30000,0(%2)\n" + "0: la %0,0\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (rc) : "m" (*aib), "a" (aib), "d" (reg0)); + return rc; +} + +/* Function codes for the steai instruction. */ +#define ETR_STEAI_STEPPING_PORT 0x10 +#define ETR_STEAI_ALTERNATE_PORT 0x11 +#define ETR_STEAI_PORT_0 0x12 +#define ETR_STEAI_PORT_1 0x13 + +static inline int etr_ptff(void *ptff_block, unsigned int func) +{ + register unsigned int reg0 asm("0") = func; + register unsigned long reg1 asm("1") = (unsigned long) ptff_block; + int rc = -ENOSYS; + + asm volatile( + " .word 0x0104\n" + " ipm %0\n" + " srl %0,28\n" + : "=d" (rc), "=m" (ptff_block) + : "d" (reg0), "d" (reg1), "m" (ptff_block) : "cc"); + return rc; +} + +/* Function codes for the ptff instruction. */ +#define ETR_PTFF_QAF 0x00 /* query available functions */ +#define ETR_PTFF_QTO 0x01 /* query tod offset */ +#define ETR_PTFF_QSI 0x02 /* query steering information */ +#define ETR_PTFF_ATO 0x40 /* adjust tod offset */ +#define ETR_PTFF_STO 0x41 /* set tod offset */ +#define ETR_PTFF_SFS 0x42 /* set fine steering rate */ +#define ETR_PTFF_SGS 0x43 /* set gross steering rate */ + +/* Functions needed by the machine check handler */ +extern void etr_switch_to_local(void); +extern void etr_sync_check(void); + +#endif /* __S390_ETR_H */ diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h index c2f6a8782d31..31beb18cb3d1 100644 --- a/include/asm-s390/hardirq.h +++ b/include/asm-s390/hardirq.h @@ -32,6 +32,6 @@ typedef struct { #define HARDIRQ_BITS 8 -extern void account_ticks(void); +extern void account_ticks(u64 time); #endif /* __ASM_HARDIRQ_H */ diff --git a/include/asm-s390/io.h b/include/asm-s390/io.h index efb7de9c1c6b..a4c2d550dad4 100644 --- a/include/asm-s390/io.h +++ b/include/asm-s390/io.h @@ -28,11 +28,7 @@ static inline unsigned long virt_to_phys(volatile void * address) { unsigned long real_address; asm volatile( -#ifndef __s390x__ " lra %0,0(%1)\n" -#else /* __s390x__ */ - " lrag %0,0(%1)\n" -#endif /* __s390x__ */ " jz 0f\n" " la %0,0\n" "0:" diff --git a/include/asm-s390/kdebug.h b/include/asm-s390/kdebug.h index 40cc68025e01..1b50f89819a4 100644 --- a/include/asm-s390/kdebug.h +++ b/include/asm-s390/kdebug.h @@ -26,7 +26,6 @@ extern int register_page_fault_notifier(struct notifier_block *); extern int unregister_page_fault_notifier(struct notifier_block *); extern struct atomic_notifier_head s390die_chain; - enum die_val { DIE_OOPS = 1, DIE_BPT, @@ -56,4 +55,6 @@ static inline int notify_die(enum die_val val, const char *str, return atomic_notifier_call_chain(&s390die_chain, val, &args); } +extern void die(const char *, struct pt_regs *, long); + #endif diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h index 74f7389bd3ee..4a31d0a7ee83 100644 --- a/include/asm-s390/lowcore.h +++ b/include/asm-s390/lowcore.h @@ -220,7 +220,8 @@ struct _lowcore __u32 kernel_asce; /* 0xc4c */ __u32 user_asce; /* 0xc50 */ __u32 panic_stack; /* 0xc54 */ - __u8 pad10[0xc60-0xc58]; /* 0xc58 */ + __u32 user_exec_asce; /* 0xc58 */ + __u8 pad10[0xc60-0xc5c]; /* 0xc5c */ /* entry.S sensitive area start */ struct cpuinfo_S390 cpu_data; /* 0xc60 */ __u32 ipl_device; /* 0xc7c */ @@ -310,7 +311,8 @@ struct _lowcore __u64 kernel_asce; /* 0xd58 */ __u64 user_asce; /* 0xd60 */ __u64 panic_stack; /* 0xd68 */ - __u8 pad10[0xd80-0xd70]; /* 0xd70 */ + __u64 user_exec_asce; /* 0xd70 */ + __u8 pad10[0xd80-0xd78]; /* 0xd78 */ /* entry.S sensitive area start */ struct cpuinfo_S390 cpu_data; /* 0xd80 */ __u32 ipl_device; /* 0xdb8 */ diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h index bcf24a873874..1d21da220d49 100644 --- a/include/asm-s390/mmu_context.h +++ b/include/asm-s390/mmu_context.h @@ -9,6 +9,7 @@ #ifndef __S390_MMU_CONTEXT_H #define __S390_MMU_CONTEXT_H +#include /* * get a new mmu context.. S390 don't know about contexts. */ @@ -16,29 +17,44 @@ #define destroy_context(mm) do { } while (0) +#ifndef __s390x__ +#define LCTL_OPCODE "lctl" +#define PGTABLE_BITS (_SEGMENT_TABLE|USER_STD_MASK) +#else +#define LCTL_OPCODE "lctlg" +#define PGTABLE_BITS (_REGION_TABLE|USER_STD_MASK) +#endif + static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { } static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk) + struct task_struct *tsk) { - if (prev != next) { -#ifndef __s390x__ - S390_lowcore.user_asce = (__pa(next->pgd)&PAGE_MASK) | - (_SEGMENT_TABLE|USER_STD_MASK); - /* Load home space page table origin. */ - asm volatile("lctl 13,13,%0" - : : "m" (S390_lowcore.user_asce) ); -#else /* __s390x__ */ - S390_lowcore.user_asce = (__pa(next->pgd) & PAGE_MASK) | - (_REGION_TABLE|USER_STD_MASK); - /* Load home space page table origin. */ - asm volatile("lctlg 13,13,%0" - : : "m" (S390_lowcore.user_asce) ); -#endif /* __s390x__ */ - } + pgd_t *shadow_pgd = get_shadow_pgd(next->pgd); + + if (prev != next) { + S390_lowcore.user_asce = (__pa(next->pgd) & PAGE_MASK) | + PGTABLE_BITS; + if (shadow_pgd) { + /* Load primary/secondary space page table origin. */ + S390_lowcore.user_exec_asce = + (__pa(shadow_pgd) & PAGE_MASK) | PGTABLE_BITS; + asm volatile(LCTL_OPCODE" 1,1,%0\n" + LCTL_OPCODE" 7,7,%1" + : : "m" (S390_lowcore.user_exec_asce), + "m" (S390_lowcore.user_asce) ); + } else if (switch_amode) { + /* Load primary space page table origin. */ + asm volatile(LCTL_OPCODE" 1,1,%0" + : : "m" (S390_lowcore.user_asce) ); + } else + /* Load home space page table origin. */ + asm volatile(LCTL_OPCODE" 13,13,%0" + : : "m" (S390_lowcore.user_asce) ); + } cpu_set(smp_processor_id(), next->cpu_vm_mask); } @@ -51,4 +67,4 @@ static inline void activate_mm(struct mm_struct *prev, set_fs(current->thread.mm_segment); } -#endif +#endif /* __S390_MMU_CONTEXT_H */ diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h index 0707a7e2fc16..56c8a6c80e2e 100644 --- a/include/asm-s390/pgalloc.h +++ b/include/asm-s390/pgalloc.h @@ -47,6 +47,17 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm) if (!pgd) return NULL; + if (s390_noexec) { + pgd_t *shadow_pgd = (pgd_t *) + __get_free_pages(GFP_KERNEL, PGD_ALLOC_ORDER); + struct page *page = virt_to_page(pgd); + + if (!shadow_pgd) { + free_pages((unsigned long) pgd, PGD_ALLOC_ORDER); + return NULL; + } + page->lru.next = (void *) shadow_pgd; + } for (i = 0; i < PTRS_PER_PGD; i++) #ifndef __s390x__ pmd_clear(pmd_offset(pgd + i, i*PGDIR_SIZE)); @@ -58,6 +69,10 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm) static inline void pgd_free(pgd_t *pgd) { + pgd_t *shadow_pgd = get_shadow_pgd(pgd); + + if (shadow_pgd) + free_pages((unsigned long) shadow_pgd, PGD_ALLOC_ORDER); free_pages((unsigned long) pgd, PGD_ALLOC_ORDER); } @@ -71,6 +86,7 @@ static inline void pgd_free(pgd_t *pgd) #define pmd_free(x) do { } while (0) #define __pmd_free_tlb(tlb,x) do { } while (0) #define pgd_populate(mm, pmd, pte) BUG() +#define pgd_populate_kernel(mm, pmd, pte) BUG() #else /* __s390x__ */ static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) { @@ -79,6 +95,17 @@ static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) if (!pmd) return NULL; + if (s390_noexec) { + pmd_t *shadow_pmd = (pmd_t *) + __get_free_pages(GFP_KERNEL, PMD_ALLOC_ORDER); + struct page *page = virt_to_page(pmd); + + if (!shadow_pmd) { + free_pages((unsigned long) pmd, PMD_ALLOC_ORDER); + return NULL; + } + page->lru.next = (void *) shadow_pmd; + } for (i=0; i < PTRS_PER_PMD; i++) pmd_clear(pmd + i); return pmd; @@ -86,6 +113,10 @@ static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) static inline void pmd_free (pmd_t *pmd) { + pmd_t *shadow_pmd = get_shadow_pmd(pmd); + + if (shadow_pmd) + free_pages((unsigned long) shadow_pmd, PMD_ALLOC_ORDER); free_pages((unsigned long) pmd, PMD_ALLOC_ORDER); } @@ -95,11 +126,22 @@ static inline void pmd_free (pmd_t *pmd) pmd_free(pmd); \ } while (0) -static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) +static inline void +pgd_populate_kernel(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) { pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd); } +static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd) +{ + pgd_t *shadow_pgd = get_shadow_pgd(pgd); + pmd_t *shadow_pmd = get_shadow_pmd(pmd); + + if (shadow_pgd && shadow_pmd) + pgd_populate_kernel(mm, shadow_pgd, shadow_pmd); + pgd_populate_kernel(mm, pgd, pmd); +} + #endif /* __s390x__ */ static inline void @@ -119,7 +161,13 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte) static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page) { - pmd_populate_kernel(mm, pmd, (pte_t *)page_to_phys(page)); + pte_t *pte = (pte_t *)page_to_phys(page); + pmd_t *shadow_pmd = get_shadow_pmd(pmd); + pte_t *shadow_pte = get_shadow_pte(pte); + + pmd_populate_kernel(mm, pmd, pte); + if (shadow_pmd && shadow_pte) + pmd_populate_kernel(mm, shadow_pmd, shadow_pte); } /* @@ -133,6 +181,17 @@ pte_alloc_one_kernel(struct mm_struct *mm, unsigned long vmaddr) if (!pte) return NULL; + if (s390_noexec) { + pte_t *shadow_pte = (pte_t *) + __get_free_page(GFP_KERNEL|__GFP_REPEAT); + struct page *page = virt_to_page(pte); + + if (!shadow_pte) { + free_page((unsigned long) pte); + return NULL; + } + page->lru.next = (void *) shadow_pte; + } for (i=0; i < PTRS_PER_PTE; i++) { pte_clear(mm, vmaddr, pte + i); vmaddr += PAGE_SIZE; @@ -151,14 +210,30 @@ pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr) static inline void pte_free_kernel(pte_t *pte) { - free_page((unsigned long) pte); + pte_t *shadow_pte = get_shadow_pte(pte); + + if (shadow_pte) + free_page((unsigned long) shadow_pte); + free_page((unsigned long) pte); } static inline void pte_free(struct page *pte) { - __free_page(pte); + struct page *shadow_page = get_shadow_page(pte); + + if (shadow_page) + __free_page(shadow_page); + __free_page(pte); } -#define __pte_free_tlb(tlb,pte) tlb_remove_page(tlb,pte) +#define __pte_free_tlb(tlb, pte) \ +({ \ + struct mmu_gather *__tlb = (tlb); \ + struct page *__pte = (pte); \ + struct page *shadow_page = get_shadow_page(__pte); \ + if (shadow_page) \ + tlb_remove_page(__tlb, shadow_page); \ + tlb_remove_page(__tlb, __pte); \ +}) #endif /* _S390_PGALLOC_H */ diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index ae61aca5d483..13c16546eff5 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -40,6 +40,7 @@ struct mm_struct; extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); extern void paging_init(void); +extern void vmem_map_init(void); /* * The S390 doesn't have any external MMU info: the kernel page @@ -223,6 +224,8 @@ extern unsigned long vmalloc_end; #define _PAGE_TYPE_FILE 0x601 /* bit 0x002 is used for offset !! */ #define _PAGE_TYPE_RO 0x200 #define _PAGE_TYPE_RW 0x000 +#define _PAGE_TYPE_EX_RO 0x202 +#define _PAGE_TYPE_EX_RW 0x002 /* * PTE type bits are rather complicated. handle_pte_fault uses pte_present, @@ -243,11 +246,13 @@ extern unsigned long vmalloc_end; * _PAGE_TYPE_FILE 11?1 -> 11?1 * _PAGE_TYPE_RO 0100 -> 1100 * _PAGE_TYPE_RW 0000 -> 1000 + * _PAGE_TYPE_EX_RO 0110 -> 1110 + * _PAGE_TYPE_EX_RW 0010 -> 1010 * - * pte_none is true for bits combinations 1000, 1100 + * pte_none is true for bits combinations 1000, 1010, 1100, 1110 * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001 * pte_file is true for bits combinations 1101, 1111 - * swap pte is 1011 and 0001, 0011, 0101, 0111, 1010 and 1110 are invalid. + * swap pte is 1011 and 0001, 0011, 0101, 0111 are invalid. */ #ifndef __s390x__ @@ -312,33 +317,100 @@ extern unsigned long vmalloc_end; #define PAGE_NONE __pgprot(_PAGE_TYPE_NONE) #define PAGE_RO __pgprot(_PAGE_TYPE_RO) #define PAGE_RW __pgprot(_PAGE_TYPE_RW) +#define PAGE_EX_RO __pgprot(_PAGE_TYPE_EX_RO) +#define PAGE_EX_RW __pgprot(_PAGE_TYPE_EX_RW) #define PAGE_KERNEL PAGE_RW #define PAGE_COPY PAGE_RO /* - * The S390 can't do page protection for execute, and considers that the - * same are read. Also, write permissions imply read permissions. This is - * the closest we can get.. + * Dependent on the EXEC_PROTECT option s390 can do execute protection. + * Write permission always implies read permission. In theory with a + * primary/secondary page table execute only can be implemented but + * it would cost an additional bit in the pte to distinguish all the + * different pte types. To avoid that execute permission currently + * implies read permission as well. */ /*xwr*/ #define __P000 PAGE_NONE #define __P001 PAGE_RO #define __P010 PAGE_RO #define __P011 PAGE_RO -#define __P100 PAGE_RO -#define __P101 PAGE_RO -#define __P110 PAGE_RO -#define __P111 PAGE_RO +#define __P100 PAGE_EX_RO +#define __P101 PAGE_EX_RO +#define __P110 PAGE_EX_RO +#define __P111 PAGE_EX_RO #define __S000 PAGE_NONE #define __S001 PAGE_RO #define __S010 PAGE_RW #define __S011 PAGE_RW -#define __S100 PAGE_RO -#define __S101 PAGE_RO -#define __S110 PAGE_RW -#define __S111 PAGE_RW +#define __S100 PAGE_EX_RO +#define __S101 PAGE_EX_RO +#define __S110 PAGE_EX_RW +#define __S111 PAGE_EX_RW + +#ifndef __s390x__ +# define PMD_SHADOW_SHIFT 1 +# define PGD_SHADOW_SHIFT 1 +#else /* __s390x__ */ +# define PMD_SHADOW_SHIFT 2 +# define PGD_SHADOW_SHIFT 2 +#endif /* __s390x__ */ + +static inline struct page *get_shadow_page(struct page *page) +{ + if (s390_noexec && !list_empty(&page->lru)) + return virt_to_page(page->lru.next); + return NULL; +} + +static inline pte_t *get_shadow_pte(pte_t *ptep) +{ + unsigned long pteptr = (unsigned long) (ptep); + + if (s390_noexec) { + unsigned long offset = pteptr & (PAGE_SIZE - 1); + void *addr = (void *) (pteptr ^ offset); + struct page *page = virt_to_page(addr); + if (!list_empty(&page->lru)) + return (pte_t *) ((unsigned long) page->lru.next | + offset); + } + return NULL; +} + +static inline pmd_t *get_shadow_pmd(pmd_t *pmdp) +{ + unsigned long pmdptr = (unsigned long) (pmdp); + + if (s390_noexec) { + unsigned long offset = pmdptr & + ((PAGE_SIZE << PMD_SHADOW_SHIFT) - 1); + void *addr = (void *) (pmdptr ^ offset); + struct page *page = virt_to_page(addr); + if (!list_empty(&page->lru)) + return (pmd_t *) ((unsigned long) page->lru.next | + offset); + } + return NULL; +} + +static inline pgd_t *get_shadow_pgd(pgd_t *pgdp) +{ + unsigned long pgdptr = (unsigned long) (pgdp); + + if (s390_noexec) { + unsigned long offset = pgdptr & + ((PAGE_SIZE << PGD_SHADOW_SHIFT) - 1); + void *addr = (void *) (pgdptr ^ offset); + struct page *page = virt_to_page(addr); + if (!list_empty(&page->lru)) + return (pgd_t *) ((unsigned long) page->lru.next | + offset); + } + return NULL; +} /* * Certain architectures need to do special things when PTEs @@ -347,7 +419,16 @@ extern unsigned long vmalloc_end; */ static inline void set_pte(pte_t *pteptr, pte_t pteval) { + pte_t *shadow_pte = get_shadow_pte(pteptr); + *pteptr = pteval; + if (shadow_pte) { + if (!(pte_val(pteval) & _PAGE_INVALID) && + (pte_val(pteval) & _PAGE_SWX)) + pte_val(*shadow_pte) = pte_val(pteval) | _PAGE_RO; + else + pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY; + } } #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) @@ -465,7 +546,7 @@ static inline int pte_read(pte_t pte) static inline void pgd_clear(pgd_t * pgdp) { } -static inline void pmd_clear(pmd_t * pmdp) +static inline void pmd_clear_kernel(pmd_t * pmdp) { pmd_val(pmdp[0]) = _PAGE_TABLE_INV; pmd_val(pmdp[1]) = _PAGE_TABLE_INV; @@ -473,24 +554,55 @@ static inline void pmd_clear(pmd_t * pmdp) pmd_val(pmdp[3]) = _PAGE_TABLE_INV; } +static inline void pmd_clear(pmd_t * pmdp) +{ + pmd_t *shadow_pmd = get_shadow_pmd(pmdp); + + pmd_clear_kernel(pmdp); + if (shadow_pmd) + pmd_clear_kernel(shadow_pmd); +} + #else /* __s390x__ */ -static inline void pgd_clear(pgd_t * pgdp) +static inline void pgd_clear_kernel(pgd_t * pgdp) { pgd_val(*pgdp) = _PGD_ENTRY_INV | _PGD_ENTRY; } -static inline void pmd_clear(pmd_t * pmdp) +static inline void pgd_clear(pgd_t * pgdp) +{ + pgd_t *shadow_pgd = get_shadow_pgd(pgdp); + + pgd_clear_kernel(pgdp); + if (shadow_pgd) + pgd_clear_kernel(shadow_pgd); +} + +static inline void pmd_clear_kernel(pmd_t * pmdp) { pmd_val(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY; pmd_val1(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY; } +static inline void pmd_clear(pmd_t * pmdp) +{ + pmd_t *shadow_pmd = get_shadow_pmd(pmdp); + + pmd_clear_kernel(pmdp); + if (shadow_pmd) + pmd_clear_kernel(shadow_pmd); +} + #endif /* __s390x__ */ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { + pte_t *shadow_pte = get_shadow_pte(ptep); + pte_val(*ptep) = _PAGE_TYPE_EMPTY; + if (shadow_pte) + pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY; } /* @@ -608,8 +720,11 @@ ptep_clear_flush(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) { pte_t pte = *ptep; + pte_t *shadow_pte = get_shadow_pte(ptep); __ptep_ipte(address, ptep); + if (shadow_pte) + __ptep_ipte(address, shadow_pte); return pte; } diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index cbbedc63ba25..4c1b73940351 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h @@ -50,6 +50,7 @@ struct cpuinfo_S390 unsigned long pgtable_cache_sz; }; +extern void s390_adjust_jiffies(void); extern void print_cpu_info(struct cpuinfo_S390 *); /* Lazy FPU handling on uni-processor */ @@ -144,7 +145,8 @@ struct stack_frame { #ifndef __s390x__ #define start_thread(regs, new_psw, new_stackp) do { \ - regs->psw.mask = PSW_USER_BITS; \ + set_fs(USER_DS); \ + regs->psw.mask = psw_user_bits; \ regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ regs->gprs[15] = new_stackp ; \ } while (0) @@ -152,13 +154,15 @@ struct stack_frame { #else /* __s390x__ */ #define start_thread(regs, new_psw, new_stackp) do { \ - regs->psw.mask = PSW_USER_BITS; \ + set_fs(USER_DS); \ + regs->psw.mask = psw_user_bits; \ regs->psw.addr = new_psw; \ regs->gprs[15] = new_stackp; \ } while (0) #define start_thread31(regs, new_psw, new_stackp) do { \ - regs->psw.mask = PSW_USER32_BITS; \ + set_fs(USER_DS); \ + regs->psw.mask = psw_user32_bits; \ regs->psw.addr = new_psw; \ regs->gprs[15] = new_stackp; \ } while (0) @@ -201,9 +205,8 @@ unsigned long get_wchan(struct task_struct *p); static inline void cpu_relax(void) { if (MACHINE_HAS_DIAG44) - asm volatile("diag 0,0,68" : : : "memory"); - else - barrier(); + asm volatile("diag 0,0,68"); + barrier(); } /* @@ -327,6 +330,18 @@ static inline void disabled_wait(unsigned long code) #endif /* __s390x__ */ } +/* + * Basic Machine Check/Program Check Handler. + */ + +extern void s390_base_mcck_handler(void); +extern void s390_base_pgm_handler(void); +extern void s390_base_ext_handler(void); + +extern void (*s390_base_mcck_handler_fn)(void); +extern void (*s390_base_pgm_handler_fn)(void); +extern void (*s390_base_ext_handler_fn)(void); + /* * CPU idle notifier chain. */ diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h index 7b768c5c68a8..fa6ca87080e8 100644 --- a/include/asm-s390/ptrace.h +++ b/include/asm-s390/ptrace.h @@ -266,17 +266,12 @@ typedef struct #define PSW_ASC_SECONDARY 0x0000800000000000UL #define PSW_ASC_HOME 0x0000C00000000000UL -#define PSW_USER32_BITS (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \ - PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \ - PSW_MASK_PSTATE | PSW_DEFAULT_KEY) +extern long psw_user32_bits; #endif /* __s390x__ */ -#define PSW_KERNEL_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | \ - PSW_MASK_MCHECK | PSW_DEFAULT_KEY) -#define PSW_USER_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \ - PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \ - PSW_MASK_PSTATE | PSW_DEFAULT_KEY) +extern long psw_kernel_bits; +extern long psw_user_bits; /* This macro merges a NEW PSW mask specified by the user into the currently active PSW mask CURRENT, modifying only those diff --git a/include/asm-s390/reset.h b/include/asm-s390/reset.h index 532e65a2aafc..f584f4a52581 100644 --- a/include/asm-s390/reset.h +++ b/include/asm-s390/reset.h @@ -18,7 +18,4 @@ struct reset_call { extern void register_reset_call(struct reset_call *reset); extern void unregister_reset_call(struct reset_call *reset); extern void s390_reset_system(void); -extern void (*s390_reset_mcck_handler)(void); -extern void (*s390_reset_pgm_handler)(void); - #endif /* _ASM_S390_RESET_H */ diff --git a/include/asm-s390/sclp.h b/include/asm-s390/sclp.h new file mode 100644 index 000000000000..468b97018405 --- /dev/null +++ b/include/asm-s390/sclp.h @@ -0,0 +1,39 @@ +/* + * include/asm-s390/sclp.h + * + * Copyright IBM Corp. 2007 + * Author(s): Heiko Carstens + */ + +#ifndef _ASM_S390_SCLP_H +#define _ASM_S390_SCLP_H + +#include + +struct sccb_header { + u16 length; + u8 function_code; + u8 control_mask[3]; + u16 response_code; +} __attribute__((packed)); + +#define LOADPARM_LEN 8 + +struct sclp_readinfo_sccb { + struct sccb_header header; /* 0-7 */ + u16 rnmax; /* 8-9 */ + u8 rnsize; /* 10 */ + u8 _reserved0[24 - 11]; /* 11-23 */ + u8 loadparm[LOADPARM_LEN]; /* 24-31 */ + u8 _reserved1[91 - 32]; /* 32-90 */ + u8 flags; /* 91 */ + u8 _reserved2[100 - 92]; /* 92-99 */ + u32 rnsize2; /* 100-103 */ + u64 rnmax2; /* 104-111 */ + u8 _reserved3[4096 - 112]; /* 112-4095 */ +} __attribute__((packed, aligned(4096))); + +extern struct sclp_readinfo_sccb s390_readinfo_sccb; +extern void sclp_readinfo_early(void); + +#endif /* _ASM_S390_SCLP_H */ diff --git a/include/asm-s390/sections.h b/include/asm-s390/sections.h index 3a0b8ffeab7a..1c5a2c4ccdad 100644 --- a/include/asm-s390/sections.h +++ b/include/asm-s390/sections.h @@ -3,4 +3,6 @@ #include +extern char _eshared[]; + #endif diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h index 9574fe80a046..3388bb52597c 100644 --- a/include/asm-s390/setup.h +++ b/include/asm-s390/setup.h @@ -42,6 +42,18 @@ struct mem_chunk { extern struct mem_chunk memory_chunk[]; +#ifdef CONFIG_S390_SWITCH_AMODE +extern unsigned int switch_amode; +#else +#define switch_amode (0) +#endif + +#ifdef CONFIG_S390_EXEC_PROTECT +extern unsigned int s390_noexec; +#else +#define s390_noexec (0) +#endif + /* * Machine features detected in head.S */ @@ -74,6 +86,9 @@ extern unsigned int console_mode; extern unsigned int console_devno; extern unsigned int console_irq; +extern char vmhalt_cmd[]; +extern char vmpoff_cmd[]; + #define CONSOLE_IS_UNDEFINED (console_mode == 0) #define CONSOLE_IS_SCLP (console_mode == 1) #define CONSOLE_IS_3215 (console_mode == 2) @@ -141,13 +156,19 @@ struct ipl_parameter_block { extern u32 ipl_flags; extern u16 ipl_devno; -void do_reipl(void); +extern void do_reipl(void); +extern void ipl_save_parameters(void); enum { IPL_DEVNO_VALID = 1, IPL_PARMBLOCK_VALID = 2, + IPL_NSS_VALID = 4, }; +#define NSS_NAME_SIZE 8 + +extern char kernel_nss_name[]; + #define IPL_PARMBLOCK_START ((struct ipl_parameter_block *) \ IPL_PARMBLOCK_ORIGIN) #define IPL_PARMBLOCK_SIZE (IPL_PARMBLOCK_START->hdr.len) diff --git a/arch/s390/math-emu/sfp-util.h b/include/asm-s390/sfp-util.h similarity index 91% rename from arch/s390/math-emu/sfp-util.h rename to include/asm-s390/sfp-util.h index 5b6ca4570ea4..8cabcd23d976 100644 --- a/arch/s390/math-emu/sfp-util.h +++ b/include/asm-s390/sfp-util.h @@ -52,12 +52,12 @@ }) #define udiv_qrnnd(q, r, n1, n0, d) \ - do { unsigned long __r; \ + do { unsigned int __r; \ (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ (r) = __r; \ } while (0) -extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long, - unsigned long , unsigned long); +extern unsigned long __udiv_qrnnd (unsigned int *, unsigned int, + unsigned int , unsigned int); #define UDIV_NEEDS_NORMALIZATION 0 diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h index 7097c96ed026..b957e4cda464 100644 --- a/include/asm-s390/smp.h +++ b/include/asm-s390/smp.h @@ -31,6 +31,10 @@ typedef struct __u16 cpu; } sigp_info; +extern void machine_restart_smp(char *); +extern void machine_halt_smp(void); +extern void machine_power_off_smp(void); + extern void smp_setup_cpu_possible_map(void); extern int smp_call_function_on(void (*func) (void *info), void *info, int nonatomic, int wait, int cpu); @@ -106,7 +110,7 @@ smp_call_function_on(void (*func) (void *info), void *info, static inline void smp_send_stop(void) { /* Disable all interrupts/machine checks */ - __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK); + __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK); } #define smp_cpu_not_running(cpu) 1 diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index bd0b05ae87d2..bbe137c3ed69 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h @@ -373,8 +373,8 @@ __set_psw_mask(unsigned long mask) __load_psw_mask(mask | (__raw_local_irq_stosm(0x00) & ~(-1UL >> 8))); } -#define local_mcck_enable() __set_psw_mask(PSW_KERNEL_BITS) -#define local_mcck_disable() __set_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK) +#define local_mcck_enable() __set_psw_mask(psw_kernel_bits) +#define local_mcck_disable() __set_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK) #ifdef CONFIG_SMP diff --git a/include/asm-s390/tape390.h b/include/asm-s390/tape390.h index f1d66ba0deef..884fba48f1ff 100644 --- a/include/asm-s390/tape390.h +++ b/include/asm-s390/tape390.h @@ -1,11 +1,11 @@ /************************************************************************* * * tape390.h - * enables user programs to display messages on the tape device + * enables user programs to display messages and control encryption + * on s390 tape devices * - * S390 and zSeries version - * Copyright (C) 2001 IBM Corporation - * Author(s): Despina Papadopoulou + * Copyright IBM Corp. 2001,2006 + * Author(s): Michael Holzheu * *************************************************************************/ @@ -36,4 +36,68 @@ typedef struct display_struct { char message2[8]; } display_struct; +/* + * Tape encryption support + */ + +struct tape390_crypt_info { + char capability; + char status; + char medium_status; +} __attribute__ ((packed)); + + +/* Macros for "capable" field */ +#define TAPE390_CRYPT_SUPPORTED_MASK 0x01 +#define TAPE390_CRYPT_SUPPORTED(x) \ + ((x.capability & TAPE390_CRYPT_SUPPORTED_MASK)) + +/* Macros for "status" field */ +#define TAPE390_CRYPT_ON_MASK 0x01 +#define TAPE390_CRYPT_ON(x) (((x.status) & TAPE390_CRYPT_ON_MASK)) + +/* Macros for "medium status" field */ +#define TAPE390_MEDIUM_LOADED_MASK 0x01 +#define TAPE390_MEDIUM_ENCRYPTED_MASK 0x02 +#define TAPE390_MEDIUM_ENCRYPTED(x) \ + (((x.medium_status) & TAPE390_MEDIUM_ENCRYPTED_MASK)) +#define TAPE390_MEDIUM_LOADED(x) \ + (((x.medium_status) & TAPE390_MEDIUM_LOADED_MASK)) + +/* + * The TAPE390_CRYPT_SET ioctl is used to switch on/off encryption. + * The "encryption_capable" and "tape_status" fields are ignored for this ioctl! + */ +#define TAPE390_CRYPT_SET _IOW('d', 2, struct tape390_crypt_info) + +/* + * The TAPE390_CRYPT_QUERY ioctl is used to query the encryption state. + */ +#define TAPE390_CRYPT_QUERY _IOR('d', 3, struct tape390_crypt_info) + +/* Values for "kekl1/2_type" and "kekl1/2_type_on_tape" fields */ +#define TAPE390_KEKL_TYPE_NONE 0 +#define TAPE390_KEKL_TYPE_LABEL 1 +#define TAPE390_KEKL_TYPE_HASH 2 + +struct tape390_kekl { + unsigned char type; + unsigned char type_on_tape; + char label[65]; +} __attribute__ ((packed)); + +struct tape390_kekl_pair { + struct tape390_kekl kekl[2]; +} __attribute__ ((packed)); + +/* + * The TAPE390_KEKL_SET ioctl is used to set Key Encrypting Key labels. + */ +#define TAPE390_KEKL_SET _IOW('d', 4, struct tape390_kekl_pair) + +/* + * The TAPE390_KEKL_QUERY ioctl is used to query Key Encrypting Key labels. + */ +#define TAPE390_KEKL_QUERY _IOR('d', 5, struct tape390_kekl_pair) + #endif diff --git a/include/asm-s390/timer.h b/include/asm-s390/timer.h index 30e5cbe570f2..adb34860a543 100644 --- a/include/asm-s390/timer.h +++ b/include/asm-s390/timer.h @@ -45,6 +45,9 @@ extern void add_virt_timer_periodic(void *new); extern int mod_virt_timer(struct vtimer_list *timer, __u64 expires); extern int del_virt_timer(struct vtimer_list *timer); +extern void init_cpu_vtimer(void); +extern void vtime_init(void); + #endif /* __KERNEL__ */ #endif /* _ASM_S390_TIMER_H */ diff --git a/include/asm-s390/timex.h b/include/asm-s390/timex.h index 4df4a41029a3..98229db24314 100644 --- a/include/asm-s390/timex.h +++ b/include/asm-s390/timex.h @@ -11,6 +11,41 @@ #ifndef _ASM_S390_TIMEX_H #define _ASM_S390_TIMEX_H +/* Inline functions for clock register access. */ +static inline int set_clock(__u64 time) +{ + int cc; + + asm volatile( + " sck 0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + : "=d" (cc) : "m" (time), "a" (&time) : "cc"); + return cc; +} + +static inline int store_clock(__u64 *time) +{ + int cc; + + asm volatile( + " stck 0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + : "=d" (cc), "=m" (*time) : "a" (time) : "cc"); + return cc; +} + +static inline void set_clock_comparator(__u64 time) +{ + asm volatile("sckc 0(%1)" : : "m" (time), "a" (&time)); +} + +static inline void store_clock_comparator(__u64 *time) +{ + asm volatile("stckc 0(%1)" : "=m" (*time) : "a" (time)); +} + #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ typedef unsigned long long cycles_t; @@ -27,9 +62,24 @@ static inline unsigned long long get_clock (void) return clk; } +static inline void get_clock_extended(void *dest) +{ + typedef struct { unsigned long long clk[2]; } __clock_t; + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) + asm volatile("stcke %0" : "=Q" (*((__clock_t *)dest)) : : "cc"); +#else /* __GNUC__ */ + asm volatile("stcke 0(%1)" : "=m" (*((__clock_t *)dest)) + : "a" ((__clock_t *)dest) : "cc"); +#endif /* __GNUC__ */ +} + static inline cycles_t get_cycles(void) { return (cycles_t) get_clock() >> 2; } +int get_sync_clock(unsigned long long *clock); +void init_cpu_timer(void); + #endif diff --git a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h index fa4dc916a9bf..66793f55c8b2 100644 --- a/include/asm-s390/tlbflush.h +++ b/include/asm-s390/tlbflush.h @@ -3,6 +3,7 @@ #include #include +#include /* * TLB flushing: @@ -102,6 +103,14 @@ static inline void __flush_tlb_mm(struct mm_struct * mm) if (unlikely(cpus_empty(mm->cpu_vm_mask))) return; if (MACHINE_HAS_IDTE) { + pgd_t *shadow_pgd = get_shadow_pgd(mm->pgd); + + if (shadow_pgd) { + asm volatile( + " .insn rrf,0xb98e0000,0,%0,%1,0" + : : "a" (2048), + "a" (__pa(shadow_pgd) & PAGE_MASK) : "cc" ); + } asm volatile( " .insn rrf,0xb98e0000,0,%0,%1,0" : : "a" (2048), "a" (__pa(mm->pgd)&PAGE_MASK) : "cc"); diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h index 73ac4e82217b..0235970278f0 100644 --- a/include/asm-s390/uaccess.h +++ b/include/asm-s390/uaccess.h @@ -90,6 +90,8 @@ struct uaccess_ops { extern struct uaccess_ops uaccess; extern struct uaccess_ops uaccess_std; extern struct uaccess_ops uaccess_mvcos; +extern struct uaccess_ops uaccess_mvcos_switch; +extern struct uaccess_ops uaccess_pt; static inline int __put_user_fn(size_t size, void __user *ptr, void *x) { diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h index 6b6fc6f8be7e..a29f05087a31 100644 --- a/include/asm-x86_64/acpi.h +++ b/include/asm-x86_64/acpi.h @@ -37,7 +37,7 @@ * Calling conventions: * * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) - * ACPI_EXTERNAL_XFACE - External ACPI interfaces + * ACPI_EXTERNAL_XFACE - External ACPI interfaces * ACPI_INTERNAL_XFACE - Internal ACPI interfaces * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces */ @@ -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 @@ -87,10 +87,10 @@ extern int acpi_strict; extern int acpi_disabled; extern int acpi_pci_disabled; extern int acpi_ht; -static inline void disable_acpi(void) -{ - acpi_disabled = 1; - acpi_ht = 0; +static inline void disable_acpi(void) +{ + acpi_disabled = 1; + acpi_ht = 0; acpi_pci_disabled = 1; acpi_noirq = 1; } @@ -100,9 +100,9 @@ static inline void disable_acpi(void) extern int acpi_gsi_to_irq(u32 gsi, unsigned int *irq); static inline void acpi_noirq_set(void) { acpi_noirq = 1; } -static inline void acpi_disable_pci(void) +static inline void acpi_disable_pci(void) { - acpi_pci_disabled = 1; + acpi_pci_disabled = 1; acpi_noirq_set(); } extern int acpi_irq_balance_set(char *str); @@ -136,8 +136,6 @@ extern void acpi_reserve_bootmem(void); extern int acpi_disabled; extern int acpi_pci_disabled; -extern u8 x86_acpiid_to_apicid[]; - #define ARCH_HAS_POWER_INIT 1 extern int acpi_skip_timer_override; diff --git a/include/asm-x86_64/swiotlb.h b/include/asm-x86_64/swiotlb.h index ba94ab3d2673..ab913ffcad56 100644 --- a/include/asm-x86_64/swiotlb.h +++ b/include/asm-x86_64/swiotlb.h @@ -1,6 +1,5 @@ #ifndef _ASM_SWIOTLB_H -#define _ASM_SWTIOLB_H 1 - +#define _ASM_SWIOTLB_H 1 #include @@ -45,6 +44,7 @@ extern void swiotlb_init(void); extern int swiotlb_force; #ifdef CONFIG_SWIOTLB +#define SWIOTLB_ARCH_NEED_ALLOC extern int swiotlb; #else #define swiotlb 0 @@ -52,4 +52,6 @@ extern int swiotlb; extern void pci_swiotlb_init(void); -#endif /* _ASM_SWTIOLB_H */ +static inline void dma_mark_clean(void *addr, size_t size) {} + +#endif /* _ASM_SWIOTLB_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/acpi.h b/include/linux/acpi.h index 91f1f2363870..815f1fb4ce21 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -53,166 +53,6 @@ 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 { - 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, - 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, @@ -222,89 +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)); - -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 - */ -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 - */ - -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, - 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, @@ -313,84 +70,12 @@ 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 */ - -/* 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)); -struct acpi_table_mcfg { - struct acpi_table_header header; - u8 reserved[8]; - struct acpi_table_mcfg_config config[0]; -} __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 *table); -typedef int (*acpi_table_handler) (unsigned long phys_addr, unsigned long size); - -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); @@ -399,14 +84,12 @@ 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_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); -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); +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_type id, acpi_madt_entry_handler handler, unsigned int max_entries); +int acpi_parse_mcfg (struct acpi_table_header *header); +void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); +void acpi_table_print_srat_entry (struct acpi_subtable_header *srat); /* the following four functions are architecture-dependent */ #ifdef CONFIG_HAVE_ARCH_PARSE_SRAT @@ -417,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 @@ -433,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; diff --git a/include/linux/device.h b/include/linux/device.h index f44247fe8135..5ca1cdba563a 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); @@ -327,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; @@ -355,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; @@ -390,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); }; 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 +#ifdef CONFIG_HID_DEBUG -struct hid_usage_entry { - unsigned page; - unsigned usage; - char *description; -}; +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 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 } -}; +#else -static void resolv_usage_page(unsigned page) { - const struct hid_usage_entry *p; +#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) - 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); -} +#endif /* CONFIG_HID_DEBUG */ -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", -}; +#endif -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, -}; - -static void __attribute__((unused)) resolv_event(__u8 type, __u16 code) { - - 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 342b4e639acb..d26b08f461f2 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -264,6 +264,9 @@ 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 +#define HID_QUIRK_IGNORE_MOUSE 0x00040000 +#define HID_QUIRK_SONY_PS3_CONTROLLER 0x00080000 /* * This is the global environment of the parser. This information is @@ -430,8 +433,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, @@ -471,16 +474,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)) @@ -503,6 +496,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 diff --git a/include/linux/ide.h b/include/linux/ide.h index e26a03981a94..04e0fa97ac99 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; /* @@ -1192,8 +1207,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); @@ -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); 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/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/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/host.h b/include/linux/mmc/host.h index c15ae1986b98..913e5752569f 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -92,8 +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 */ @@ -106,8 +108,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; @@ -126,6 +129,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); 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 diff --git a/include/linux/module.h b/include/linux/module.h index 10f771a49997..419d3ef293dd 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,7 @@ struct module struct module_attribute *modinfo_attrs; const char *version; const char *srcversion; - struct kobject *drivers_dir; + struct kobject *holders_dir; /* Exported symbols */ const struct kernel_symbol *syms; diff --git a/include/linux/msi.h b/include/linux/msi.h index c7ef94343673..74c8a2ecc9dd 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 { @@ -42,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); 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/include/linux/pci.h b/include/linux/pci.h index f3c617eabd8d..805412cc6875 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) @@ -181,6 +184,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) { @@ -463,8 +471,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 *pci_find_device_reverse (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); @@ -533,6 +540,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 +569,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, @@ -573,10 +583,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 *); @@ -611,10 +622,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 */ @@ -622,7 +629,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, @@ -630,7 +636,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, @@ -722,8 +727,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) { } diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 3d1d21035dec..defdeed20641 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 @@ -1451,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 @@ -1971,6 +1975,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 @@ -2066,6 +2071,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 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); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 2129d1b6c874..192de3afa96b 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -11,10 +11,12 @@ #define _SYSFS_H_ #include +#include #include struct kobject; struct module; +struct nameidata; struct attribute { const char * name; @@ -88,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 *); @@ -126,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; } @@ -140,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; } @@ -204,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/include/linux/tifm.h b/include/linux/tifm.h index dfb8052eee5e..3deb0a6c1370 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 { @@ -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 @@ -89,10 +88,9 @@ 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, + void (*signal_irq)(struct tifm_dev *sock, unsigned int sock_irq_status); struct tifm_driver *drv; @@ -103,24 +101,23 @@ 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; }; 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; + wait_queue_head_t change_set_notify; unsigned int id; - unsigned int max_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; + unsigned int num_sockets; struct tifm_dev **sockets; + struct task_struct *media_switcher; struct class_device cdev; struct device *dev; @@ -130,9 +127,9 @@ 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, 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); diff --git a/include/linux/usb.h b/include/linux/usb.h index aab5b1b72021..b5c226a87ed8 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 @@ -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) @@ -372,7 +373,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 */ /* @@ -475,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); @@ -553,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 @@ -723,11 +738,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. @@ -868,10 +893,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 *); @@ -1085,7 +1111,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 */ 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 similarity index 99% rename from include/linux/usb_ch9.h rename to 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 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); 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 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 diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 623a0fc0dae1..6e84258b94de 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -284,7 +284,7 @@ struct pcmcia_socket { #endif /* socket device */ - struct class_device dev; + struct device dev; void *driver_data; /* data internal to the socket driver */ }; diff --git a/include/rdma/ib_user_mad.h b/include/rdma/ib_user_mad.h index 44537aa32e62..d66b15ea82c4 100644 --- a/include/rdma/ib_user_mad.h +++ b/include/rdma/ib_user_mad.h @@ -98,7 +98,7 @@ struct ib_user_mad_hdr { */ struct ib_user_mad { struct ib_user_mad_hdr hdr; - __u8 data[0]; + __u64 data[0]; }; /** diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 0bfa3328d686..765589f4d166 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -419,8 +420,8 @@ struct ib_wc { enum ib_wc_opcode opcode; u32 vendor_err; u32 byte_len; + struct ib_qp *qp; __be32 imm_data; - u32 qp_num; u32 src_qp; int wc_flags; u16 pkey_index; 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 diff --git a/kernel/module.c b/kernel/module.c index d0f2260a0210..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,21 +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->drivers_dir = kobject_add_dir(&mod->mkobj.kobj, "drivers"); - if (!mod->drivers_dir) { - err = -ENOMEM; + 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) @@ -1150,8 +1161,8 @@ static int mod_sysfs_setup(struct module *mod, out_unreg_param: module_param_sysfs_remove(mod); -out_unreg_drivers: - kobject_unregister(mod->drivers_dir); +out_unreg_holders: + kobject_unregister(mod->holders_dir); out_unreg: kobject_del(&mod->mkobj.kobj); kobject_put(&mod->mkobj.kobj); @@ -1163,7 +1174,10 @@ static void mod_kobject_remove(struct module *mod) { module_remove_modinfo_attrs(mod); module_param_sysfs_remove(mod); - kobject_unregister(mod->drivers_dir); + 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); } @@ -1768,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")); @@ -2340,19 +2358,43 @@ static char *make_driver_name(struct device_driver *drv) return driver_name; } +static void module_create_drivers_dir(struct module_kobject *mk) +{ + if (!mk || mk->drivers_dir) + return; + + mk->drivers_dir = kobject_add_dir(&mk->kobj, "drivers"); +} + 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, + module_create_drivers_dir(mk); + no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj, driver_name); kfree(driver_name); } @@ -2367,10 +2409,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..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 == '-') @@ -561,14 +563,11 @@ 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); + kobject_uevent(&mk->kobj, KOBJ_ADD); } /* @@ -674,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, @@ -685,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 diff --git a/lib/kobject.c b/lib/kobject.c index 7ce6dc138e90..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); @@ -126,6 +126,8 @@ EXPORT_SYMBOL_GPL(kobject_get_path); */ void kobject_init(struct kobject * kobj) { + if (!kobj) + return; kref_init(&kobj->kref); INIT_LIST_HEAD(&kobj->entry); init_waitqueue_head(&kobj->poll); @@ -156,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; @@ -189,12 +192,11 @@ 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); - if (parent) - kobject_put(parent); + kobject_put(parent); /* be noisy on error issues */ if (error == -EEXIST) @@ -211,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. @@ -303,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; @@ -312,7 +345,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name) /** * kobject_move - move object to another parent * @kobj: object in question. - * @new_parent: object's new parent + * @new_parent: object's new parent (can be NULL) */ int kobject_move(struct kobject *kobj, struct kobject *new_parent) @@ -328,8 +361,8 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent) return -EINVAL; new_parent = kobject_get(new_parent); if (!new_parent) { - error = -EINVAL; - goto out; + if (kobj->kset) + new_parent = kobject_get(&kobj->kset->kobj); } /* old object path */ devpath = kobject_get_path(kobj, GFP_KERNEL); @@ -366,6 +399,8 @@ out: void kobject_del(struct kobject * kobj) { + if (!kobj) + return; sysfs_remove_dir(kobj); unlink(kobj); } @@ -377,6 +412,8 @@ void kobject_del(struct kobject * kobj) void kobject_unregister(struct kobject * kobj) { + if (!kobj) + return; pr_debug("kobject %s: unregistering\n",kobject_name(kobj)); kobject_uevent(kobj, KOBJ_REMOVE); kobject_del(kobj); @@ -414,8 +451,7 @@ void kobject_cleanup(struct kobject * kobj) t->release(kobj); if (s) kset_put(s); - if (parent) - kobject_put(parent); + kobject_put(parent); } static void kobject_release(struct kref *kref) @@ -523,6 +559,8 @@ int kset_add(struct kset * k) int kset_register(struct kset * k) { + if (!k) + return -EINVAL; kset_init(k); return kset_add(k); } @@ -535,6 +573,8 @@ int kset_register(struct kset * k) void kset_unregister(struct kset * k) { + if (!k) + return; kobject_unregister(&k->kobj); } @@ -586,6 +626,9 @@ int subsystem_register(struct subsystem * s) { int error; + if (!s) + return -EINVAL; + subsystem_init(s); pr_debug("subsystem %s: registering\n",s->kset.kobj.name); @@ -598,6 +641,8 @@ int subsystem_register(struct subsystem * s) void subsystem_unregister(struct subsystem * s) { + if (!s) + return; pr_debug("subsystem %s: unregistering\n",s->kset.kobj.name); kset_unregister(&s->kset); } @@ -612,6 +657,10 @@ void subsystem_unregister(struct subsystem * s) int subsys_create_file(struct subsystem * s, struct subsys_attribute * a) { int error = 0; + + if (!s || !a) + return -EINVAL; + if (subsys_get(s)) { error = sysfs_create_file(&s->kset.kobj,&a->attr); subsys_put(s); diff --git a/lib/swiotlb.c b/lib/swiotlb.c index 10625785eefd..50a438010182 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -1,7 +1,7 @@ /* * Dynamic DMA mapping support. * - * This implementation is for IA-64 and EM64T platforms that do not support + * This implementation is a fallback for platforms that do not support * I/O TLBs (aka DMA address translation hardware). * Copyright (C) 2000 Asit Mallick * Copyright (C) 2000 Goutham Rao @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -35,8 +36,10 @@ #define OFFSET(val,align) ((unsigned long) \ ( (val) & ( (align) - 1))) +#ifndef SG_ENT_VIRT_ADDRESS #define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset) -#define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG)) +#define SG_ENT_PHYS_ADDRESS(sg) virt_to_bus(SG_ENT_VIRT_ADDRESS(sg)) +#endif /* * Maximum allowable number of contiguous slabs to map, @@ -101,13 +104,25 @@ static unsigned int io_tlb_index; * We need to save away the original address corresponding to a mapped entry * for the sync operations. */ -static unsigned char **io_tlb_orig_addr; +#ifndef SWIOTLB_ARCH_HAS_IO_TLB_ADDR_T +typedef char *io_tlb_addr_t; +#define swiotlb_orig_addr_null(buffer) (!(buffer)) +#define ptr_to_io_tlb_addr(ptr) (ptr) +#define page_to_io_tlb_addr(pg, off) (page_address(pg) + (off)) +#define sg_to_io_tlb_addr(sg) SG_ENT_VIRT_ADDRESS(sg) +#endif +static io_tlb_addr_t *io_tlb_orig_addr; /* * Protect the above data structures in the map and unmap calls */ static DEFINE_SPINLOCK(io_tlb_lock); +#ifdef SWIOTLB_EXTRA_VARIABLES +SWIOTLB_EXTRA_VARIABLES; +#endif + +#ifndef SWIOTLB_ARCH_HAS_SETUP_IO_TLB_NPAGES static int __init setup_io_tlb_npages(char *str) { @@ -122,30 +137,50 @@ setup_io_tlb_npages(char *str) swiotlb_force = 1; return 1; } +#endif __setup("swiotlb=", setup_io_tlb_npages); /* make io_tlb_overflow tunable too? */ +#ifndef swiotlb_adjust_size +#define swiotlb_adjust_size(size) ((void)0) +#endif + +#ifndef swiotlb_adjust_seg +#define swiotlb_adjust_seg(start, size) ((void)0) +#endif + +#ifndef swiotlb_print_info +#define swiotlb_print_info(bytes) \ + printk(KERN_INFO "Placing %luMB software IO TLB between 0x%lx - " \ + "0x%lx\n", bytes >> 20, \ + virt_to_bus(io_tlb_start), virt_to_bus(io_tlb_end)) +#endif + /* * Statically reserve bounce buffer space and initialize bounce buffer data * structures for the software IO TLB used to implement the DMA API. */ -void -swiotlb_init_with_default_size (size_t default_size) +void __init +swiotlb_init_with_default_size(size_t default_size) { - unsigned long i; + unsigned long i, bytes; if (!io_tlb_nslabs) { io_tlb_nslabs = (default_size >> IO_TLB_SHIFT); io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE); } + swiotlb_adjust_size(io_tlb_nslabs); + swiotlb_adjust_size(io_tlb_overflow); + + bytes = io_tlb_nslabs << IO_TLB_SHIFT; /* * Get IO TLB memory from the low pages */ - io_tlb_start = alloc_bootmem_low_pages(io_tlb_nslabs * (1 << IO_TLB_SHIFT)); + io_tlb_start = alloc_bootmem_low_pages(bytes); if (!io_tlb_start) panic("Cannot allocate SWIOTLB buffer"); - io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT); + io_tlb_end = io_tlb_start + bytes; /* * Allocate and initialize the free list array. This array is used @@ -153,34 +188,45 @@ swiotlb_init_with_default_size (size_t default_size) * between io_tlb_start and io_tlb_end. */ io_tlb_list = alloc_bootmem(io_tlb_nslabs * sizeof(int)); - for (i = 0; i < io_tlb_nslabs; i++) + for (i = 0; i < io_tlb_nslabs; i++) { + if ( !(i % IO_TLB_SEGSIZE) ) + swiotlb_adjust_seg(io_tlb_start + (i << IO_TLB_SHIFT), + IO_TLB_SEGSIZE << IO_TLB_SHIFT); io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); + } io_tlb_index = 0; - io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *)); + io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(io_tlb_addr_t)); /* * Get the overflow emergency buffer */ io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow); - printk(KERN_INFO "Placing software IO TLB between 0x%lx - 0x%lx\n", - virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end)); -} + if (!io_tlb_overflow_buffer) + panic("Cannot allocate SWIOTLB overflow buffer!\n"); + swiotlb_adjust_seg(io_tlb_overflow_buffer, io_tlb_overflow); -void -swiotlb_init (void) + swiotlb_print_info(bytes); +} +#ifndef __swiotlb_init_with_default_size +#define __swiotlb_init_with_default_size swiotlb_init_with_default_size +#endif + +void __init +swiotlb_init(void) { - swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */ + __swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */ } +#ifdef SWIOTLB_ARCH_NEED_LATE_INIT /* * Systems with larger DMA zones (those that don't support ISA) can * initialize the swiotlb later using the slab allocator if needed. * This should be just like above, but with some error catching. */ int -swiotlb_late_init_with_default_size (size_t default_size) +swiotlb_late_init_with_default_size(size_t default_size) { - unsigned long i, req_nslabs = io_tlb_nslabs; + unsigned long i, bytes, req_nslabs = io_tlb_nslabs; unsigned int order; if (!io_tlb_nslabs) { @@ -191,8 +237,9 @@ swiotlb_late_init_with_default_size (size_t default_size) /* * Get IO TLB memory from the low pages */ - order = get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT)); + order = get_order(io_tlb_nslabs << IO_TLB_SHIFT); io_tlb_nslabs = SLABS_PER_PAGE << order; + bytes = io_tlb_nslabs << IO_TLB_SHIFT; while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) { io_tlb_start = (char *)__get_free_pages(GFP_DMA | __GFP_NOWARN, @@ -205,13 +252,14 @@ swiotlb_late_init_with_default_size (size_t default_size) if (!io_tlb_start) goto cleanup1; - if (order != get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT))) { + if (order != get_order(bytes)) { printk(KERN_WARNING "Warning: only able to allocate %ld MB " "for software IO TLB\n", (PAGE_SIZE << order) >> 20); io_tlb_nslabs = SLABS_PER_PAGE << order; + bytes = io_tlb_nslabs << IO_TLB_SHIFT; } - io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT); - memset(io_tlb_start, 0, io_tlb_nslabs * (1 << IO_TLB_SHIFT)); + io_tlb_end = io_tlb_start + bytes; + memset(io_tlb_start, 0, bytes); /* * Allocate and initialize the free list array. This array is used @@ -227,12 +275,12 @@ swiotlb_late_init_with_default_size (size_t default_size) io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE); io_tlb_index = 0; - io_tlb_orig_addr = (unsigned char **)__get_free_pages(GFP_KERNEL, - get_order(io_tlb_nslabs * sizeof(char *))); + io_tlb_orig_addr = (io_tlb_addr_t *)__get_free_pages(GFP_KERNEL, + get_order(io_tlb_nslabs * sizeof(io_tlb_addr_t))); if (!io_tlb_orig_addr) goto cleanup3; - memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(char *)); + memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(io_tlb_addr_t)); /* * Get the overflow emergency buffer @@ -242,29 +290,29 @@ swiotlb_late_init_with_default_size (size_t default_size) if (!io_tlb_overflow_buffer) goto cleanup4; - printk(KERN_INFO "Placing %ldMB software IO TLB between 0x%lx - " - "0x%lx\n", (io_tlb_nslabs * (1 << IO_TLB_SHIFT)) >> 20, - virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end)); + swiotlb_print_info(bytes); return 0; cleanup4: - free_pages((unsigned long)io_tlb_orig_addr, get_order(io_tlb_nslabs * - sizeof(char *))); + free_pages((unsigned long)io_tlb_orig_addr, + get_order(io_tlb_nslabs * sizeof(io_tlb_addr_t))); io_tlb_orig_addr = NULL; cleanup3: - free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs * - sizeof(int))); + free_pages((unsigned long)io_tlb_list, + get_order(io_tlb_nslabs * sizeof(int))); io_tlb_list = NULL; - io_tlb_end = NULL; cleanup2: + io_tlb_end = NULL; free_pages((unsigned long)io_tlb_start, order); io_tlb_start = NULL; cleanup1: io_tlb_nslabs = req_nslabs; return -ENOMEM; } +#endif +#ifndef SWIOTLB_ARCH_HAS_NEEDS_MAPPING static inline int address_needs_mapping(struct device *hwdev, dma_addr_t addr) { @@ -275,11 +323,35 @@ address_needs_mapping(struct device *hwdev, dma_addr_t addr) return (addr & ~mask) != 0; } +static inline int range_needs_mapping(const void *ptr, size_t size) +{ + return swiotlb_force; +} + +static inline int order_needs_mapping(unsigned int order) +{ + return 0; +} +#endif + +static void +__sync_single(io_tlb_addr_t buffer, char *dma_addr, size_t size, int dir) +{ +#ifndef SWIOTLB_ARCH_HAS_SYNC_SINGLE + if (dir == DMA_TO_DEVICE) + memcpy(dma_addr, buffer, size); + else + memcpy(buffer, dma_addr, size); +#else + __swiotlb_arch_sync_single(buffer, dma_addr, size, dir); +#endif +} + /* * Allocates bounce buffer and returns its kernel virtual address. */ static void * -map_single(struct device *hwdev, char *buffer, size_t size, int dir) +map_single(struct device *hwdev, io_tlb_addr_t buffer, size_t size, int dir) { unsigned long flags; char *dma_addr; @@ -352,7 +424,7 @@ map_single(struct device *hwdev, char *buffer, size_t size, int dir) */ io_tlb_orig_addr[index] = buffer; if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL) - memcpy(dma_addr, buffer, size); + __sync_single(buffer, dma_addr, size, DMA_TO_DEVICE); return dma_addr; } @@ -366,17 +438,18 @@ unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir) unsigned long flags; int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT; int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT; - char *buffer = io_tlb_orig_addr[index]; + io_tlb_addr_t buffer = io_tlb_orig_addr[index]; /* * First, sync the memory before unmapping the entry */ - if (buffer && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL))) + if (!swiotlb_orig_addr_null(buffer) + && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL))) /* * bounce... copy the data back into the original buffer * and * delete the bounce buffer. */ - memcpy(buffer, dma_addr, size); + __sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE); /* * Return the buffer to the free list by setting the corresponding @@ -409,18 +482,18 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size, int dir, int target) { int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT; - char *buffer = io_tlb_orig_addr[index]; + io_tlb_addr_t buffer = io_tlb_orig_addr[index]; switch (target) { case SYNC_FOR_CPU: if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)) - memcpy(buffer, dma_addr, size); + __sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE); else BUG_ON(dir != DMA_TO_DEVICE); break; case SYNC_FOR_DEVICE: if (likely(dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)) - memcpy(dma_addr, buffer, size); + __sync_single(buffer, dma_addr, size, DMA_TO_DEVICE); else BUG_ON(dir != DMA_FROM_DEVICE); break; @@ -429,11 +502,13 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size, } } +#ifdef SWIOTLB_ARCH_NEED_ALLOC + void * swiotlb_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t flags) { - unsigned long dev_addr; + dma_addr_t dev_addr; void *ret; int order = get_order(size); @@ -444,8 +519,11 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, */ flags |= GFP_DMA; - ret = (void *)__get_free_pages(flags, order); - if (ret && address_needs_mapping(hwdev, virt_to_phys(ret))) { + if (!order_needs_mapping(order)) + ret = (void *)__get_free_pages(flags, order); + else + ret = NULL; + if (ret && address_needs_mapping(hwdev, virt_to_bus(ret))) { /* * The allocated memory isn't reachable by the device. * Fall back on swiotlb_map_single(). @@ -465,22 +543,24 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size, if (swiotlb_dma_mapping_error(handle)) return NULL; - ret = phys_to_virt(handle); + ret = bus_to_virt(handle); } memset(ret, 0, size); - dev_addr = virt_to_phys(ret); + dev_addr = virt_to_bus(ret); /* Confirm address can be DMA'd by device */ if (address_needs_mapping(hwdev, dev_addr)) { - printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016lx\n", - (unsigned long long)*hwdev->dma_mask, dev_addr); + printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n", + (unsigned long long)*hwdev->dma_mask, + (unsigned long long)dev_addr); panic("swiotlb_alloc_coherent: allocated memory is out of " "range for device"); } *dma_handle = dev_addr; return ret; } +EXPORT_SYMBOL(swiotlb_alloc_coherent); void swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, @@ -493,6 +573,9 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, /* DMA_TO_DEVICE to avoid memcpy in unmap_single */ swiotlb_unmap_single (hwdev, dma_handle, size, DMA_TO_DEVICE); } +EXPORT_SYMBOL(swiotlb_free_coherent); + +#endif static void swiotlb_full(struct device *dev, size_t size, int dir, int do_panic) @@ -504,7 +587,7 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic) * When the mapping is small enough return a static buffer to limit * the damage, or panic when the transfer is too big. */ - printk(KERN_ERR "DMA: Out of SW-IOMMU space for %lu bytes at " + printk(KERN_ERR "DMA: Out of SW-IOMMU space for %zu bytes at " "device %s\n", size, dev ? dev->bus_id : "?"); if (size > io_tlb_overflow && do_panic) { @@ -525,7 +608,7 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic) dma_addr_t swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir) { - unsigned long dev_addr = virt_to_phys(ptr); + dma_addr_t dev_addr = virt_to_bus(ptr); void *map; BUG_ON(dir == DMA_NONE); @@ -534,19 +617,20 @@ swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir) * we can safely return the device addr and not worry about bounce * buffering it. */ - if (!address_needs_mapping(hwdev, dev_addr) && !swiotlb_force) + if (!range_needs_mapping(ptr, size) + && !address_needs_mapping(hwdev, dev_addr)) return dev_addr; /* * Oh well, have to allocate and map a bounce buffer. */ - map = map_single(hwdev, ptr, size, dir); + map = map_single(hwdev, ptr_to_io_tlb_addr(ptr), size, dir); if (!map) { swiotlb_full(hwdev, size, dir, 1); map = io_tlb_overflow_buffer; } - dev_addr = virt_to_phys(map); + dev_addr = virt_to_bus(map); /* * Ensure that the address returned is DMA'ble @@ -557,25 +641,6 @@ swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir) return dev_addr; } -/* - * Since DMA is i-cache coherent, any (complete) pages that were written via - * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to - * flush them when they get mapped into an executable vm-area. - */ -static void -mark_clean(void *addr, size_t size) -{ - unsigned long pg_addr, end; - - pg_addr = PAGE_ALIGN((unsigned long) addr); - end = (unsigned long) addr + size; - while (pg_addr + PAGE_SIZE <= end) { - struct page *page = virt_to_page(pg_addr); - set_bit(PG_arch_1, &page->flags); - pg_addr += PAGE_SIZE; - } -} - /* * Unmap a single streaming mode DMA translation. The dma_addr and size must * match what was provided for in a previous swiotlb_map_single call. All @@ -588,13 +653,13 @@ void swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir) { - char *dma_addr = phys_to_virt(dev_addr); + char *dma_addr = bus_to_virt(dev_addr); BUG_ON(dir == DMA_NONE); if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) unmap_single(hwdev, dma_addr, size, dir); else if (dir == DMA_FROM_DEVICE) - mark_clean(dma_addr, size); + dma_mark_clean(dma_addr, size); } /* @@ -611,13 +676,13 @@ static inline void swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir, int target) { - char *dma_addr = phys_to_virt(dev_addr); + char *dma_addr = bus_to_virt(dev_addr); BUG_ON(dir == DMA_NONE); if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) sync_single(hwdev, dma_addr, size, dir, target); else if (dir == DMA_FROM_DEVICE) - mark_clean(dma_addr, size); + dma_mark_clean(dma_addr, size); } void @@ -642,13 +707,13 @@ swiotlb_sync_single_range(struct device *hwdev, dma_addr_t dev_addr, unsigned long offset, size_t size, int dir, int target) { - char *dma_addr = phys_to_virt(dev_addr) + offset; + char *dma_addr = bus_to_virt(dev_addr) + offset; BUG_ON(dir == DMA_NONE); if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) sync_single(hwdev, dma_addr, size, dir, target); else if (dir == DMA_FROM_DEVICE) - mark_clean(dma_addr, size); + dma_mark_clean(dma_addr, size); } void @@ -687,18 +752,16 @@ int swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems, int dir) { - void *addr; - unsigned long dev_addr; + dma_addr_t dev_addr; int i; BUG_ON(dir == DMA_NONE); for (i = 0; i < nelems; i++, sg++) { - addr = SG_ENT_VIRT_ADDRESS(sg); - dev_addr = virt_to_phys(addr); - if (swiotlb_force || address_needs_mapping(hwdev, dev_addr)) { - void *map = map_single(hwdev, addr, sg->length, dir); - sg->dma_address = virt_to_bus(map); + dev_addr = SG_ENT_PHYS_ADDRESS(sg); + if (range_needs_mapping(SG_ENT_VIRT_ADDRESS(sg), sg->length) + || address_needs_mapping(hwdev, dev_addr)) { + void *map = map_single(hwdev, sg_to_io_tlb_addr(sg), sg->length, dir); if (!map) { /* Don't panic here, we expect map_sg users to do proper error handling. */ @@ -707,6 +770,7 @@ swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems, sg[0].dma_length = 0; return 0; } + sg->dma_address = virt_to_bus(map); } else sg->dma_address = dev_addr; sg->dma_length = sg->length; @@ -728,9 +792,10 @@ swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nelems, for (i = 0; i < nelems; i++, sg++) if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) - unmap_single(hwdev, (void *) phys_to_virt(sg->dma_address), sg->dma_length, dir); + unmap_single(hwdev, bus_to_virt(sg->dma_address), + sg->dma_length, dir); else if (dir == DMA_FROM_DEVICE) - mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length); + dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length); } /* @@ -750,8 +815,10 @@ swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sg, for (i = 0; i < nelems; i++, sg++) if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) - sync_single(hwdev, (void *) sg->dma_address, + sync_single(hwdev, bus_to_virt(sg->dma_address), sg->dma_length, dir, target); + else if (dir == DMA_FROM_DEVICE) + dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length); } void @@ -768,10 +835,48 @@ swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg, swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_DEVICE); } +#ifdef SWIOTLB_ARCH_NEED_MAP_PAGE + +dma_addr_t +swiotlb_map_page(struct device *hwdev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + dma_addr_t dev_addr; + char *map; + + dev_addr = page_to_bus(page) + offset; + if (address_needs_mapping(hwdev, dev_addr)) { + map = map_single(hwdev, page_to_io_tlb_addr(page, offset), size, direction); + if (!map) { + swiotlb_full(hwdev, size, direction, 1); + map = io_tlb_overflow_buffer; + } + dev_addr = virt_to_bus(map); + } + + return dev_addr; +} + +void +swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr, + size_t size, enum dma_data_direction direction) +{ + char *dma_addr = bus_to_virt(dev_addr); + + BUG_ON(direction == DMA_NONE); + if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) + unmap_single(hwdev, dma_addr, size, direction); + else if (direction == DMA_FROM_DEVICE) + dma_mark_clean(dma_addr, size); +} + +#endif + int swiotlb_dma_mapping_error(dma_addr_t dma_addr) { - return (dma_addr == virt_to_phys(io_tlb_overflow_buffer)); + return (dma_addr == virt_to_bus(io_tlb_overflow_buffer)); } /* @@ -780,10 +885,13 @@ swiotlb_dma_mapping_error(dma_addr_t dma_addr) * during bus mastering, then you would pass 0x00ffffff as the mask to * this function. */ +#ifndef __swiotlb_dma_supported +#define __swiotlb_dma_supported(hwdev, mask) (virt_to_bus(io_tlb_end - 1) <= (mask)) +#endif int -swiotlb_dma_supported (struct device *hwdev, u64 mask) +swiotlb_dma_supported(struct device *hwdev, u64 mask) { - return (virt_to_phys (io_tlb_end) - 1) <= mask; + return __swiotlb_dma_supported(hwdev, mask); } EXPORT_SYMBOL(swiotlb_init); @@ -798,6 +906,4 @@ EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_device); EXPORT_SYMBOL(swiotlb_sync_sg_for_cpu); EXPORT_SYMBOL(swiotlb_sync_sg_for_device); EXPORT_SYMBOL(swiotlb_dma_mapping_error); -EXPORT_SYMBOL(swiotlb_alloc_coherent); -EXPORT_SYMBOL(swiotlb_free_coherent); EXPORT_SYMBOL(swiotlb_dma_supported); 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); diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c index fa2f7da606a9..fb58e03b3fbd 100644 --- a/net/ieee80211/softmac/ieee80211softmac_wx.c +++ b/net/ieee80211/softmac/ieee80211softmac_wx.c @@ -265,6 +265,12 @@ ieee80211softmac_wx_get_rate(struct net_device *net_dev, int err = -EINVAL; spin_lock_irqsave(&mac->lock, flags); + + if (unlikely(!mac->running)) { + err = -ENODEV; + goto out_unlock; + } + switch (mac->txrates.default_rate) { case IEEE80211_CCK_RATE_1MB: data->bitrate.value = 1000000; diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index f01f8c072852..a1880e854dce 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -1,7 +1,7 @@ #### # kbuild: Generic definitions -# Convinient variables +# Convenient constants comma := , squote := ' empty := @@ -56,76 +56,87 @@ endef # gcc support functions # See documentation in Documentation/kbuild/makefiles.txt -# output directory for tests below -TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/) +# checker-shell +# Usage: option = $(call checker-shell,$(CC)...-o $$OUT,option-ok,otherwise) +# Exit code chooses option. $$OUT is safe location for needless output. +define checker-shell +$(shell set -e; \ + DIR=$(KBUILD_EXTMOD); \ + cd $${DIR:-$(objtree)}; \ + OUT=$$PWD/.$$$$.null; \ + if $(1) >/dev/null 2>&1; \ + then echo "$(2)"; \ + else echo "$(3)"; \ + fi; \ + rm -f $$OUT) +endef # as-option -# Usage: cflags-y += $(call as-option, -Wa$(comma)-isa=foo,) - -as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \ - -xassembler /dev/null > /dev/null 2>&1; then echo "$(1)"; \ - else echo "$(2)"; fi ;) +# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,) +as-option = $(call checker-shell,\ + $(CC) $(CFLAGS) $(1) -c -xassembler /dev/null -o $$OUT,$(1),$(2)) # as-instr -# Usage: cflags-y += $(call as-instr, instr, option1, option2) - -as-instr = $(shell if echo -e "$(1)" | \ - $(CC) $(AFLAGS) -c -xassembler - \ - -o $(TMPOUT)astest$$$$.out > /dev/null 2>&1; \ - then rm $(TMPOUT)astest$$$$.out; echo "$(2)"; \ - else echo "$(3)"; fi) +# Usage: cflags-y += $(call as-instr,instr,option1,option2) +as-instr = $(call checker-shell,\ + printf "$(1)" | $(CC) $(AFLAGS) -c -xassembler -o $$OUT -,$(2),$(3)) # cc-option -# Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586) - -cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \ - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) +# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) +cc-option = $(call checker-shell,\ + $(CC) $(CFLAGS) $(if $(3),$(3),$(1)) -S -xc /dev/null -o $$OUT,$(1),$(2)) # cc-option-yn -# Usage: flag := $(call cc-option-yn, -march=winchip-c6) -cc-option-yn = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \ - > /dev/null 2>&1; then echo "y"; else echo "n"; fi;) +# Usage: flag := $(call cc-option-yn,-march=winchip-c6) +cc-option-yn = $(call cc-option,"y","n",$(1)) # cc-option-align # Prefix align with either -falign or -malign cc-option-align = $(subst -functions=0,,\ - $(call cc-option,-falign-functions=0,-malign-functions=0)) + $(call cc-option,-falign-functions=0,-malign-functions=0)) # cc-version -# Usage gcc-ver := $(call cc-version, $(CC)) +# Usage gcc-ver := $(call cc-version,$(CC)) cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) # cc-ifversion # Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1) -cc-ifversion = $(shell if [ $(call cc-version, $(CC)) $(1) $(2) ]; then \ - echo $(3); fi;) +cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3)) # ld-option # Usage: ldflags += $(call ld-option, -Wl$(comma)--hash-style=both) -ld-option = $(shell if $(CC) $(1) -nostdlib -xc /dev/null \ - -o $(TMPOUT)ldtest$$$$.out > /dev/null 2>&1; \ - then rm $(TMPOUT)ldtest$$$$.out; echo "$(1)"; \ - else echo "$(2)"; fi) +ld-option = $(call checker-shell,\ + $(CC) $(1) -nostdlib -xc /dev/null -o $$OUT,$(1),$(2)) + +###### -### # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj= # Usage: # $(Q)$(MAKE) $(build)=dir build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj -# Prefix -I with $(srctree) if it is not an absolute path -addtree = $(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1) -# Find all -I options and call addtree -flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o))) +# Prefix -I with $(srctree) if it is not an absolute path, +# add original to the end +addtree = $(if \ + $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1) -# If quiet is set, only print short version of command +# Find all -I options and call addtree +flags = $(foreach o,$($(1)),\ + $(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o))) + +# echo command. +# Short version is used, if $(quiet) equals `quiet_', otherwise full one. +echo-cmd = $(if $($(quiet)cmd_$(1)),\ + echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';) + +# printing commands cmd = @$(echo-cmd) $(cmd_$(1)) -# Add $(obj)/ for paths that is not absolute +# Add $(obj)/ for paths that are not absolute objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o))) ### -# if_changed - execute command if any prerequisite is newer than +# if_changed - execute command if any prerequisite is newer than # target, or command line has changed # if_changed_dep - as if_changed, but uses fixdep to reveal dependencies # including used config symbols @@ -133,16 +144,12 @@ objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o))) # See Documentation/kbuild/makefiles.txt for more info ifneq ($(KBUILD_NOCMDDEP),1) -# Check if both arguments has same arguments. Result in empty string if equal +# Check if both arguments has same arguments. Result is empty string, if equal. # User may override this check using make KBUILD_NOCMDDEP=1 arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ $(filter-out $(cmd_$@), $(cmd_$(1))) ) endif -# echo command. Short version is $(quiet) equals quiet, otherwise full command -echo-cmd = $(if $($(quiet)cmd_$(1)), \ - echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';) - # >'< substitution is for echo to work, # >$< substitution to preserve $ when reloading .cmd file # note: when using inline perl scripts [perl -e '...$$t=1;...'] @@ -153,15 +160,15 @@ make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1))))) # PHONY targets skipped in both cases. any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^) -# Execute command if command has changed or prerequisitei(s) are updated +# Execute command if command has changed or prerequisite(s) are updated. # if_changed = $(if $(strip $(any-prereq) $(arg-check)), \ @set -e; \ $(echo-cmd) $(cmd_$(1)); \ echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd) -# execute the command and also postprocess generated .d dependencies -# file +# Execute the command and also postprocess generated .d dependencies file. +# if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \ @set -e; \ $(echo-cmd) $(cmd_$(1)); \ @@ -169,9 +176,10 @@ if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \ rm -f $(depfile); \ mv -f $(dot-target).tmp $(dot-target).cmd) +# Will check if $(cmd_foo) changed, or any of the prerequisites changed, +# and if so will execute $(rule_foo). # Usage: $(call if_changed_rule,foo) -# will check if $(cmd_foo) changed, or any of the prequisites changed, -# and if so will execute $(rule_foo) +# if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \ @set -e; \ $(rule_$(1))) diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh index 4c723fd18648..43f75d6e4d96 100644 --- a/scripts/gen_initramfs_list.sh +++ b/scripts/gen_initramfs_list.sh @@ -1,6 +1,6 @@ #!/bin/bash # Copyright (C) Martin Schlemmer -# Copyright (c) 2006 Sam Ravnborg +# Copyright (C) 2006 Sam Ravnborg # # Released under the terms of the GNU GPL # @@ -17,15 +17,15 @@ cat << EOF Usage: $0 [-o ] [-u ] [-g ] {-d | } ... -o Create gzipped initramfs file named using - gen_init_cpio and gzip + gen_init_cpio and gzip -u User ID to map to user ID 0 (root). - is only meaningful if - is a directory. + is only meaningful if + is a directory. -g Group ID to map to group ID 0 (root). - is only meaningful if - is a directory. + is only meaningful if + is a directory. File list or directory for cpio archive. - If is a .cpio file it will be used + If is a .cpio file it will be used as direct input to initramfs. -d Output the default cpio list. @@ -36,6 +36,12 @@ to reset the root/group mapping. EOF } +# awk style field access +# $1 - field number; rest is argument string +field() { + shift $1 ; echo $1 +} + list_default_initramfs() { # echo usr/kinit/kinit : @@ -119,22 +125,17 @@ parse() { str="${ftype} ${name} ${location} ${str}" ;; "nod") - local dev_type= - local maj=$(LC_ALL=C ls -l "${location}" | \ - gawk '{sub(/,/, "", $5); print $5}') - local min=$(LC_ALL=C ls -l "${location}" | \ - gawk '{print $6}') + local dev=`LC_ALL=C ls -l "${location}"` + local maj=`field 5 ${dev}` + local min=`field 6 ${dev}` + maj=${maj%,} - if [ -b "${location}" ]; then - dev_type="b" - else - dev_type="c" - fi - str="${ftype} ${name} ${str} ${dev_type} ${maj} ${min}" + [ -b "${location}" ] && dev="b" || dev="c" + + str="${ftype} ${name} ${str} ${dev} ${maj} ${min}" ;; "slink") - local target=$(LC_ALL=C ls -l "${location}" | \ - gawk '{print $11}') + local target=`field 11 $(LC_ALL=C ls -l "${location}")` str="${ftype} ${name} ${target} ${str}" ;; *) diff --git a/scripts/makelst b/scripts/makelst index 34bd72391238..4fc80f2b7e19 100755 --- a/scripts/makelst +++ b/scripts/makelst @@ -1,31 +1,31 @@ -#!/bin/bash +#!/bin/sh # A script to dump mixed source code & assembly # with correct relocations from System.map -# Requires the following lines in Rules.make. -# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) -# William Stearns +# Requires the following lines in makefile: #%.lst: %.c # $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $< -# $(TOPDIR)/scripts/makelst $*.o $(TOPDIR)/System.map $(OBJDUMP) +# $(srctree)/scripts/makelst $*.o $(objtree)/System.map $(OBJDUMP) # -# Copyright (C) 2000 IBM Corporation -# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) +# Copyright (C) 2000 IBM Corporation +# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) +# William Stearns # -t1=`$3 --syms $1 | grep .text | grep " F " | head -n 1` +# awk style field access +field() { + shift $1 ; echo $1 +} + +t1=`$3 --syms $1 | grep .text | grep -m1 " F "` if [ -n "$t1" ]; then - t2=`echo $t1 | gawk '{ print $6 }'` + t2=`field 6 $t1` if [ ! -r $2 ]; then echo "No System.map" >&2 - t7=0 else t3=`grep $t2 $2` - t4=`echo $t3 | gawk '{ print $1 }'` - t5=`echo $t1 | gawk '{ print $1 }'` - t6=`echo $t4 - $t5 | tr a-f A-F` - t7=`( echo ibase=16 ; echo $t6 ) | bc` + t4=`field 1 $t3` + t5=`field 1 $t1` + t6=`printf "%lu" $((0x$t4 - 0x$t5))` fi -else - t7=0 fi -$3 -r --source --adjust-vma=$t7 $1 +$3 -r --source --adjust-vma=${t6:-0} $1 diff --git a/security/keys/key.c b/security/keys/key.c index ac9326c5f1da..700400d801dc 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -188,6 +188,7 @@ static inline void key_alloc_serial(struct key *key) spin_lock(&key_serial_lock); +attempt_insertion: parent = NULL; p = &key_serial_tree.rb_node; @@ -202,39 +203,33 @@ static inline void key_alloc_serial(struct key *key) else goto serial_exists; } - goto insert_here; + + /* we've found a suitable hole - arrange for this key to occupy it */ + rb_link_node(&key->serial_node, parent, p); + rb_insert_color(&key->serial_node, &key_serial_tree); + + spin_unlock(&key_serial_lock); + return; /* we found a key with the proposed serial number - walk the tree from * that point looking for the next unused serial number */ serial_exists: for (;;) { key->serial++; - if (key->serial < 2) - key->serial = 2; - - if (!rb_parent(parent)) - p = &key_serial_tree.rb_node; - else if (rb_parent(parent)->rb_left == parent) - p = &(rb_parent(parent)->rb_left); - else - p = &(rb_parent(parent)->rb_right); + if (key->serial < 3) { + key->serial = 3; + goto attempt_insertion; + } parent = rb_next(parent); if (!parent) - break; + goto attempt_insertion; xkey = rb_entry(parent, struct key, serial_node); if (key->serial < xkey->serial) - goto insert_here; + goto attempt_insertion; } - /* we've found a suitable hole - arrange for this key to occupy it */ -insert_here: - rb_link_node(&key->serial_node, parent, p); - rb_insert_color(&key->serial_node, &key_serial_tree); - - spin_unlock(&key_serial_lock); - } /* end key_alloc_serial() */ /*****************************************************************************/