From 3cca65944a49a3f8346ac868f5ad3746f9d8a222 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Tue, 28 Jun 2005 21:01:03 +0100 Subject: [PATCH] --- yaml --- r: 3870 b: refs/heads/master c: fa0ebff62a8a25952a082641db0ed6b1cfc6c38c h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/Documentation/DocBook/libata.tmpl | 96 +- trunk/Documentation/kernel-parameters.txt | 4 - trunk/arch/arm/oprofile/Makefile | 2 +- trunk/arch/arm/oprofile/backtrace.c | 144 ++ trunk/arch/arm/oprofile/init.c | 2 + trunk/arch/arm/oprofile/op_arm_model.h | 2 + trunk/arch/i386/kernel/acpi/boot.c | 57 +- trunk/arch/i386/pci/common.c | 8 +- trunk/arch/i386/pci/irq.c | 51 +- trunk/arch/i386/pci/legacy.c | 2 - trunk/arch/i386/pci/mmconfig.c | 39 +- trunk/arch/i386/pci/numa.c | 2 - trunk/arch/i386/pci/pci.h | 1 - trunk/arch/ia64/kernel/acpi.c | 30 +- trunk/arch/ia64/kernel/iosapic.c | 134 +- trunk/arch/ia64/pci/pci.c | 38 +- trunk/arch/ppc/kernel/pci.c | 21 +- trunk/arch/ppc64/kernel/pci.c | 22 +- trunk/arch/x86_64/pci/mmconfig.c | 68 +- trunk/drivers/acpi/container.c | 2 +- trunk/drivers/acpi/pci_bind.c | 27 +- trunk/drivers/acpi/pci_root.c | 24 +- trunk/drivers/acpi/processor_core.c | 2 +- trunk/drivers/acpi/scan.c | 126 +- trunk/drivers/block/cciss.c | 1 + trunk/drivers/block/ll_rw_blk.c | 9 - trunk/drivers/char/moxa.c | 2 +- trunk/drivers/char/rio/rio_linux.c | 4 +- trunk/drivers/md/md.c | 1 - trunk/drivers/message/fusion/mptfc.c | 4 +- trunk/drivers/message/fusion/mptscsih.c | 10 +- trunk/drivers/message/fusion/mptscsih.h | 2 +- trunk/drivers/message/fusion/mptspi.c | 4 +- trunk/drivers/net/amd8111e.c | 8 +- trunk/drivers/net/at1700.c | 4 + trunk/drivers/net/e100.c | 9 +- trunk/drivers/net/skge.c | 1710 +++++++++++---------- trunk/drivers/net/skge.h | 586 +++++-- trunk/drivers/net/smc91x.c | 2 +- trunk/drivers/net/smc91x.h | 13 - trunk/drivers/net/via-rhine.c | 11 +- trunk/drivers/parisc/dino.c | 1 - trunk/drivers/parisc/lba_pci.c | 2 - trunk/drivers/pci/bus.c | 11 +- trunk/drivers/pci/hotplug/Makefile | 4 +- trunk/drivers/pci/hotplug/acpiphp.h | 47 +- trunk/drivers/pci/hotplug/acpiphp_core.c | 9 +- trunk/drivers/pci/hotplug/acpiphp_glue.c | 882 +++++------ trunk/drivers/pci/hotplug/acpiphp_pci.c | 449 ++++++ trunk/drivers/pci/hotplug/acpiphp_res.c | 700 +++++++++ trunk/drivers/pci/hotplug/cpqphp_core.c | 5 +- trunk/drivers/pci/msi.c | 88 +- trunk/drivers/pci/msi.h | 9 +- trunk/drivers/pci/pci-sysfs.c | 26 +- trunk/drivers/pci/probe.c | 29 +- trunk/drivers/pci/proc.c | 14 +- trunk/drivers/pci/remove.c | 14 +- trunk/drivers/pci/setup-bus.c | 5 +- trunk/drivers/scsi/3w-9xxx.c | 8 +- trunk/drivers/scsi/3w-xxxx.c | 8 +- trunk/drivers/scsi/ahci.c | 22 +- trunk/drivers/scsi/ipr.c | 10 +- trunk/drivers/scsi/libata-core.c | 6 +- trunk/drivers/scsi/megaraid.c | 8 +- trunk/include/acpi/acpi_bus.h | 17 +- trunk/include/acpi/acpi_drivers.h | 1 - trunk/include/asm-alpha/pci.h | 19 - trunk/include/asm-arm/pci.h | 10 - trunk/include/asm-frv/pci.h | 10 - trunk/include/asm-i386/pci.h | 10 - trunk/include/asm-ia64/iosapic.h | 12 +- trunk/include/asm-ia64/pci.h | 19 - trunk/include/asm-mips/pci.h | 10 - trunk/include/asm-parisc/pci.h | 19 - trunk/include/asm-ppc/pci.h | 16 - trunk/include/asm-ppc64/pci.h | 26 - trunk/include/asm-sh/pci.h | 10 - trunk/include/asm-sh64/pci.h | 10 - trunk/include/asm-sparc/pci.h | 10 - trunk/include/asm-sparc64/pci.h | 19 - trunk/include/asm-v850/pci.h | 10 - trunk/include/asm-x86_64/pci.h | 10 - trunk/include/linux/acpi.h | 19 +- trunk/include/linux/etherdevice.h | 2 +- trunk/include/linux/pci.h | 33 +- trunk/include/linux/pci_ids.h | 2 - trunk/include/net/ieee80211.h | 48 +- trunk/init/main.c | 7 - trunk/kernel/kexec.c | 10 +- trunk/kernel/sched.c | 9 +- 91 files changed, 3424 insertions(+), 2587 deletions(-) create mode 100644 trunk/arch/arm/oprofile/backtrace.c create mode 100644 trunk/drivers/pci/hotplug/acpiphp_pci.c create mode 100644 trunk/drivers/pci/hotplug/acpiphp_res.c diff --git a/[refs] b/[refs] index 7b78cfec6798..cca3b71b3f54 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: adb2705a89e8b41abcf29c0ed86f4ce93ab36734 +refs/heads/master: fa0ebff62a8a25952a082641db0ed6b1cfc6c38c diff --git a/trunk/Documentation/DocBook/libata.tmpl b/trunk/Documentation/DocBook/libata.tmpl index 375ae760dc1e..6df1dfd18b65 100644 --- a/trunk/Documentation/DocBook/libata.tmpl +++ b/trunk/Documentation/DocBook/libata.tmpl @@ -84,14 +84,6 @@ void (*port_disable) (struct ata_port *); Called from ata_bus_probe() and ata_bus_reset() error paths, as well as when unregistering from the SCSI module (rmmod, hot unplug). - This function should do whatever needs to be done to take the - port out of use. In most cases, ata_port_disable() can be used - as this hook. - - - Called from ata_bus_probe() on a failed probe. - Called from ata_bus_reset() on a failed bus reset. - Called from ata_scsi_release(). @@ -106,13 +98,6 @@ void (*dev_config) (struct ata_port *, struct ata_device *); found. Typically used to apply device-specific fixups prior to issue of SET FEATURES - XFER MODE, and prior to operation. - - Called by ata_device_add() after ata_dev_identify() determines - a device is present. - - - This entry may be specified as NULL in ata_port_operations. - @@ -150,8 +135,6 @@ void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf); registers / DMA buffers. ->tf_read() is called to read the hardware registers / DMA buffers, to obtain the current set of taskfile register values. - Most drivers for taskfile-based hardware (PIO or MMIO) use - ata_tf_load() and ata_tf_read() for these hooks. @@ -164,8 +147,6 @@ void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf); causes an ATA command, previously loaded with ->tf_load(), to be initiated in hardware. - Most drivers for taskfile-based hardware use ata_exec_command() - for this hook. @@ -180,10 +161,6 @@ Allow low-level driver to filter ATA PACKET commands, returning a status indicating whether or not it is OK to use DMA for the supplied PACKET command. - - This hook may be specified as NULL, in which case libata will - assume that atapi dma can be supported. - @@ -198,14 +175,6 @@ u8 (*check_err)(struct ata_port *ap); Reads the Status/AltStatus/Error ATA shadow register from hardware. On some hardware, reading the Status register has the side effect of clearing the interrupt condition. - Most drivers for taskfile-based hardware use - ata_check_status() for this hook. - - - Note that because this is called from ata_device_add(), at - least a dummy function that clears device interrupts must be - provided for all drivers, even if the controller doesn't - actually have a taskfile status register. @@ -219,13 +188,7 @@ void (*dev_select)(struct ata_port *ap, unsigned int device); Issues the low-level hardware command(s) that causes one of N hardware devices to be considered 'selected' (active and available for use) on the ATA bus. This generally has no - meaning on FIS-based devices. - - - Most drivers for taskfile-based hardware use - ata_std_dev_select() for this hook. Controllers which do not - support second drives on a port (such as SATA contollers) will - use ata_noop_dev_select(). +meaning on FIS-based devices. @@ -241,8 +204,6 @@ void (*phy_reset) (struct ata_port *ap); for device presence (PATA and SATA), typically a soft reset (SRST) will be performed. Drivers typically use the helper functions ata_bus_reset() or sata_phy_reset() for this hook. - Many SATA drivers use sata_phy_reset() or call it from within - their own phy_reset() functions. @@ -266,25 +227,6 @@ PCI IDE DMA Status register. These hooks are typically either no-ops, or simply not implemented, in FIS-based drivers. - -Most legacy IDE drivers use ata_bmdma_setup() for the bmdma_setup() -hook. ata_bmdma_setup() will write the pointer to the PRD table to -the IDE PRD Table Address register, enable DMA in the DMA Command -register, and call exec_command() to begin the transfer. - - -Most legacy IDE drivers use ata_bmdma_start() for the bmdma_start() -hook. ata_bmdma_start() will write the ATA_DMA_START flag to the DMA -Command register. - - -Many legacy IDE drivers use ata_bmdma_stop() for the bmdma_stop() -hook. ata_bmdma_stop() clears the ATA_DMA_START flag in the DMA -command register. - - -Many legacy IDE drivers use ata_bmdma_status() as the bmdma_status() hook. - @@ -308,10 +250,6 @@ int (*qc_issue) (struct ata_queued_cmd *qc); helper function ata_qc_issue_prot() for taskfile protocol-based dispatch. More advanced drivers implement their own ->qc_issue. - - ata_qc_issue_prot() calls ->tf_load(), ->bmdma_setup(), and - ->bmdma_start() as necessary to initiate a transfer. - @@ -341,21 +279,6 @@ void (*irq_clear) (struct ata_port *); before the interrupt handler is registered, to be sure hardware is quiet. - - The second argument, dev_instance, should be cast to a pointer - to struct ata_host_set. - - - Most legacy IDE drivers use ata_interrupt() for the - irq_handler hook, which scans all ports in the host_set, - determines which queued command was active (if any), and calls - ata_host_intr(ap,qc). - - - Most legacy IDE drivers use ata_bmdma_irq_clear() for the - irq_clear() hook, which simply clears the interrupt and error - flags in the DMA status register. - @@ -369,7 +292,6 @@ void (*scr_write) (struct ata_port *ap, unsigned int sc_reg, Read and write standard SATA phy registers. Currently only used if ->phy_reset hook called the sata_phy_reset() helper function. - sc_reg is one of SCR_STATUS, SCR_CONTROL, SCR_ERROR, or SCR_ACTIVE. @@ -385,29 +307,17 @@ void (*host_stop) (struct ata_host_set *host_set); ->port_start() is called just after the data structures for each port are initialized. Typically this is used to alloc per-port DMA buffers / tables / rings, enable DMA engines, and similar - tasks. Some drivers also use this entry point as a chance to - allocate driver-private memory for ap->private_data. - - - Many drivers use ata_port_start() as this hook or call - it from their own port_start() hooks. ata_port_start() - allocates space for a legacy IDE PRD table and returns. + tasks. ->port_stop() is called after ->host_stop(). It's sole function is to release DMA/memory resources, now that they are no longer - actively being used. Many drivers also free driver-private - data from port at this time. - - - Many drivers use ata_port_stop() as this hook, which frees the - PRD table. + actively being used. ->host_stop() is called after all ->port_stop() calls have completed. The hook must finalize hardware shutdown, release DMA and other resources, etc. - This hook may be specified as NULL, in which case it is not called. diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index 0f71251f12b9..89cd417651e0 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -1030,10 +1030,6 @@ running once the system is up. irqmask=0xMMMM [IA-32] Set a bit mask of IRQs allowed to be assigned automatically to PCI devices. You can make the kernel exclude IRQs of your ISA cards this way. - pirqaddr=0xAAAAA [IA-32] Specify the physical address - of the PIRQ table (normally generated - by the BIOS) if it is outside the - F0000h-100000h range. lastbus=N [IA-32] Scan all buses till bus #N. Can be useful if the kernel is unable to find your secondary buses and you want to tell it explicitly which ones they are. diff --git a/trunk/arch/arm/oprofile/Makefile b/trunk/arch/arm/oprofile/Makefile index ba1a6e9f2b28..8ffb523e6c77 100644 --- a/trunk/arch/arm/oprofile/Makefile +++ b/trunk/arch/arm/oprofile/Makefile @@ -6,6 +6,6 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ oprofilefs.o oprofile_stats.o \ timer_int.o ) -oprofile-y := $(DRIVER_OBJS) init.o +oprofile-y := $(DRIVER_OBJS) init.o backtrace.o oprofile-$(CONFIG_CPU_XSCALE) += common.o op_model_xscale.o diff --git a/trunk/arch/arm/oprofile/backtrace.c b/trunk/arch/arm/oprofile/backtrace.c new file mode 100644 index 000000000000..ec58d3e2eb8b --- /dev/null +++ b/trunk/arch/arm/oprofile/backtrace.c @@ -0,0 +1,144 @@ +/* + * Arm specific backtracing code for oprofile + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * Based on i386 oprofile backtrace code by John Levon, David Smith + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include + + +/* + * The registers we're interested in are at the end of the variable + * length saved register structure. The fp points at the end of this + * structure so the address of this struct is: + * (struct frame_tail *)(xxx->fp)-1 + */ +struct frame_tail { + struct frame_tail *fp; + unsigned long sp; + unsigned long lr; +} __attribute__((packed)); + + +#ifdef CONFIG_FRAME_POINTER +static struct frame_tail* kernel_backtrace(struct frame_tail *tail) +{ + oprofile_add_trace(tail->lr); + + /* frame pointers should strictly progress back up the stack + * (towards higher addresses) */ + if (tail >= tail->fp) + return NULL; + + return tail->fp-1; +} +#endif + +static struct frame_tail* user_backtrace(struct frame_tail *tail) +{ + struct frame_tail buftail; + + /* hardware pte might not be valid due to dirty/accessed bit emulation + * so we use copy_from_user and benefit from exception fixups */ + if (copy_from_user(&buftail, tail, sizeof(struct frame_tail))) + return NULL; + + oprofile_add_trace(buftail.lr); + + /* frame pointers should strictly progress back up the stack + * (towards higher addresses) */ + if (tail >= buftail.fp) + return NULL; + + return buftail.fp-1; +} + +/* Compare two addresses and see if they're on the same page */ +#define CMP_ADDR_EQUAL(x,y,offset) ((((unsigned long) x) >> PAGE_SHIFT) \ + == ((((unsigned long) y) + offset) >> PAGE_SHIFT)) + +/* check that the page(s) containing the frame tail are present */ +static int pages_present(struct frame_tail *tail) +{ + struct mm_struct * mm = current->mm; + + if (!check_user_page_readable(mm, (unsigned long)tail)) + return 0; + + if (CMP_ADDR_EQUAL(tail, tail, 8)) + return 1; + + if (!check_user_page_readable(mm, ((unsigned long)tail) + 8)) + return 0; + + return 1; +} + +/* + * | | /\ Higher addresses + * | | + * --------------- stack base (address of current_thread_info) + * | thread info | + * . . + * | stack | + * --------------- saved regs->ARM_fp value if valid (frame_tail address) + * . . + * --------------- struct pt_regs stored on stack (struct pt_regs *) + * | | + * . . + * | | + * --------------- %esp + * | | + * | | \/ Lower addresses + * + * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values + */ +static int valid_kernel_stack(struct frame_tail *tail, struct pt_regs *regs) +{ + unsigned long tailaddr = (unsigned long)tail; + unsigned long stack = (unsigned long)regs; + unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE; + + return (tailaddr > stack) && (tailaddr < stack_base); +} + +void arm_backtrace(struct pt_regs const *regs, unsigned int depth) +{ + struct frame_tail *tail; + unsigned long last_address = 0; + + tail = ((struct frame_tail *) regs->ARM_fp) - 1; + + if (!user_mode(regs)) { + +#ifdef CONFIG_FRAME_POINTER + while (depth-- && tail && valid_kernel_stack(tail, regs)) { + tail = kernel_backtrace(tail); + } +#endif + return; + } + + while (depth-- && tail && !((unsigned long) tail & 3)) { + if ((!CMP_ADDR_EQUAL(last_address, tail, 0) + || !CMP_ADDR_EQUAL(last_address, tail, 8)) + && !pages_present(tail)) + return; + last_address = (unsigned long) tail; + tail = user_backtrace(tail); + } +} + diff --git a/trunk/arch/arm/oprofile/init.c b/trunk/arch/arm/oprofile/init.c index cce3d3015eb7..d315a3a86c86 100644 --- a/trunk/arch/arm/oprofile/init.c +++ b/trunk/arch/arm/oprofile/init.c @@ -20,6 +20,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) ret = pmu_init(ops, &op_xscale_spec); #endif + ops->backtrace = arm_backtrace; + return ret; } diff --git a/trunk/arch/arm/oprofile/op_arm_model.h b/trunk/arch/arm/oprofile/op_arm_model.h index 2d4caf4781ad..2148d07484b7 100644 --- a/trunk/arch/arm/oprofile/op_arm_model.h +++ b/trunk/arch/arm/oprofile/op_arm_model.h @@ -24,6 +24,8 @@ struct op_arm_model_spec { extern struct op_arm_model_spec op_xscale_spec; #endif +extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth); + extern int __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec); extern void pmu_exit(void); #endif /* OP_ARM_MODEL_H */ diff --git a/trunk/arch/i386/kernel/acpi/boot.c b/trunk/arch/i386/kernel/acpi/boot.c index b7808a89d945..9f63ae0f404b 100644 --- a/trunk/arch/i386/kernel/acpi/boot.c +++ b/trunk/arch/i386/kernel/acpi/boot.c @@ -159,15 +159,9 @@ char *__acpi_map_table(unsigned long phys, unsigned long size) #endif #ifdef CONFIG_PCI_MMCONFIG -/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ -struct acpi_table_mcfg_config *pci_mmcfg_config; -int pci_mmcfg_config_num; - -int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) +static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) { struct acpi_table_mcfg *mcfg; - unsigned long i; - int config_size; if (!phys_addr || !size) return -EINVAL; @@ -178,38 +172,18 @@ int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) return -ENODEV; } - /* 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)) { - ++pci_mmcfg_config_num; - i -= sizeof(struct acpi_table_mcfg_config); - }; - if (pci_mmcfg_config_num == 0) { - printk(KERN_ERR PREFIX "MMCONFIG has no entries\n"); + if (mcfg->base_reserved) { + printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n"); return -ENODEV; } - config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config); - pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL); - if (!pci_mmcfg_config) { - printk(KERN_WARNING PREFIX - "No memory for MCFG config tables\n"); - return -ENOMEM; - } - - memcpy(pci_mmcfg_config, &mcfg->config, config_size); - for (i = 0; i < pci_mmcfg_config_num; ++i) { - if (mcfg->config[i].base_reserved) { - printk(KERN_ERR PREFIX - "MMCONFIG not in low 4GB of memory\n"); - return -ENODEV; - } - } + pci_mmcfg_base_addr = mcfg->base_address; return 0; } -#endif /* CONFIG_PCI_MMCONFIG */ +#else +#define acpi_parse_mcfg NULL +#endif /* !CONFIG_PCI_MMCONFIG */ #ifdef CONFIG_X86_LOCAL_APIC static int __init @@ -533,22 +507,6 @@ acpi_unmap_lsapic(int cpu) EXPORT_SYMBOL(acpi_unmap_lsapic); #endif /* CONFIG_ACPI_HOTPLUG_CPU */ -int -acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base) -{ - /* TBD */ - return -EINVAL; -} -EXPORT_SYMBOL(acpi_register_ioapic); - -int -acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base) -{ - /* TBD */ - return -EINVAL; -} -EXPORT_SYMBOL(acpi_unregister_ioapic); - static unsigned long __init acpi_scan_rsdp ( unsigned long start, @@ -1165,6 +1123,7 @@ int __init acpi_boot_init(void) acpi_process_madt(); acpi_table_parse(ACPI_HPET, acpi_parse_hpet); + acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); return 0; } diff --git a/trunk/arch/i386/pci/common.c b/trunk/arch/i386/pci/common.c index 87325263cd4f..720975e1af50 100644 --- a/trunk/arch/i386/pci/common.c +++ b/trunk/arch/i386/pci/common.c @@ -25,8 +25,7 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | int pci_routeirq; int pcibios_last_bus = -1; -unsigned long pirq_table_addr; -struct pci_bus *pci_root_bus; +struct pci_bus *pci_root_bus = NULL; struct pci_raw_ops *raw_pci_ops; static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) @@ -134,7 +133,7 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum) printk("PCI: Probing PCI hardware (bus %02x)\n", busnum); - return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, NULL); + return pci_scan_bus(busnum, &pci_root_ops, NULL); } extern u8 pci_cache_line_size; @@ -189,9 +188,6 @@ char * __devinit pcibios_setup(char *str) } else if (!strcmp(str, "biosirq")) { pci_probe |= PCI_BIOS_IRQ_SCAN; return NULL; - } else if (!strncmp(str, "pirqaddr=", 9)) { - pirq_table_addr = simple_strtoul(str+9, NULL, 0); - return NULL; } #endif #ifdef CONFIG_PCI_DIRECT diff --git a/trunk/arch/i386/pci/irq.c b/trunk/arch/i386/pci/irq.c index 78ca1ecbb907..83458f81e661 100644 --- a/trunk/arch/i386/pci/irq.c +++ b/trunk/arch/i386/pci/irq.c @@ -57,35 +57,6 @@ struct irq_router_handler { int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL; -/* - * Check passed address for the PCI IRQ Routing Table signature - * and perform checksum verification. - */ - -static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr) -{ - struct irq_routing_table *rt; - int i; - u8 sum; - - rt = (struct irq_routing_table *) addr; - if (rt->signature != PIRQ_SIGNATURE || - rt->version != PIRQ_VERSION || - rt->size % 16 || - rt->size < sizeof(struct irq_routing_table)) - return NULL; - sum = 0; - for (i=0; i < rt->size; i++) - sum += addr[i]; - if (!sum) { - DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt); - return rt; - } - return NULL; -} - - - /* * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. */ @@ -94,17 +65,23 @@ static struct irq_routing_table * __init pirq_find_routing_table(void) { u8 *addr; struct irq_routing_table *rt; + int i; + u8 sum; - if (pirq_table_addr) { - rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr)); - if (rt) - return rt; - printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n"); - } for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) { - rt = pirq_check_routing_table(addr); - if (rt) + rt = (struct irq_routing_table *) addr; + if (rt->signature != PIRQ_SIGNATURE || + rt->version != PIRQ_VERSION || + rt->size % 16 || + rt->size < sizeof(struct irq_routing_table)) + continue; + sum = 0; + for(i=0; isize; i++) + sum += addr[i]; + if (!sum) { + DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt); return rt; + } } return NULL; } diff --git a/trunk/arch/i386/pci/legacy.c b/trunk/arch/i386/pci/legacy.c index 149a9588c256..1492e3753869 100644 --- a/trunk/arch/i386/pci/legacy.c +++ b/trunk/arch/i386/pci/legacy.c @@ -45,8 +45,6 @@ static int __init pci_legacy_init(void) printk("PCI: Probing PCI hardware\n"); pci_root_bus = pcibios_scan_root(0); - if (pci_root_bus) - pci_bus_add_devices(pci_root_bus); pcibios_fixup_peer_bridges(); diff --git a/trunk/arch/i386/pci/mmconfig.c b/trunk/arch/i386/pci/mmconfig.c index 60f0e7a1162a..021a50aa51f4 100644 --- a/trunk/arch/i386/pci/mmconfig.c +++ b/trunk/arch/i386/pci/mmconfig.c @@ -11,9 +11,11 @@ #include #include -#include #include "pci.h" +/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ +u32 pci_mmcfg_base_addr; + #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) /* The base address of the last MMCONFIG device accessed */ @@ -22,31 +24,10 @@ static u32 mmcfg_last_accessed_device; /* * Functions for accessing PCI configuration space with MMCONFIG accesses */ -static u32 get_base_addr(unsigned int seg, int bus) -{ - int cfg_num = -1; - struct acpi_table_mcfg_config *cfg; - - while (1) { - ++cfg_num; - if (cfg_num >= pci_mmcfg_config_num) { - /* something bad is going on, no cfg table is found. */ - /* so we fall back to the old way we used to do this */ - /* and just rely on the first entry to be correct. */ - return pci_mmcfg_config[0].base_address; - } - cfg = &pci_mmcfg_config[cfg_num]; - if (cfg->pci_segment_group_number != seg) - continue; - if ((cfg->start_bus_number <= bus) && - (cfg->end_bus_number >= bus)) - return cfg->base_address; - } -} -static inline void pci_exp_set_dev_base(unsigned int seg, int bus, int devfn) +static inline void pci_exp_set_dev_base(int bus, int devfn) { - u32 dev_base = get_base_addr(seg, bus) | (bus << 20) | (devfn << 12); + u32 dev_base = pci_mmcfg_base_addr | (bus << 20) | (devfn << 12); if (dev_base != mmcfg_last_accessed_device) { mmcfg_last_accessed_device = dev_base; set_fixmap_nocache(FIX_PCIE_MCFG, dev_base); @@ -63,7 +44,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus, spin_lock_irqsave(&pci_config_lock, flags); - pci_exp_set_dev_base(seg, bus, devfn); + pci_exp_set_dev_base(bus, devfn); switch (len) { case 1: @@ -92,7 +73,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus, spin_lock_irqsave(&pci_config_lock, flags); - pci_exp_set_dev_base(seg, bus, devfn); + pci_exp_set_dev_base(bus, devfn); switch (len) { case 1: @@ -120,11 +101,7 @@ static int __init pci_mmcfg_init(void) { if ((pci_probe & PCI_PROBE_MMCONF) == 0) goto out; - - acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); - if ((pci_mmcfg_config_num == 0) || - (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].base_address == 0)) + if (!pci_mmcfg_base_addr) goto out; /* Kludge for now. Don't use mmconfig on AMD systems because diff --git a/trunk/arch/i386/pci/numa.c b/trunk/arch/i386/pci/numa.c index adbe17a38f6f..9e3695461899 100644 --- a/trunk/arch/i386/pci/numa.c +++ b/trunk/arch/i386/pci/numa.c @@ -115,8 +115,6 @@ static int __init pci_numa_init(void) return 0; pci_root_bus = pcibios_scan_root(0); - if (pci_root_bus) - pci_bus_add_devices(pci_root_bus); if (num_online_nodes() > 1) for_each_online_node(quad) { if (quad == 0) diff --git a/trunk/arch/i386/pci/pci.h b/trunk/arch/i386/pci/pci.h index a80f0f55ff51..a8fc80ca69f3 100644 --- a/trunk/arch/i386/pci/pci.h +++ b/trunk/arch/i386/pci/pci.h @@ -27,7 +27,6 @@ #define PCI_ASSIGN_ALL_BUSSES 0x4000 extern unsigned int pci_probe; -extern unsigned long pirq_table_addr; /* pci-i386.c */ diff --git a/trunk/arch/ia64/kernel/acpi.c b/trunk/arch/ia64/kernel/acpi.c index cda06f88c66e..72dfd9e7de0f 100644 --- a/trunk/arch/ia64/kernel/acpi.c +++ b/trunk/arch/ia64/kernel/acpi.c @@ -236,7 +236,9 @@ acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end) if (BAD_MADT_ENTRY(iosapic, end)) return -EINVAL; - return iosapic_init(iosapic->address, iosapic->global_irq_base); + iosapic_init(iosapic->address, iosapic->global_irq_base); + + return 0; } @@ -770,7 +772,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic); #ifdef CONFIG_ACPI_NUMA -acpi_status __devinit +acpi_status __init acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) { struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; @@ -823,28 +825,4 @@ acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) return AE_OK; } #endif /* CONFIG_NUMA */ - -int -acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base) -{ - int err; - - if ((err = iosapic_init(phys_addr, gsi_base))) - return err; - -#if CONFIG_ACPI_NUMA - acpi_map_iosapic(handle, 0, NULL, NULL); -#endif /* CONFIG_ACPI_NUMA */ - - return 0; -} -EXPORT_SYMBOL(acpi_register_ioapic); - -int -acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base) -{ - return iosapic_remove(gsi_base); -} -EXPORT_SYMBOL(acpi_unregister_ioapic); - #endif /* CONFIG_ACPI_BOOT */ diff --git a/trunk/arch/ia64/kernel/iosapic.c b/trunk/arch/ia64/kernel/iosapic.c index c170be095ccd..88b014381df5 100644 --- a/trunk/arch/ia64/kernel/iosapic.c +++ b/trunk/arch/ia64/kernel/iosapic.c @@ -129,13 +129,14 @@ static struct iosapic { char __iomem *addr; /* base address of IOSAPIC */ unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ unsigned short num_rte; /* number of RTE in this IOSAPIC */ - int rtes_inuse; /* # of RTEs in use on this IOSAPIC */ #ifdef CONFIG_NUMA unsigned short node; /* numa node association via pxm */ #endif } iosapic_lists[NR_IOSAPICS]; -static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */ +static int num_iosapic; + +static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */ static int iosapic_kmalloc_ok; static LIST_HEAD(free_rte_list); @@ -148,7 +149,7 @@ find_iosapic (unsigned int gsi) { int i; - for (i = 0; i < NR_IOSAPICS; i++) { + for (i = 0; i < num_iosapic; i++) { if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) return i; } @@ -597,7 +598,6 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, rte->refcnt++; list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes); iosapic_intr_info[vector].count++; - iosapic_lists[index].rtes_inuse++; } else if (vector_is_shared(vector)) { struct iosapic_intr_info *info = &iosapic_intr_info[vector]; @@ -778,7 +778,7 @@ void iosapic_unregister_intr (unsigned int gsi) { unsigned long flags; - int irq, vector, index; + int irq, vector; irq_desc_t *idesc; u32 low32; unsigned long trigger, polarity; @@ -819,9 +819,6 @@ iosapic_unregister_intr (unsigned int gsi) list_del(&rte->rte_list); iosapic_intr_info[vector].count--; iosapic_free_rte(rte); - index = find_iosapic(gsi); - iosapic_lists[index].rtes_inuse--; - WARN_ON(iosapic_lists[index].rtes_inuse < 0); trigger = iosapic_intr_info[vector].trigger; polarity = iosapic_intr_info[vector].polarity; @@ -955,86 +952,30 @@ iosapic_system_init (int system_pcat_compat) } } -static inline int -iosapic_alloc (void) -{ - int index; - - for (index = 0; index < NR_IOSAPICS; index++) - if (!iosapic_lists[index].addr) - return index; - - printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__); - return -1; -} - -static inline void -iosapic_free (int index) -{ - memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0])); -} - -static inline int -iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver) -{ - int index; - unsigned int gsi_end, base, end; - - /* check gsi range */ - gsi_end = gsi_base + ((ver >> 16) & 0xff); - for (index = 0; index < NR_IOSAPICS; index++) { - if (!iosapic_lists[index].addr) - continue; - - base = iosapic_lists[index].gsi_base; - end = base + iosapic_lists[index].num_rte - 1; - - if (gsi_base < base && gsi_end < base) - continue;/* OK */ - - if (gsi_base > end && gsi_end > end) - continue; /* OK */ - - return -EBUSY; - } - return 0; -} - -int __devinit +void __init iosapic_init (unsigned long phys_addr, unsigned int gsi_base) { - int num_rte, err, index; + int num_rte; unsigned int isa_irq, ver; char __iomem *addr; - unsigned long flags; - - spin_lock_irqsave(&iosapic_lock, flags); - { - addr = ioremap(phys_addr, 0); - ver = iosapic_version(addr); - if ((err = iosapic_check_gsi_range(gsi_base, ver))) { - iounmap(addr); - spin_unlock_irqrestore(&iosapic_lock, flags); - return err; - } + addr = ioremap(phys_addr, 0); + ver = iosapic_version(addr); - /* - * The MAX_REDIR register holds the highest input pin - * number (starting from 0). - * We add 1 so that we can use it for number of pins (= RTEs) - */ - num_rte = ((ver >> 16) & 0xff) + 1; + /* + * The MAX_REDIR register holds the highest input pin + * number (starting from 0). + * We add 1 so that we can use it for number of pins (= RTEs) + */ + num_rte = ((ver >> 16) & 0xff) + 1; - index = iosapic_alloc(); - iosapic_lists[index].addr = addr; - iosapic_lists[index].gsi_base = gsi_base; - iosapic_lists[index].num_rte = num_rte; + iosapic_lists[num_iosapic].addr = addr; + iosapic_lists[num_iosapic].gsi_base = gsi_base; + iosapic_lists[num_iosapic].num_rte = num_rte; #ifdef CONFIG_NUMA - iosapic_lists[index].node = MAX_NUMNODES; + iosapic_lists[num_iosapic].node = MAX_NUMNODES; #endif - } - spin_unlock_irqrestore(&iosapic_lock, flags); + num_iosapic++; if ((gsi_base == 0) && pcat_compat) { /* @@ -1045,43 +986,10 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) for (isa_irq = 0; isa_irq < 16; ++isa_irq) iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); } - return 0; -} - -#ifdef CONFIG_HOTPLUG -int -iosapic_remove (unsigned int gsi_base) -{ - int index, err = 0; - unsigned long flags; - - spin_lock_irqsave(&iosapic_lock, flags); - { - index = find_iosapic(gsi_base); - if (index < 0) { - printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n", - __FUNCTION__, gsi_base); - goto out; - } - - if (iosapic_lists[index].rtes_inuse) { - err = -EBUSY; - printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n", - __FUNCTION__, gsi_base); - goto out; - } - - iounmap(iosapic_lists[index].addr); - iosapic_free(index); - } - out: - spin_unlock_irqrestore(&iosapic_lock, flags); - return err; } -#endif /* CONFIG_HOTPLUG */ #ifdef CONFIG_NUMA -void __devinit +void __init map_iosapic_to_node(unsigned int gsi_base, int node) { int index; diff --git a/trunk/arch/ia64/pci/pci.c b/trunk/arch/ia64/pci/pci.c index 720a861f88be..e3fc4edea113 100644 --- a/trunk/arch/ia64/pci/pci.c +++ b/trunk/arch/ia64/pci/pci.c @@ -312,7 +312,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus) acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window, &info); - pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller); + pbus = pci_scan_bus(bus, &pci_root_ops, controller); if (pbus) pcibios_setup_root_windows(pbus, controller); @@ -373,25 +373,6 @@ void pcibios_bus_to_resource(struct pci_dev *dev, res->end = region->end + offset; } -static int __devinit is_valid_resource(struct pci_dev *dev, int idx) -{ - unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; - struct resource *devr = &dev->resource[idx]; - - if (!dev->bus) - return 0; - for (i=0; ibus->resource[i]; - - if (!busr || ((busr->flags ^ devr->flags) & type_mask)) - continue; - if ((devr->start) && (devr->start >= busr->start) && - (devr->end <= busr->end)) - return 1; - } - return 0; -} - static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) { struct pci_bus_region region; @@ -405,8 +386,7 @@ static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) region.start = dev->resource[i].start; region.end = dev->resource[i].end; pcibios_bus_to_resource(dev, &dev->resource[i], ®ion); - if ((is_valid_resource(dev, i))) - pci_claim_resource(dev, i); + pci_claim_resource(dev, i); } } @@ -418,10 +398,6 @@ pcibios_fixup_bus (struct pci_bus *b) { struct pci_dev *dev; - if (b->self) { - pci_read_bridge_bases(b); - pcibios_fixup_device_resources(b->self); - } list_for_each_entry(dev, &b->devices, bus_list) pcibios_fixup_device_resources(dev); @@ -442,24 +418,18 @@ pcibios_enable_resources (struct pci_dev *dev, int mask) u16 cmd, old_cmd; int idx; struct resource *r; - unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; if (!dev) return -EINVAL; pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; - for (idx=0; idxresource[idx]; - if (!(r->flags & type_mask)) - continue; - if ((idx == PCI_ROM_RESOURCE) && - (!(r->flags & IORESOURCE_ROM_ENABLE))) - continue; if (!r->start && r->end) { printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", @@ -471,6 +441,8 @@ pcibios_enable_resources (struct pci_dev *dev, int mask) if (r->flags & IORESOURCE_MEM) cmd |= PCI_COMMAND_MEMORY; } + if (dev->resource[PCI_ROM_RESOURCE].start) + cmd |= PCI_COMMAND_MEMORY; if (cmd != old_cmd) { printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd); pci_write_config_word(dev, PCI_COMMAND, cmd); diff --git a/trunk/arch/ppc/kernel/pci.c b/trunk/arch/ppc/kernel/pci.c index 70cfb6ffd877..6d7b92d72458 100644 --- a/trunk/arch/ppc/kernel/pci.c +++ b/trunk/arch/ppc/kernel/pci.c @@ -1495,7 +1495,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, *offset += hose->pci_mem_offset; res_bit = IORESOURCE_MEM; } else { - io_offset = hose->io_base_virt - ___IO_BASE; + io_offset = (unsigned long)hose->io_base_virt; *offset += io_offset; res_bit = IORESOURCE_IO; } @@ -1522,7 +1522,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, /* found it! construct the final physical address */ if (mmap_state == pci_mmap_io) - *offset += hose->io_base_phys - io_offset; + *offset += hose->io_base_phys - _IO_BASE; return rp; } @@ -1739,23 +1739,6 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) return result; } -void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, - u64 *start, u64 *end) -{ - struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); - unsigned long offset = 0; - - if (hose == NULL) - return; - - if (rsrc->flags & IORESOURCE_IO) - offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys; - - *start = rsrc->start + offset; - *end = rsrc->end + offset; -} - void __init pci_init_resource(struct resource *res, unsigned long start, unsigned long end, int flags, char *name) diff --git a/trunk/arch/ppc64/kernel/pci.c b/trunk/arch/ppc64/kernel/pci.c index ae6f579d3fa0..580676f87d23 100644 --- a/trunk/arch/ppc64/kernel/pci.c +++ b/trunk/arch/ppc64/kernel/pci.c @@ -351,7 +351,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, *offset += hose->pci_mem_offset; res_bit = IORESOURCE_MEM; } else { - io_offset = (unsigned long)hose->io_base_virt - pci_io_base; + io_offset = (unsigned long)hose->io_base_virt; *offset += io_offset; res_bit = IORESOURCE_IO; } @@ -378,7 +378,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, /* found it! construct the final physical address */ if (mmap_state == pci_mmap_io) - *offset += hose->io_base_phys - io_offset; + *offset += hose->io_base_phys - io_offset; return rp; } @@ -944,22 +944,4 @@ int pci_read_irq_line(struct pci_dev *pci_dev) } EXPORT_SYMBOL(pci_read_irq_line); -void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, - u64 *start, u64 *end) -{ - struct pci_controller *hose = pci_bus_to_host(dev->bus); - unsigned long offset = 0; - - if (hose == NULL) - return; - - if (rsrc->flags & IORESOURCE_IO) - offset = pci_io_base - (unsigned long)hose->io_base_virt + - hose->io_base_phys; - - *start = rsrc->start + offset; - *end = rsrc->end + offset; -} - #endif /* CONFIG_PPC_MULTIPLATFORM */ diff --git a/trunk/arch/x86_64/pci/mmconfig.c b/trunk/arch/x86_64/pci/mmconfig.c index 657e88aa0902..b693c232fd07 100644 --- a/trunk/arch/x86_64/pci/mmconfig.c +++ b/trunk/arch/x86_64/pci/mmconfig.c @@ -7,50 +7,25 @@ #include #include -#include #include "pci.h" #define MMCONFIG_APER_SIZE (256*1024*1024) +/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ +u32 pci_mmcfg_base_addr; + /* Static virtual mapping of the MMCONFIG aperture */ -struct mmcfg_virt { - struct acpi_table_mcfg_config *cfg; - char *virt; -}; -static struct mmcfg_virt *pci_mmcfg_virt; +char *pci_mmcfg_virt; -static char *get_virt(unsigned int seg, int bus) +static inline char *pci_dev_base(unsigned int bus, unsigned int devfn) { - int cfg_num = -1; - struct acpi_table_mcfg_config *cfg; - - while (1) { - ++cfg_num; - if (cfg_num >= pci_mmcfg_config_num) { - /* something bad is going on, no cfg table is found. */ - /* so we fall back to the old way we used to do this */ - /* and just rely on the first entry to be correct. */ - return pci_mmcfg_virt[0].virt; - } - cfg = pci_mmcfg_virt[cfg_num].cfg; - if (cfg->pci_segment_group_number != seg) - continue; - if ((cfg->start_bus_number <= bus) && - (cfg->end_bus_number >= bus)) - return pci_mmcfg_virt[cfg_num].virt; - } -} - -static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) -{ - - return get_virt(seg, bus) + ((bus << 20) | (devfn << 12)); + return pci_mmcfg_virt + ((bus << 20) | (devfn << 12)); } static int pci_mmcfg_read(unsigned int seg, unsigned int bus, unsigned int devfn, int reg, int len, u32 *value) { - char *addr = pci_dev_base(seg, bus, devfn); + char *addr = pci_dev_base(bus, devfn); if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095))) return -EINVAL; @@ -73,7 +48,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus, static int pci_mmcfg_write(unsigned int seg, unsigned int bus, unsigned int devfn, int reg, int len, u32 value) { - char *addr = pci_dev_base(seg, bus, devfn); + char *addr = pci_dev_base(bus,devfn); if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) return -EINVAL; @@ -100,15 +75,9 @@ static struct pci_raw_ops pci_mmcfg = { static int __init pci_mmcfg_init(void) { - int i; - if ((pci_probe & PCI_PROBE_MMCONF) == 0) return 0; - - acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); - if ((pci_mmcfg_config_num == 0) || - (pci_mmcfg_config == NULL) || - (pci_mmcfg_config[0].base_address == 0)) + if (!pci_mmcfg_base_addr) return 0; /* Kludge for now. Don't use mmconfig on AMD systems because @@ -119,22 +88,13 @@ static int __init pci_mmcfg_init(void) return 0; /* RED-PEN i386 doesn't do _nocache right now */ - pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL); - if (pci_mmcfg_virt == NULL) { - printk("PCI: Can not allocate memory for mmconfig structures\n"); + pci_mmcfg_virt = ioremap_nocache(pci_mmcfg_base_addr, MMCONFIG_APER_SIZE); + if (!pci_mmcfg_virt) { + printk("PCI: Cannot map mmconfig aperture\n"); return 0; - } - 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, MMCONFIG_APER_SIZE); - if (!pci_mmcfg_virt[i].virt) { - printk("PCI: Cannot map mmconfig aperture for segment %d\n", - pci_mmcfg_config[i].pci_segment_group_number); - return 0; - } - printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address); - } + } + printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_base_addr); raw_pci_ops = &pci_mmcfg; pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; diff --git a/trunk/drivers/acpi/container.c b/trunk/drivers/acpi/container.c index 97013ddfa202..5a0adbf8bc04 100644 --- a/trunk/drivers/acpi/container.c +++ b/trunk/drivers/acpi/container.c @@ -153,7 +153,7 @@ container_device_add(struct acpi_device **device, acpi_handle handle) return_VALUE(-ENODEV); } - result = acpi_bus_start(*device); + result = acpi_bus_scan(*device); return_VALUE(result); } diff --git a/trunk/drivers/acpi/pci_bind.c b/trunk/drivers/acpi/pci_bind.c index 5148f3c10b5c..5d19b39e9e2b 100644 --- a/trunk/drivers/acpi/pci_bind.c +++ b/trunk/drivers/acpi/pci_bind.c @@ -61,14 +61,15 @@ acpi_pci_data_handler ( /** - * acpi_get_pci_id + * acpi_os_get_pci_id * ------------------ * This function is used by the ACPI Interpreter (a.k.a. Core Subsystem) * to resolve PCI information for ACPI-PCI devices defined in the namespace. * This typically occurs when resolving PCI operation region information. */ +#ifdef ACPI_FUTURE_USAGE acpi_status -acpi_get_pci_id ( +acpi_os_get_pci_id ( acpi_handle handle, struct acpi_pci_id *id) { @@ -77,7 +78,7 @@ acpi_get_pci_id ( struct acpi_device *device = NULL; struct acpi_pci_data *data = NULL; - ACPI_FUNCTION_TRACE("acpi_get_pci_id"); + ACPI_FUNCTION_TRACE("acpi_os_get_pci_id"); if (!id) return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -91,7 +92,7 @@ acpi_get_pci_id ( } status = acpi_get_data(handle, acpi_pci_data_handler, (void**) &data); - if (ACPI_FAILURE(status) || !data) { + if (ACPI_FAILURE(status) || !data || !data->dev) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid ACPI-PCI context for device %s\n", acpi_device_bid(device))); @@ -114,7 +115,7 @@ acpi_get_pci_id ( return_ACPI_STATUS(AE_OK); } -EXPORT_SYMBOL(acpi_get_pci_id); +#endif /* ACPI_FUTURE_USAGE */ int @@ -128,8 +129,6 @@ acpi_pci_bind ( char *pathname = NULL; struct acpi_buffer buffer = {0, NULL}; acpi_handle handle = NULL; - struct pci_dev *dev; - struct pci_bus *bus; ACPI_FUNCTION_TRACE("acpi_pci_bind"); @@ -194,20 +193,8 @@ acpi_pci_bind ( * Locate matching device in PCI namespace. If it doesn't exist * this typically means that the device isn't currently inserted * (e.g. docking station, port replicator, etc.). - * We cannot simply search the global pci device list, since - * PCI devices are added to the global pci list when the root - * bridge start ops are run, which may not have happened yet. */ - bus = pci_find_bus(data->id.segment, data->id.bus); - if (bus) { - list_for_each_entry(dev, &bus->devices, bus_list) { - if (dev->devfn == PCI_DEVFN(data->id.device, - data->id.function)) { - data->dev = dev; - break; - } - } - } + data->dev = pci_find_slot(data->id.bus, PCI_DEVFN(data->id.device, data->id.function)); if (!data->dev) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %02x:%02x:%02x.%02x not present in PCI namespace\n", diff --git a/trunk/drivers/acpi/pci_root.c b/trunk/drivers/acpi/pci_root.c index 5d2f77fcd50c..7e6b8e3b2ed4 100644 --- a/trunk/drivers/acpi/pci_root.c +++ b/trunk/drivers/acpi/pci_root.c @@ -46,7 +46,6 @@ ACPI_MODULE_NAME ("pci_root") static int acpi_pci_root_add (struct acpi_device *device); static int acpi_pci_root_remove (struct acpi_device *device, int type); -static int acpi_pci_root_start (struct acpi_device *device); static struct acpi_driver acpi_pci_root_driver = { .name = ACPI_PCI_ROOT_DRIVER_NAME, @@ -55,7 +54,6 @@ static struct acpi_driver acpi_pci_root_driver = { .ops = { .add = acpi_pci_root_add, .remove = acpi_pci_root_remove, - .start = acpi_pci_root_start, }, }; @@ -171,7 +169,6 @@ acpi_pci_root_add ( if (!root) return_VALUE(-ENOMEM); memset(root, 0, sizeof(struct acpi_pci_root)); - INIT_LIST_HEAD(&root->node); root->handle = device->handle; strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); @@ -301,31 +298,12 @@ acpi_pci_root_add ( root->id.bus); end: - if (result) { - if (!list_empty(&root->node)) - list_del(&root->node); + if (result) kfree(root); - } return_VALUE(result); } -static int -acpi_pci_root_start ( - struct acpi_device *device) -{ - struct acpi_pci_root *root; - - ACPI_FUNCTION_TRACE("acpi_pci_root_start"); - - list_for_each_entry(root, &acpi_pci_roots, node) { - if (root->handle == device->handle) { - pci_bus_add_devices(root->bus); - return_VALUE(0); - } - } - return_VALUE(-ENODEV); -} static int acpi_pci_root_remove ( diff --git a/trunk/drivers/acpi/processor_core.c b/trunk/drivers/acpi/processor_core.c index 76156ac91bd3..f4778747e889 100644 --- a/trunk/drivers/acpi/processor_core.c +++ b/trunk/drivers/acpi/processor_core.c @@ -723,7 +723,7 @@ int acpi_processor_device_add( return_VALUE(-ENODEV); } - acpi_bus_start(*device); + acpi_bus_scan(*device); pr = acpi_driver_data(*device); if (!pr) diff --git a/trunk/drivers/acpi/scan.c b/trunk/drivers/acpi/scan.c index 337d49b5564b..e85885593280 100644 --- a/trunk/drivers/acpi/scan.c +++ b/trunk/drivers/acpi/scan.c @@ -553,29 +553,20 @@ acpi_bus_driver_init ( * upon possible configuration and currently allocated resources. */ - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); - return_VALUE(0); -} - -int -acpi_start_single_object ( - struct acpi_device *device) -{ - int result = 0; - struct acpi_driver *driver; - - ACPI_FUNCTION_TRACE("acpi_start_single_object"); - - if (!(driver = device->driver)) - return_VALUE(0); - if (driver->ops.start) { result = driver->ops.start(device); if (result && driver->ops.remove) driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); + return_VALUE(result); } - return_VALUE(result); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); + + if (driver->ops.scan) { + driver->ops.scan(device); + } + + return_VALUE(0); } static int acpi_driver_attach(struct acpi_driver * drv) @@ -595,7 +586,6 @@ static int acpi_driver_attach(struct acpi_driver * drv) if (!acpi_bus_match(dev, drv)) { if (!acpi_bus_driver_init(dev, drv)) { - acpi_start_single_object(dev); atomic_inc(&drv->references); count++; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", @@ -1019,8 +1009,8 @@ acpi_bus_remove ( } -static int -acpi_add_single_object ( +int +acpi_bus_add ( struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, @@ -1029,7 +1019,7 @@ acpi_add_single_object ( int result = 0; struct acpi_device *device = NULL; - ACPI_FUNCTION_TRACE("acpi_add_single_object"); + ACPI_FUNCTION_TRACE("acpi_bus_add"); if (!child) return_VALUE(-EINVAL); @@ -1150,7 +1140,7 @@ acpi_add_single_object ( * * TBD: Assumes LDM provides driver hot-plug capability. */ - result = acpi_bus_find_driver(device); + acpi_bus_find_driver(device); end: if (!result) @@ -1163,10 +1153,10 @@ acpi_add_single_object ( return_VALUE(result); } +EXPORT_SYMBOL(acpi_bus_add); -static int acpi_bus_scan (struct acpi_device *start, - struct acpi_bus_ops *ops) +int acpi_bus_scan (struct acpi_device *start) { acpi_status status = AE_OK; struct acpi_device *parent = NULL; @@ -1239,20 +1229,9 @@ static int acpi_bus_scan (struct acpi_device *start, continue; } - if (ops->acpi_op_add) - status = acpi_add_single_object(&child, parent, - chandle, type); - else - status = acpi_bus_get_device(chandle, &child); - - if (ACPI_FAILURE(status)) - continue; - - if (ops->acpi_op_start) { - status = acpi_start_single_object(child); - if (ACPI_FAILURE(status)) - continue; - } + status = acpi_bus_add(&child, parent, chandle, type); + if (ACPI_FAILURE(status)) + continue; /* * If the device is present, enabled, and functioning then @@ -1278,50 +1257,8 @@ static int acpi_bus_scan (struct acpi_device *start, return_VALUE(0); } +EXPORT_SYMBOL(acpi_bus_scan); -int -acpi_bus_add ( - struct acpi_device **child, - struct acpi_device *parent, - acpi_handle handle, - int type) -{ - int result; - struct acpi_bus_ops ops; - - ACPI_FUNCTION_TRACE("acpi_bus_add"); - - result = acpi_add_single_object(child, parent, handle, type); - if (!result) { - memset(&ops, 0, sizeof(ops)); - ops.acpi_op_add = 1; - result = acpi_bus_scan(*child, &ops); - } - return_VALUE(result); -} -EXPORT_SYMBOL(acpi_bus_add); - -int -acpi_bus_start ( - struct acpi_device *device) -{ - int result; - struct acpi_bus_ops ops; - - ACPI_FUNCTION_TRACE("acpi_bus_start"); - - if (!device) - return_VALUE(-EINVAL); - - result = acpi_start_single_object(device); - if (!result) { - memset(&ops, 0, sizeof(ops)); - ops.acpi_op_start = 1; - result = acpi_bus_scan(device, &ops); - } - return_VALUE(result); -} -EXPORT_SYMBOL(acpi_bus_start); static int acpi_bus_trim(struct acpi_device *start, @@ -1394,19 +1331,13 @@ acpi_bus_scan_fixed ( /* * Enumerate all fixed-feature devices. */ - if (acpi_fadt.pwr_button == 0) { - result = acpi_add_single_object(&device, acpi_root, + if (acpi_fadt.pwr_button == 0) + result = acpi_bus_add(&device, acpi_root, NULL, ACPI_BUS_TYPE_POWER_BUTTON); - if (!result) - result = acpi_start_single_object(device); - } - if (acpi_fadt.sleep_button == 0) { - result = acpi_add_single_object(&device, acpi_root, + if (acpi_fadt.sleep_button == 0) + result = acpi_bus_add(&device, acpi_root, NULL, ACPI_BUS_TYPE_SLEEP_BUTTON); - if (!result) - result = acpi_start_single_object(device); - } return_VALUE(result); } @@ -1415,7 +1346,6 @@ acpi_bus_scan_fixed ( static int __init acpi_scan_init(void) { int result; - struct acpi_bus_ops ops; ACPI_FUNCTION_TRACE("acpi_scan_init"); @@ -1427,23 +1357,17 @@ 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, + result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_SYSTEM); if (result) goto Done; - result = acpi_start_single_object(acpi_root); - /* * 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; - result = acpi_bus_scan(acpi_root, &ops); - } + if (!result) + result = acpi_bus_scan(acpi_root); if (result) acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); diff --git a/trunk/drivers/block/cciss.c b/trunk/drivers/block/cciss.c index 3e9fb6e4a52a..653512b77570 100644 --- a/trunk/drivers/block/cciss.c +++ b/trunk/drivers/block/cciss.c @@ -786,6 +786,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, case CCISS_GETLUNINFO: { LogvolInfo_struct luninfo; + int i; luninfo.LunID = drv->LunID; luninfo.num_opens = drv->usage_count; diff --git a/trunk/drivers/block/ll_rw_blk.c b/trunk/drivers/block/ll_rw_blk.c index 6c98cf042714..234fdcfbdf01 100644 --- a/trunk/drivers/block/ll_rw_blk.c +++ b/trunk/drivers/block/ll_rw_blk.c @@ -1912,15 +1912,6 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, } get_rq: - /* - * Only allow batching queuers to allocate up to 50% over the defined - * limit of requests, otherwise we could have thousands of requests - * allocated with any setting of ->nr_requests - */ - if (rl->count[rw] >= (3 * q->nr_requests / 2)) { - spin_unlock_irq(q->queue_lock); - goto out; - } rl->count[rw]++; rl->starved[rw] = 0; if (rl->count[rw] >= queue_congestion_on_threshold(q)) diff --git a/trunk/drivers/char/moxa.c b/trunk/drivers/char/moxa.c index 95f7046ff059..7c24fbe831f8 100644 --- a/trunk/drivers/char/moxa.c +++ b/trunk/drivers/char/moxa.c @@ -451,7 +451,7 @@ static int __init moxa_init(void) int n = (sizeof(moxa_pcibrds) / sizeof(moxa_pcibrds[0])) - 1; i = 0; while (i < n) { - while ((p = pci_get_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL) + while ((p = pci_find_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL) { if (pci_enable_device(p)) continue; diff --git a/trunk/drivers/char/rio/rio_linux.c b/trunk/drivers/char/rio/rio_linux.c index d7d484024e2b..7db3370f4972 100644 --- a/trunk/drivers/char/rio/rio_linux.c +++ b/trunk/drivers/char/rio/rio_linux.c @@ -1095,7 +1095,7 @@ static int __init rio_init(void) #ifdef CONFIG_PCI /* First look for the JET devices: */ - while ((pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX, + while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, pdev))) { if (pci_enable_device(pdev)) continue; @@ -1169,7 +1169,7 @@ static int __init rio_init(void) */ /* Then look for the older RIO/PCI devices: */ - while ((pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX, + while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_RIO, pdev))) { if (pci_enable_device(pdev)) continue; diff --git a/trunk/drivers/md/md.c b/trunk/drivers/md/md.c index 4a0c57db2b67..3802f7a17f16 100644 --- a/trunk/drivers/md/md.c +++ b/trunk/drivers/md/md.c @@ -338,7 +338,6 @@ static int super_written(struct bio *bio, unsigned int bytes_done, int error) if (atomic_dec_and_test(&rdev->mddev->pending_writes)) wake_up(&rdev->mddev->sb_wait); - bio_put(bio); return 0; } diff --git a/trunk/drivers/message/fusion/mptfc.c b/trunk/drivers/message/fusion/mptfc.c index 353deb25e397..d8d65397e06e 100644 --- a/trunk/drivers/message/fusion/mptfc.c +++ b/trunk/drivers/message/fusion/mptfc.c @@ -364,7 +364,9 @@ static struct pci_driver mptfc_driver = { .id_table = mptfc_pci_table, .probe = mptfc_probe, .remove = __devexit_p(mptscsih_remove), - .shutdown = mptscsih_shutdown, + .driver = { + .shutdown = mptscsih_shutdown, + }, #ifdef CONFIG_PM .suspend = mptscsih_suspend, .resume = mptscsih_resume, diff --git a/trunk/drivers/message/fusion/mptscsih.c b/trunk/drivers/message/fusion/mptscsih.c index 4f973a49be4c..a0078ae5b9b8 100644 --- a/trunk/drivers/message/fusion/mptscsih.c +++ b/trunk/drivers/message/fusion/mptscsih.c @@ -170,7 +170,7 @@ static void mptscsih_fillbuf(char *buffer, int size, int index, int width); #endif void mptscsih_remove(struct pci_dev *); -void mptscsih_shutdown(struct pci_dev *); +void mptscsih_shutdown(struct device *); #ifdef CONFIG_PM int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state); int mptscsih_resume(struct pci_dev *pdev); @@ -988,7 +988,7 @@ mptscsih_remove(struct pci_dev *pdev) #endif #endif - mptscsih_shutdown(pdev); + mptscsih_shutdown(&pdev->dev); sz1=0; @@ -1026,9 +1026,9 @@ mptscsih_remove(struct pci_dev *pdev) * */ void -mptscsih_shutdown(struct pci_dev *pdev) +mptscsih_shutdown(struct device * dev) { - MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + MPT_ADAPTER *ioc = pci_get_drvdata(to_pci_dev(dev)); struct Scsi_Host *host = ioc->sh; MPT_SCSI_HOST *hd; @@ -1054,7 +1054,7 @@ mptscsih_shutdown(struct pci_dev *pdev) int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state) { - mptscsih_shutdown(pdev); + mptscsih_shutdown(&pdev->dev); return mpt_suspend(pdev,state); } diff --git a/trunk/drivers/message/fusion/mptscsih.h b/trunk/drivers/message/fusion/mptscsih.h index 5ea89bf0df19..d73aec33e16a 100644 --- a/trunk/drivers/message/fusion/mptscsih.h +++ b/trunk/drivers/message/fusion/mptscsih.h @@ -82,7 +82,7 @@ #endif extern void mptscsih_remove(struct pci_dev *); -extern void mptscsih_shutdown(struct pci_dev *); +extern void mptscsih_shutdown(struct device *); #ifdef CONFIG_PM extern int mptscsih_suspend(struct pci_dev *pdev, u32 state); extern int mptscsih_resume(struct pci_dev *pdev); diff --git a/trunk/drivers/message/fusion/mptspi.c b/trunk/drivers/message/fusion/mptspi.c index e0c0ee5bc966..5f9a61b85b3b 100644 --- a/trunk/drivers/message/fusion/mptspi.c +++ b/trunk/drivers/message/fusion/mptspi.c @@ -419,7 +419,9 @@ static struct pci_driver mptspi_driver = { .id_table = mptspi_pci_table, .probe = mptspi_probe, .remove = __devexit_p(mptscsih_remove), - .shutdown = mptscsih_shutdown, + .driver = { + .shutdown = mptscsih_shutdown, + }, #ifdef CONFIG_PM .suspend = mptscsih_suspend, .resume = mptscsih_resume, diff --git a/trunk/drivers/net/amd8111e.c b/trunk/drivers/net/amd8111e.c index 8618012df06a..b7dd7260cafb 100755 --- a/trunk/drivers/net/amd8111e.c +++ b/trunk/drivers/net/amd8111e.c @@ -87,7 +87,6 @@ Revision History: #include #include #include -#include #include #include @@ -2007,11 +2006,12 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, } /* Initialize DMA */ - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) < 0) { + if(!pci_dma_supported(pdev, 0xffffffff)){ printk(KERN_ERR "amd8111e: DMA not supported," "exiting.\n"); - goto err_free_reg; - } + goto err_free_reg; + } else + pdev->dma_mask = 0xffffffff; reg_addr = pci_resource_start(pdev, 0); reg_len = pci_resource_len(pdev, 0); diff --git a/trunk/drivers/net/at1700.c b/trunk/drivers/net/at1700.c index e613cc289749..b8ab2b6355eb 100644 --- a/trunk/drivers/net/at1700.c +++ b/trunk/drivers/net/at1700.c @@ -34,6 +34,10 @@ only is it difficult to detect, it also moves around in I/O space in response to inb()s from other device probes! */ +/* + 99/03/03 Allied Telesis RE1000 Plus support by T.Hagawa + 99/12/30 port to 2.3.35 by K.Takai +*/ #include #include diff --git a/trunk/drivers/net/e100.c b/trunk/drivers/net/e100.c index d0fa2448761d..1e56c8eea35f 100644 --- a/trunk/drivers/net/e100.c +++ b/trunk/drivers/net/e100.c @@ -2447,8 +2447,9 @@ static int e100_resume(struct pci_dev *pdev) #endif -static void e100_shutdown(struct pci_dev *pdev) +static void e100_shutdown(struct device *dev) { + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); @@ -2469,7 +2470,11 @@ static struct pci_driver e100_driver = { .suspend = e100_suspend, .resume = e100_resume, #endif - .shutdown = e100_shutdown, + + .driver = { + .shutdown = e100_shutdown, + } + }; static int __init e100_init_module(void) diff --git a/trunk/drivers/net/skge.c b/trunk/drivers/net/skge.c index 3dbb1cb09ed8..30e8d589d167 100644 --- a/trunk/drivers/net/skge.c +++ b/trunk/drivers/net/skge.c @@ -7,7 +7,7 @@ * of the original driver such as link fail-over and link management because * those should be done at higher levels. * - * Copyright (C) 2004, 2005 Stephen Hemminger + * Copyright (C) 2004, Stephen Hemminger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,20 +42,19 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "0.7" +#define DRV_VERSION "0.6" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 #define DEFAULT_RX_RING_SIZE 512 #define MAX_TX_RING_SIZE 1024 #define MAX_RX_RING_SIZE 4096 -#define RX_COPY_THRESHOLD 128 -#define RX_BUF_SIZE 1536 #define PHY_RETRIES 1000 #define ETH_JUMBO_MTU 9000 #define TX_WATCHDOG (5 * HZ) #define NAPI_WEIGHT 64 #define BLINK_HZ (HZ/4) +#define LINK_POLL_HZ (HZ/10) MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); MODULE_AUTHOR("Stephen Hemminger "); @@ -71,17 +70,28 @@ module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); static const struct pci_device_id skge_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940) }, - { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B) }, - { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) }, - { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) }, - { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, /* SK-9Exx */ - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) }, - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */ - { PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) }, - { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032) }, - { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064) }, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940, + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B, + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE, + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU, + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_SYSKONNECT, 0x9E00, /* SK-9Exx */ + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T, + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_MARVELL, 0x4320, /* Gigabit Ethernet Controller */ + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_MARVELL, 0x5005, /* Marvell (11ab), Belkin */ + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD, + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032, + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064, + PCI_ANY_ID, PCI_ANY_ID }, { 0 } }; MODULE_DEVICE_TABLE(pci, skge_id_table); @@ -89,22 +99,19 @@ MODULE_DEVICE_TABLE(pci, skge_id_table); static int skge_up(struct net_device *dev); static int skge_down(struct net_device *dev); static void skge_tx_clean(struct skge_port *skge); -static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); -static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); +static void skge_xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); +static void skge_gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); static void genesis_get_stats(struct skge_port *skge, u64 *data); static void yukon_get_stats(struct skge_port *skge, u64 *data); static void yukon_init(struct skge_hw *hw, int port); static void yukon_reset(struct skge_hw *hw, int port); static void genesis_mac_init(struct skge_hw *hw, int port); static void genesis_reset(struct skge_hw *hw, int port); -static void genesis_link_up(struct skge_port *skge); -/* Avoid conditionals by using array */ static const int txqaddr[] = { Q_XA1, Q_XA2 }; static const int rxqaddr[] = { Q_R1, Q_R2 }; static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F }; static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F }; -static const u32 portirqmask[] = { IS_PORT_1, IS_PORT_2 }; /* Don't need to look at whole 16K. * last interesting register is descriptor poll timer. @@ -147,7 +154,7 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs, static int wol_supported(const struct skge_hw *hw) { return !((hw->chip_id == CHIP_ID_GENESIS || - (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0))); + (hw->chip_id == CHIP_ID_YUKON && chip_rev(hw) == 0))); } static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) @@ -163,7 +170,7 @@ 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 != WAKE_MAGIC && wol->wolopts != 0) return -EOPNOTSUPP; if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw)) @@ -183,36 +190,6 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return 0; } -/* Determine supported/adverised modes based on hardware. - * Note: ethtoool ADVERTISED_xxx == SUPPORTED_xxx - */ -static u32 skge_supported_modes(const struct skge_hw *hw) -{ - u32 supported; - - if (iscopper(hw)) { - supported = SUPPORTED_10baseT_Half - | SUPPORTED_10baseT_Full - | SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full - | SUPPORTED_1000baseT_Half - | SUPPORTED_1000baseT_Full - | SUPPORTED_Autoneg| SUPPORTED_TP; - - if (hw->chip_id == CHIP_ID_GENESIS) - supported &= ~(SUPPORTED_10baseT_Half - | SUPPORTED_10baseT_Full - | SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full); - - else if (hw->chip_id == CHIP_ID_YUKON) - supported &= ~SUPPORTED_1000baseT_Half; - } else - supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE - | SUPPORTED_Autoneg; - - return supported; -} static int skge_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) @@ -221,13 +198,38 @@ static int skge_get_settings(struct net_device *dev, struct skge_hw *hw = skge->hw; ecmd->transceiver = XCVR_INTERNAL; - ecmd->supported = skge_supported_modes(hw); if (iscopper(hw)) { + if (hw->chip_id == CHIP_ID_GENESIS) + ecmd->supported = SUPPORTED_1000baseT_Full + | SUPPORTED_1000baseT_Half + | SUPPORTED_Autoneg | SUPPORTED_TP; + else { + ecmd->supported = SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full + | SUPPORTED_1000baseT_Half + | SUPPORTED_1000baseT_Full + | SUPPORTED_Autoneg| SUPPORTED_TP; + + if (hw->chip_id == CHIP_ID_YUKON) + ecmd->supported &= ~SUPPORTED_1000baseT_Half; + + else if (hw->chip_id == CHIP_ID_YUKON_FE) + ecmd->supported &= ~(SUPPORTED_1000baseT_Half + | SUPPORTED_1000baseT_Full); + } + ecmd->port = PORT_TP; ecmd->phy_address = hw->phy_addr; - } else + } else { + ecmd->supported = SUPPORTED_1000baseT_Full + | SUPPORTED_FIBRE + | SUPPORTED_Autoneg; + ecmd->port = PORT_FIBRE; + } ecmd->advertising = skge->advertising; ecmd->autoneg = skge->autoneg; @@ -236,57 +238,65 @@ static int skge_get_settings(struct net_device *dev, return 0; } +static u32 skge_modes(const struct skge_hw *hw) +{ + u32 modes = ADVERTISED_Autoneg + | ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half + | ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half + | ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half; + + if (iscopper(hw)) { + modes |= ADVERTISED_TP; + switch(hw->chip_id) { + case CHIP_ID_GENESIS: + modes &= ~(ADVERTISED_100baseT_Full + | ADVERTISED_100baseT_Half + | ADVERTISED_10baseT_Full + | ADVERTISED_10baseT_Half); + break; + + case CHIP_ID_YUKON: + modes &= ~ADVERTISED_1000baseT_Half; + break; + + case CHIP_ID_YUKON_FE: + modes &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full); + break; + } + } else { + modes |= ADVERTISED_FIBRE; + modes &= ~ADVERTISED_1000baseT_Half; + } + return modes; +} + static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct skge_port *skge = netdev_priv(dev); const struct skge_hw *hw = skge->hw; - u32 supported = skge_supported_modes(hw); if (ecmd->autoneg == AUTONEG_ENABLE) { - ecmd->advertising = supported; - skge->duplex = -1; - skge->speed = -1; + if (ecmd->advertising & skge_modes(hw)) + return -EINVAL; } else { - u32 setting; - switch(ecmd->speed) { case SPEED_1000: - if (ecmd->duplex == DUPLEX_FULL) - setting = SUPPORTED_1000baseT_Full; - else if (ecmd->duplex == DUPLEX_HALF) - setting = SUPPORTED_1000baseT_Half; - else + if (hw->chip_id == CHIP_ID_YUKON_FE) return -EINVAL; break; case SPEED_100: - if (ecmd->duplex == DUPLEX_FULL) - setting = SUPPORTED_100baseT_Full; - else if (ecmd->duplex == DUPLEX_HALF) - setting = SUPPORTED_100baseT_Half; - else - return -EINVAL; - break; - case SPEED_10: - if (ecmd->duplex == DUPLEX_FULL) - setting = SUPPORTED_10baseT_Full; - else if (ecmd->duplex == DUPLEX_HALF) - setting = SUPPORTED_10baseT_Half; - else + if (iscopper(hw) || hw->chip_id == CHIP_ID_GENESIS) return -EINVAL; break; default: return -EINVAL; } - - if ((setting & supported) == 0) - return -EINVAL; - - skge->speed = ecmd->speed; - skge->duplex = ecmd->duplex; } skge->autoneg = ecmd->autoneg; + skge->speed = ecmd->speed; + skge->duplex = ecmd->duplex; skge->advertising = ecmd->advertising; if (netif_running(dev)) { @@ -383,7 +393,7 @@ static void skge_get_strings(struct net_device *dev, u32 stringset, u8 *data) { int i; - switch (stringset) { + switch(stringset) { case ETH_SS_STATS: for (i = 0; i < ARRAY_SIZE(skge_stats); i++) memcpy(data + i * ETH_GSTRING_LEN, @@ -501,6 +511,14 @@ static int skge_set_rx_csum(struct net_device *dev, u32 data) return 0; } +/* Only Yukon II supports TSO (not implemented yet) */ +static int skge_set_tso(struct net_device *dev, u32 data) +{ + if (data) + return -EOPNOTSUPP; + return 0; +} + static void skge_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *ecmd) { @@ -522,9 +540,9 @@ static int skge_set_pauseparam(struct net_device *dev, skge->autoneg = ecmd->autoneg; if (ecmd->rx_pause && ecmd->tx_pause) skge->flow_control = FLOW_MODE_SYMMETRIC; - else if (ecmd->rx_pause && !ecmd->tx_pause) + else if(ecmd->rx_pause && !ecmd->tx_pause) skge->flow_control = FLOW_MODE_REM_SEND; - else if (!ecmd->rx_pause && ecmd->tx_pause) + else if(!ecmd->rx_pause && ecmd->tx_pause) skge->flow_control = FLOW_MODE_LOC_SEND; else skge->flow_control = FLOW_MODE_NONE; @@ -541,6 +559,8 @@ static inline u32 hwkhz(const struct skge_hw *hw) { if (hw->chip_id == CHIP_ID_GENESIS) return 53215; /* or: 53.125 MHz */ + else if (hw->chip_id == CHIP_ID_YUKON_EC) + return 125000; /* or: 125.000 MHz */ else return 78215; /* or: 78.125 MHz */ } @@ -623,18 +643,30 @@ static int skge_set_coalesce(struct net_device *dev, static void skge_led_on(struct skge_hw *hw, int port) { if (hw->chip_id == CHIP_ID_GENESIS) { - skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON); + skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_ON); skge_write8(hw, B0_LED, LED_STAT_ON); - skge_write8(hw, SK_REG(port, RX_LED_TST), LED_T_ON); - skge_write32(hw, SK_REG(port, RX_LED_VAL), 100); - skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); + skge_write8(hw, SKGEMAC_REG(port, RX_LED_TST), LED_T_ON); + skge_write32(hw, SKGEMAC_REG(port, RX_LED_VAL), 100); + skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_START); - /* For Broadcom Phy only */ - xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON); + switch (hw->phy_type) { + case SK_PHY_BCOM: + skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, + PHY_B_PEC_LED_ON); + break; + case SK_PHY_LONE: + skge_xm_phy_write(hw, port, PHY_LONE_LED_CFG, + 0x0800); + break; + default: + skge_write8(hw, SKGEMAC_REG(port, TX_LED_TST), LED_T_ON); + skge_write32(hw, SKGEMAC_REG(port, TX_LED_VAL), 100); + skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_START); + } } else { - gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); - gm_phy_write(hw, port, PHY_MARV_LED_OVER, + skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); + skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER, PHY_M_LED_MO_DUP(MO_LED_ON) | PHY_M_LED_MO_10(MO_LED_ON) | PHY_M_LED_MO_100(MO_LED_ON) | @@ -646,17 +678,28 @@ static void skge_led_on(struct skge_hw *hw, int port) static void skge_led_off(struct skge_hw *hw, int port) { if (hw->chip_id == CHIP_ID_GENESIS) { - skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF); + skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_OFF); skge_write8(hw, B0_LED, LED_STAT_OFF); - skge_write32(hw, SK_REG(port, RX_LED_VAL), 0); - skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF); + skge_write32(hw, SKGEMAC_REG(port, RX_LED_VAL), 0); + skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_T_OFF); - /* Broadcom only */ - xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF); + switch (hw->phy_type) { + case SK_PHY_BCOM: + skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, + PHY_B_PEC_LED_OFF); + break; + case SK_PHY_LONE: + skge_xm_phy_write(hw, port, PHY_LONE_LED_CFG, + PHY_L_LC_LEDT); + break; + default: + skge_write32(hw, SKGEMAC_REG(port, TX_LED_VAL), 0); + skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_T_OFF); + } } else { - gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); - gm_phy_write(hw, port, PHY_MARV_LED_OVER, + skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); + skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER, PHY_M_LED_MO_DUP(MO_LED_OFF) | PHY_M_LED_MO_10(MO_LED_OFF) | PHY_M_LED_MO_100(MO_LED_OFF) | @@ -687,7 +730,7 @@ static int skge_phys_id(struct net_device *dev, u32 data) { struct skge_port *skge = netdev_priv(dev); - if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) + if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); /* start blinking */ @@ -720,6 +763,8 @@ static struct ethtool_ops skge_ethtool_ops = { .set_pauseparam = skge_set_pauseparam, .get_coalesce = skge_get_coalesce, .set_coalesce = skge_set_coalesce, + .get_tso = ethtool_op_get_tso, + .set_tso = skge_set_tso, .get_sg = ethtool_op_get_sg, .set_sg = skge_set_sg, .get_tx_csum = ethtool_op_get_tx_csum, @@ -748,7 +793,6 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base) for (i = 0, e = ring->start, d = vaddr; i < ring->count; i++, e++, d++) { e->desc = d; - e->skb = NULL; if (i == ring->count - 1) { e->next = ring->start; d->next_offset = base; @@ -762,23 +806,24 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base) return 0; } -static struct sk_buff *skge_rx_alloc(struct net_device *dev, unsigned int size) +/* Setup buffer for receiving */ +static inline int skge_rx_alloc(struct skge_port *skge, + struct skge_element *e) { - struct sk_buff *skb = dev_alloc_skb(size); + unsigned long bufsize = skge->netdev->mtu + ETH_HLEN; /* VLAN? */ + struct skge_rx_desc *rd = e->desc; + struct sk_buff *skb; + u64 map; - if (likely(skb)) { - skb->dev = dev; - skb_reserve(skb, NET_IP_ALIGN); + skb = dev_alloc_skb(bufsize + NET_IP_ALIGN); + if (unlikely(!skb)) { + printk(KERN_DEBUG PFX "%s: out of memory for receive\n", + skge->netdev->name); + return -ENOMEM; } - return skb; -} -/* Allocate and setup a new buffer for receiving */ -static void skge_rx_setup(struct skge_port *skge, struct skge_element *e, - struct sk_buff *skb, unsigned int bufsize) -{ - struct skge_rx_desc *rd = e->desc; - u64 map; + skb->dev = skge->netdev; + skb_reserve(skb, NET_IP_ALIGN); map = pci_map_single(skge->hw->pdev, skb->data, bufsize, PCI_DMA_FROMDEVICE); @@ -796,69 +841,55 @@ static void skge_rx_setup(struct skge_port *skge, struct skge_element *e, rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize; pci_unmap_addr_set(e, mapaddr, map); pci_unmap_len_set(e, maplen, bufsize); + return 0; } -/* Resume receiving using existing skb, - * Note: DMA address is not changed by chip. - * MTU not changed while receiver active. - */ -static void skge_rx_reuse(struct skge_element *e, unsigned int size) -{ - struct skge_rx_desc *rd = e->desc; - - rd->csum2 = 0; - rd->csum2_start = ETH_HLEN; - - wmb(); - - rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | size; -} - - -/* Free all buffers in receive ring, assumes receiver stopped */ +/* Free all unused buffers in receive ring, assumes receiver stopped */ static void skge_rx_clean(struct skge_port *skge) { struct skge_hw *hw = skge->hw; struct skge_ring *ring = &skge->rx_ring; struct skge_element *e; - e = ring->start; - do { + for (e = ring->to_clean; e != ring->to_use; e = e->next) { struct skge_rx_desc *rd = e->desc; rd->control = 0; - if (e->skb) { - pci_unmap_single(hw->pdev, - pci_unmap_addr(e, mapaddr), - pci_unmap_len(e, maplen), - PCI_DMA_FROMDEVICE); - dev_kfree_skb(e->skb); - e->skb = NULL; - } - } while ((e = e->next) != ring->start); -} + pci_unmap_single(hw->pdev, + pci_unmap_addr(e, mapaddr), + pci_unmap_len(e, maplen), + PCI_DMA_FROMDEVICE); + dev_kfree_skb(e->skb); + e->skb = NULL; + } + ring->to_clean = e; +} /* Allocate buffers for receive ring - * For receive: to_clean is next received frame. + * For receive: to_use is refill location + * to_clean is next received frame. + * + * if (to_use == to_clean) + * then ring all frames in ring need buffers + * if (to_use->next == to_clean) + * then ring all frames in ring have buffers */ static int skge_rx_fill(struct skge_port *skge) { struct skge_ring *ring = &skge->rx_ring; struct skge_element *e; - unsigned int bufsize = skge->rx_buf_size; - - e = ring->start; - do { - struct sk_buff *skb = skge_rx_alloc(skge->netdev, bufsize); + int ret = 0; - if (!skb) - return -ENOMEM; + for (e = ring->to_use; e->next != ring->to_clean; e = e->next) { + if (skge_rx_alloc(skge, e)) { + ret = 1; + break; + } - skge_rx_setup(skge, e, skb, bufsize); - } while ( (e = e->next) != ring->start); + } + ring->to_use = e; - ring->to_clean = ring->start; - return 0; + return ret; } static void skge_link_up(struct skge_port *skge) @@ -888,50 +919,50 @@ static void skge_link_down(struct skge_port *skge) printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name); } -static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg) +static u16 skge_xm_phy_read(struct skge_hw *hw, int port, u16 reg) { int i; u16 v; - xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); - v = xm_read16(hw, port, XM_PHY_DATA); + skge_xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); + v = skge_xm_read16(hw, port, XM_PHY_DATA); + if (hw->phy_type != SK_PHY_XMAC) { + for (i = 0; i < PHY_RETRIES; i++) { + udelay(1); + if (skge_xm_read16(hw, port, XM_MMU_CMD) + & XM_MMU_PHY_RDY) + goto ready; + } - /* Need to wait for external PHY */ - for (i = 0; i < PHY_RETRIES; i++) { - udelay(1); - if (xm_read16(hw, port, XM_MMU_CMD) - & XM_MMU_PHY_RDY) - goto ready; + printk(KERN_WARNING PFX "%s: phy read timed out\n", + hw->dev[port]->name); + return 0; + ready: + v = skge_xm_read16(hw, port, XM_PHY_DATA); } - printk(KERN_WARNING PFX "%s: phy read timed out\n", - hw->dev[port]->name); - return 0; - ready: - v = xm_read16(hw, port, XM_PHY_DATA); - return v; } -static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) +static void skge_xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) { int i; - xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); + skge_xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); for (i = 0; i < PHY_RETRIES; i++) { - if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY)) + if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY)) goto ready; - udelay(1); + cpu_relax(); } printk(KERN_WARNING PFX "%s: phy write failed to come ready\n", hw->dev[port]->name); ready: - xm_write16(hw, port, XM_PHY_DATA, val); + skge_xm_write16(hw, port, XM_PHY_DATA, val); for (i = 0; i < PHY_RETRIES; i++) { udelay(1); - if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY)) + if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY)) return; } printk(KERN_WARNING PFX "%s: phy write timed out\n", @@ -968,112 +999,34 @@ static void genesis_init(struct skge_hw *hw) static void genesis_reset(struct skge_hw *hw, int port) { - const u8 zero[8] = { 0 }; + int i; + u64 zero = 0; /* reset the statistics module */ - xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT); - xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */ - xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */ - xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */ - xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */ + skge_xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT); + skge_xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */ + skge_xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */ + skge_xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */ + skge_xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */ - /* disable Broadcom PHY IRQ */ - xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff); + /* disable all PHY IRQs */ + if (hw->phy_type == SK_PHY_BCOM) + skge_xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff); - xm_outhash(hw, port, XM_HSM, zero); + skge_xm_outhash(hw, port, XM_HSM, (u8 *) &zero); + for (i = 0; i < 15; i++) + skge_xm_outaddr(hw, port, XM_EXM(i), (u8 *) &zero); + skge_xm_outhash(hw, port, XM_SRC_CHK, (u8 *) &zero); } -/* Convert mode to MII values */ -static const u16 phy_pause_map[] = { - [FLOW_MODE_NONE] = 0, - [FLOW_MODE_LOC_SEND] = PHY_AN_PAUSE_ASYM, - [FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP, - [FLOW_MODE_REM_SEND] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, -}; - - -/* Check status of Broadcom phy link */ -static void bcom_check_link(struct skge_hw *hw, int port) -{ - struct net_device *dev = hw->dev[port]; - struct skge_port *skge = netdev_priv(dev); - u16 status; - - /* read twice because of latch */ - (void) xm_phy_read(hw, port, PHY_BCOM_STAT); - status = xm_phy_read(hw, port, PHY_BCOM_STAT); - - pr_debug("bcom_check_link status=0x%x\n", status); - - if ((status & PHY_ST_LSYNC) == 0) { - u16 cmd = xm_read16(hw, port, XM_MMU_CMD); - cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); - xm_write16(hw, port, XM_MMU_CMD, cmd); - /* dummy read to ensure writing */ - (void) xm_read16(hw, port, XM_MMU_CMD); - - if (netif_carrier_ok(dev)) - skge_link_down(skge); - } else { - if (skge->autoneg == AUTONEG_ENABLE && - (status & PHY_ST_AN_OVER)) { - u16 lpa = xm_phy_read(hw, port, PHY_BCOM_AUNE_LP); - u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT); - - if (lpa & PHY_B_AN_RF) { - printk(KERN_NOTICE PFX "%s: remote fault\n", - dev->name); - return; - } - - /* Check Duplex mismatch */ - switch(aux & PHY_B_AS_AN_RES_MSK) { - case PHY_B_RES_1000FD: - skge->duplex = DUPLEX_FULL; - break; - case PHY_B_RES_1000HD: - skge->duplex = DUPLEX_HALF; - break; - default: - printk(KERN_NOTICE PFX "%s: duplex mismatch\n", - dev->name); - return; - } - - - /* We are using IEEE 802.3z/D5.0 Table 37-4 */ - switch (aux & PHY_B_AS_PAUSE_MSK) { - case PHY_B_AS_PAUSE_MSK: - skge->flow_control = FLOW_MODE_SYMMETRIC; - break; - case PHY_B_AS_PRR: - skge->flow_control = FLOW_MODE_REM_SEND; - break; - case PHY_B_AS_PRT: - skge->flow_control = FLOW_MODE_LOC_SEND; - break; - default: - skge->flow_control = FLOW_MODE_NONE; - } - - skge->speed = SPEED_1000; - } - - if (!netif_carrier_ok(dev)) - genesis_link_up(skge); - } -} - -/* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional - * Phy on for 100 or 10Mbit operation - */ -static void bcom_phy_init(struct skge_port *skge, int jumbo) +static void genesis_mac_init(struct skge_hw *hw, int port) { - struct skge_hw *hw = skge->hw; - int port = skge->port; + struct skge_port *skge = netdev_priv(hw->dev[port]); int i; - u16 id1, r, ext, ctl; + u32 r; + u16 id1; + u16 ctrl1, ctrl2, ctrl3, ctrl4, ctrl5; /* magic workaround patterns for Broadcom */ static const struct { @@ -1089,120 +1042,16 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo) { 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 }, }; - pr_debug("bcom_phy_init\n"); - - /* read Id from external PHY (all have the same address) */ - id1 = xm_phy_read(hw, port, PHY_XMAC_ID1); - - /* Optimize MDIO transfer by suppressing preamble. */ - r = xm_read16(hw, port, XM_MMU_CMD); - r |= XM_MMU_NO_PRE; - xm_write16(hw, port, XM_MMU_CMD,r); - - switch(id1) { - case PHY_BCOM_ID1_C0: - /* - * Workaround BCOM Errata for the C0 type. - * Write magic patterns to reserved registers. - */ - for (i = 0; i < ARRAY_SIZE(C0hack); i++) - xm_phy_write(hw, port, - C0hack[i].reg, C0hack[i].val); - - break; - case PHY_BCOM_ID1_A1: - /* - * Workaround BCOM Errata for the A1 type. - * Write magic patterns to reserved registers. - */ - for (i = 0; i < ARRAY_SIZE(A1hack); i++) - xm_phy_write(hw, port, - A1hack[i].reg, A1hack[i].val); - break; - } - - /* - * Workaround BCOM Errata (#10523) for all BCom PHYs. - * Disable Power Management after reset. - */ - r = xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL); - r |= PHY_B_AC_DIS_PM; - xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r); - - /* Dummy read */ - xm_read16(hw, port, XM_ISRC); - - ext = PHY_B_PEC_EN_LTR; /* enable tx led */ - ctl = PHY_CT_SP1000; /* always 1000mbit */ - - if (skge->autoneg == AUTONEG_ENABLE) { - /* - * Workaround BCOM Errata #1 for the C5 type. - * 1000Base-T Link Acquisition Failure in Slave Mode - * Set Repeater/DTE bit 10 of the 1000Base-T Control Register - */ - u16 adv = PHY_B_1000C_RD; - if (skge->advertising & ADVERTISED_1000baseT_Half) - adv |= PHY_B_1000C_AHD; - if (skge->advertising & ADVERTISED_1000baseT_Full) - adv |= PHY_B_1000C_AFD; - xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, adv); - - ctl |= PHY_CT_ANE | PHY_CT_RE_CFG; - } else { - if (skge->duplex == DUPLEX_FULL) - ctl |= PHY_CT_DUP_MD; - /* Force to slave */ - xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, PHY_B_1000C_MSE); - } - - /* Set autonegotiation pause parameters */ - xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV, - phy_pause_map[skge->flow_control] | PHY_AN_CSMA); - - /* Handle Jumbo frames */ - if (jumbo) { - xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, - PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK); - - ext |= PHY_B_PEC_HIGH_LA; - - } - - xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ext); - xm_phy_write(hw, port, PHY_BCOM_CTRL, ctl); - - /* Use link status change interrrupt */ - xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); - - bcom_check_link(hw, port); -} - -static void genesis_mac_init(struct skge_hw *hw, int port) -{ - struct net_device *dev = hw->dev[port]; - struct skge_port *skge = netdev_priv(dev); - int jumbo = hw->dev[port]->mtu > ETH_DATA_LEN; - int i; - u32 r; - const u8 zero[6] = { 0 }; - - /* Clear MIB counters */ - xm_write16(hw, port, XM_STAT_CMD, - XM_SC_CLR_RXC | XM_SC_CLR_TXC); - /* Clear two times according to Errata #3 */ - xm_write16(hw, port, XM_STAT_CMD, - XM_SC_CLR_RXC | XM_SC_CLR_TXC); /* initialize Rx, Tx and Link LED */ - skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON); - skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON); + skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_ON); + skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON); - skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); - skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START); + skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_START); + skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_START); /* Unreset the XMAC. */ - skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); + skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); /* * Perform additional initialization for external PHYs, @@ -1210,56 +1059,67 @@ static void genesis_mac_init(struct skge_hw *hw, int port) * GMII mode. */ spin_lock_bh(&hw->phy_lock); - /* Take external Phy out of reset */ - r = skge_read32(hw, B2_GP_IO); - if (port == 0) - r |= GP_DIR_0|GP_IO_0; - else - r |= GP_DIR_2|GP_IO_2; - - skge_write32(hw, B2_GP_IO, r); - skge_read32(hw, B2_GP_IO); - spin_unlock_bh(&hw->phy_lock); - - /* Enable GMII interfac */ - xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD); - - bcom_phy_init(skge, jumbo); - - /* Set Station Address */ - xm_outaddr(hw, port, XM_SA, dev->dev_addr); - - /* We don't use match addresses so clear */ - for (i = 1; i < 16; i++) - xm_outaddr(hw, port, XM_EXM(i), zero); - - /* configure Rx High Water Mark (XM_RX_HI_WM) */ - xm_write16(hw, port, XM_RX_HI_WM, 1450); - - /* We don't need the FCS appended to the packet. */ - r = XM_RX_LENERR_OK | XM_RX_STRIP_FCS; - if (jumbo) - r |= XM_RX_BIG_PK_OK; + if (hw->phy_type != SK_PHY_XMAC) { + /* Take PHY out of reset. */ + r = skge_read32(hw, B2_GP_IO); + if (port == 0) + r |= GP_DIR_0|GP_IO_0; + else + r |= GP_DIR_2|GP_IO_2; + + skge_write32(hw, B2_GP_IO, r); + skge_read32(hw, B2_GP_IO); + + /* Enable GMII mode on the XMAC. */ + skge_xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD); + + id1 = skge_xm_phy_read(hw, port, PHY_XMAC_ID1); + + /* Optimize MDIO transfer by suppressing preamble. */ + skge_xm_write16(hw, port, XM_MMU_CMD, + skge_xm_read16(hw, port, XM_MMU_CMD) + | XM_MMU_NO_PRE); + + if (id1 == PHY_BCOM_ID1_C0) { + /* + * Workaround BCOM Errata for the C0 type. + * Write magic patterns to reserved registers. + */ + for (i = 0; i < ARRAY_SIZE(C0hack); i++) + skge_xm_phy_write(hw, port, + C0hack[i].reg, C0hack[i].val); + + } else if (id1 == PHY_BCOM_ID1_A1) { + /* + * Workaround BCOM Errata for the A1 type. + * Write magic patterns to reserved registers. + */ + for (i = 0; i < ARRAY_SIZE(A1hack); i++) + skge_xm_phy_write(hw, port, + A1hack[i].reg, A1hack[i].val); + } - if (skge->duplex == DUPLEX_HALF) { /* - * If in manual half duplex mode the other side might be in - * full duplex mode, so ignore if a carrier extension is not seen - * on frames received + * Workaround BCOM Errata (#10523) for all BCom PHYs. + * Disable Power Management after reset. */ - r |= XM_RX_DIS_CEXT; + r = skge_xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL); + skge_xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r | PHY_B_AC_DIS_PM); } - xm_write16(hw, port, XM_RX_CMD, r); + /* Dummy read */ + skge_xm_read16(hw, port, XM_ISRC); - /* We want short frames padded to 60 bytes. */ - xm_write16(hw, port, XM_TX_CMD, XM_TX_AUTO_PAD); + r = skge_xm_read32(hw, port, XM_MODE); + skge_xm_write32(hw, port, XM_MODE, r|XM_MD_CSA); - /* - * Bump up the transmit threshold. This helps hold off transmit - * underruns when we're blasting traffic from both ports at once. - */ - xm_write16(hw, port, XM_TX_THR, 512); + /* We don't need the FCS appended to the packet. */ + r = skge_xm_read16(hw, port, XM_RX_CMD); + skge_xm_write16(hw, port, XM_RX_CMD, r | XM_RX_STRIP_FCS); + + /* We want short frames padded to 60 bytes. */ + r = skge_xm_read16(hw, port, XM_TX_CMD); + skge_xm_write16(hw, port, XM_TX_CMD, r | XM_TX_AUTO_PAD); /* * Enable the reception of all error frames. This is is @@ -1275,22 +1135,19 @@ static void genesis_mac_init(struct skge_hw *hw, int port) * case the XMAC will start transfering frames out of the * RX FIFO as soon as the FIFO threshold is reached. */ - xm_write32(hw, port, XM_MODE, XM_DEF_MODE); + r = skge_xm_read32(hw, port, XM_MODE); + skge_xm_write32(hw, port, XM_MODE, + XM_MD_RX_CRCE|XM_MD_RX_LONG|XM_MD_RX_RUNT| + XM_MD_RX_ERR|XM_MD_RX_IRLE); + skge_xm_outaddr(hw, port, XM_SA, hw->dev[port]->dev_addr); + skge_xm_outaddr(hw, port, XM_EXM(0), hw->dev[port]->dev_addr); /* - * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK) - * - Enable all bits excepting 'Octets Rx OK Low CntOv' - * and 'Octets Rx OK Hi Cnt Ov'. - */ - xm_write32(hw, port, XM_RX_EV_MSK, XMR_DEF_MSK); - - /* - * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK) - * - Enable all bits excepting 'Octets Tx OK Low CntOv' - * and 'Octets Tx OK Hi Cnt Ov'. + * Bump up the transmit threshold. This helps hold off transmit + * underruns when we're blasting traffic from both ports at once. */ - xm_write32(hw, port, XM_TX_EV_MSK, XMT_DEF_MSK); + skge_xm_write16(hw, port, XM_TX_THR, 512); /* Configure MAC arbiter */ skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR); @@ -1307,30 +1164,137 @@ static void genesis_mac_init(struct skge_hw *hw, int port) skge_write8(hw, B3_MA_RCINI_TX2, 0); /* Configure Rx MAC FIFO */ - skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_CLR); - skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_TIM_PAT); - skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_ENA_OP_MD); + skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_RST_CLR); + skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_ENA_TIM_PAT); + skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_ENA_OP_MD); /* Configure Tx MAC FIFO */ - skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_CLR); - skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF); - skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD); + skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_RST_CLR); + skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF); + skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD); - if (jumbo) { + if (hw->dev[port]->mtu > ETH_DATA_LEN) { /* Enable frame flushing if jumbo frames used */ - skge_write16(hw, SK_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH); + skge_write16(hw, SKGEMAC_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH); } else { /* enable timeout timers if normal frames */ skge_write16(hw, B3_PA_CTRL, - (port == 0) ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2); + port == 0 ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2); } + + + r = skge_xm_read16(hw, port, XM_RX_CMD); + if (hw->dev[port]->mtu > ETH_DATA_LEN) + skge_xm_write16(hw, port, XM_RX_CMD, r | XM_RX_BIG_PK_OK); + else + skge_xm_write16(hw, port, XM_RX_CMD, r & ~(XM_RX_BIG_PK_OK)); + + switch (hw->phy_type) { + case SK_PHY_XMAC: + if (skge->autoneg == AUTONEG_ENABLE) { + ctrl1 = PHY_X_AN_FD | PHY_X_AN_HD; + + switch (skge->flow_control) { + case FLOW_MODE_NONE: + ctrl1 |= PHY_X_P_NO_PAUSE; + break; + case FLOW_MODE_LOC_SEND: + ctrl1 |= PHY_X_P_ASYM_MD; + break; + case FLOW_MODE_SYMMETRIC: + ctrl1 |= PHY_X_P_SYM_MD; + break; + case FLOW_MODE_REM_SEND: + ctrl1 |= PHY_X_P_BOTH_MD; + break; + } + + skge_xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl1); + ctrl2 = PHY_CT_ANE | PHY_CT_RE_CFG; + } else { + ctrl2 = 0; + if (skge->duplex == DUPLEX_FULL) + ctrl2 |= PHY_CT_DUP_MD; + } + + skge_xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl2); + break; + + case SK_PHY_BCOM: + ctrl1 = PHY_CT_SP1000; + ctrl2 = 0; + ctrl3 = PHY_SEL_TYPE; + ctrl4 = PHY_B_PEC_EN_LTR; + ctrl5 = PHY_B_AC_TX_TST; + + if (skge->autoneg == AUTONEG_ENABLE) { + /* + * Workaround BCOM Errata #1 for the C5 type. + * 1000Base-T Link Acquisition Failure in Slave Mode + * Set Repeater/DTE bit 10 of the 1000Base-T Control Register + */ + ctrl2 |= PHY_B_1000C_RD; + if (skge->advertising & ADVERTISED_1000baseT_Half) + ctrl2 |= PHY_B_1000C_AHD; + if (skge->advertising & ADVERTISED_1000baseT_Full) + ctrl2 |= PHY_B_1000C_AFD; + + /* Set Flow-control capabilities */ + switch (skge->flow_control) { + case FLOW_MODE_NONE: + ctrl3 |= PHY_B_P_NO_PAUSE; + break; + case FLOW_MODE_LOC_SEND: + ctrl3 |= PHY_B_P_ASYM_MD; + break; + case FLOW_MODE_SYMMETRIC: + ctrl3 |= PHY_B_P_SYM_MD; + break; + case FLOW_MODE_REM_SEND: + ctrl3 |= PHY_B_P_BOTH_MD; + break; + } + + /* Restart Auto-negotiation */ + ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG; + } else { + if (skge->duplex == DUPLEX_FULL) + ctrl1 |= PHY_CT_DUP_MD; + + ctrl2 |= PHY_B_1000C_MSE; /* set it to Slave */ + } + + skge_xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, ctrl2); + skge_xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV, ctrl3); + + if (skge->netdev->mtu > ETH_DATA_LEN) { + ctrl4 |= PHY_B_PEC_HIGH_LA; + ctrl5 |= PHY_B_AC_LONG_PACK; + + skge_xm_phy_write(hw, port,PHY_BCOM_AUX_CTRL, ctrl5); + } + + skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ctrl4); + skge_xm_phy_write(hw, port, PHY_BCOM_CTRL, ctrl1); + break; + } + spin_unlock_bh(&hw->phy_lock); + + /* Clear MIB counters */ + skge_xm_write16(hw, port, XM_STAT_CMD, + XM_SC_CLR_RXC | XM_SC_CLR_TXC); + /* Clear two times according to Errata #3 */ + skge_xm_write16(hw, port, XM_STAT_CMD, + XM_SC_CLR_RXC | XM_SC_CLR_TXC); + + /* Start polling for link status */ + mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ); } static void genesis_stop(struct skge_port *skge) { struct skge_hw *hw = skge->hw; int port = skge->port; - u32 reg; /* Clear Tx packet arbiter timeout IRQ */ skge_write16(hw, B3_PA_CTRL, @@ -1340,30 +1304,33 @@ static void genesis_stop(struct skge_port *skge) * If the transfer stucks at the MAC the STOP command will not * terminate if we don't flush the XMAC's transmit FIFO ! */ - xm_write32(hw, port, XM_MODE, - xm_read32(hw, port, XM_MODE)|XM_MD_FTF); + skge_xm_write32(hw, port, XM_MODE, + skge_xm_read32(hw, port, XM_MODE)|XM_MD_FTF); /* Reset the MAC */ - skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST); + skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST); /* For external PHYs there must be special handling */ - reg = skge_read32(hw, B2_GP_IO); - if (port == 0) { - reg |= GP_DIR_0; - reg &= ~GP_IO_0; - } else { - reg |= GP_DIR_2; - reg &= ~GP_IO_2; + if (hw->phy_type != SK_PHY_XMAC) { + u32 reg = skge_read32(hw, B2_GP_IO); + + if (port == 0) { + reg |= GP_DIR_0; + reg &= ~GP_IO_0; + } else { + reg |= GP_DIR_2; + reg &= ~GP_IO_2; + } + skge_write32(hw, B2_GP_IO, reg); + skge_read32(hw, B2_GP_IO); } - skge_write32(hw, B2_GP_IO, reg); - skge_read32(hw, B2_GP_IO); - xm_write16(hw, port, XM_MMU_CMD, - xm_read16(hw, port, XM_MMU_CMD) + skge_xm_write16(hw, port, XM_MMU_CMD, + skge_xm_read16(hw, port, XM_MMU_CMD) & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX)); - xm_read16(hw, port, XM_MMU_CMD); + skge_xm_read16(hw, port, XM_MMU_CMD); } @@ -1374,11 +1341,11 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data) int i; unsigned long timeout = jiffies + HZ; - xm_write16(hw, port, + skge_xm_write16(hw, port, XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC); /* wait for update to complete */ - while (xm_read16(hw, port, XM_STAT_CMD) + while (skge_xm_read16(hw, port, XM_STAT_CMD) & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) { if (time_after(jiffies, timeout)) break; @@ -1386,60 +1353,68 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data) } /* special case for 64 bit octet counter */ - data[0] = (u64) xm_read32(hw, port, XM_TXO_OK_HI) << 32 - | xm_read32(hw, port, XM_TXO_OK_LO); - data[1] = (u64) xm_read32(hw, port, XM_RXO_OK_HI) << 32 - | xm_read32(hw, port, XM_RXO_OK_LO); + data[0] = (u64) skge_xm_read32(hw, port, XM_TXO_OK_HI) << 32 + | skge_xm_read32(hw, port, XM_TXO_OK_LO); + data[1] = (u64) skge_xm_read32(hw, port, XM_RXO_OK_HI) << 32 + | skge_xm_read32(hw, port, XM_RXO_OK_LO); for (i = 2; i < ARRAY_SIZE(skge_stats); i++) - data[i] = xm_read32(hw, port, skge_stats[i].xmac_offset); + data[i] = skge_xm_read32(hw, port, skge_stats[i].xmac_offset); } static void genesis_mac_intr(struct skge_hw *hw, int port) { struct skge_port *skge = netdev_priv(hw->dev[port]); - u16 status = xm_read16(hw, port, XM_ISRC); - - if (netif_msg_intr(skge)) - printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", - skge->netdev->name, status); + u16 status = skge_xm_read16(hw, port, XM_ISRC); + + pr_debug("genesis_intr status %x\n", status); + if (hw->phy_type == SK_PHY_XMAC) { + /* LInk down, start polling for state change */ + if (status & XM_IS_INP_ASS) { + skge_xm_write16(hw, port, XM_IMSK, + skge_xm_read16(hw, port, XM_IMSK) | XM_IS_INP_ASS); + mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ); + } + else if (status & XM_IS_AND) + mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ); + } if (status & XM_IS_TXF_UR) { - xm_write32(hw, port, XM_MODE, XM_MD_FTF); + skge_xm_write32(hw, port, XM_MODE, XM_MD_FTF); ++skge->net_stats.tx_fifo_errors; } if (status & XM_IS_RXF_OV) { - xm_write32(hw, port, XM_MODE, XM_MD_FRF); + skge_xm_write32(hw, port, XM_MODE, XM_MD_FRF); ++skge->net_stats.rx_fifo_errors; } } -static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) +static void skge_gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) { int i; - gma_write16(hw, port, GM_SMI_DATA, val); - gma_write16(hw, port, GM_SMI_CTRL, + skge_gma_write16(hw, port, GM_SMI_DATA, val); + skge_gma_write16(hw, port, GM_SMI_CTRL, GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg)); for (i = 0; i < PHY_RETRIES; i++) { udelay(1); - if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY)) + if (!(skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY)) break; } } -static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg) +static u16 skge_gm_phy_read(struct skge_hw *hw, int port, u16 reg) { int i; - gma_write16(hw, port, GM_SMI_CTRL, + skge_gma_write16(hw, port, GM_SMI_CTRL, GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD); for (i = 0; i < PHY_RETRIES; i++) { udelay(1); - if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL) + if (skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL) goto ready; } @@ -1447,7 +1422,24 @@ static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg) hw->dev[port]->name); return 0; ready: - return gma_read16(hw, port, GM_SMI_DATA); + return skge_gma_read16(hw, port, GM_SMI_DATA); +} + +static void genesis_link_down(struct skge_port *skge) +{ + struct skge_hw *hw = skge->hw; + int port = skge->port; + + pr_debug("genesis_link_down\n"); + + skge_xm_write16(hw, port, XM_MMU_CMD, + skge_xm_read16(hw, port, XM_MMU_CMD) + & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX)); + + /* dummy read to ensure writing */ + (void) skge_xm_read16(hw, port, XM_MMU_CMD); + + skge_link_down(skge); } static void genesis_link_up(struct skge_port *skge) @@ -1458,7 +1450,7 @@ static void genesis_link_up(struct skge_port *skge) u32 mode, msk; pr_debug("genesis_link_up\n"); - cmd = xm_read16(hw, port, XM_MMU_CMD); + cmd = skge_xm_read16(hw, port, XM_MMU_CMD); /* * enabling pause frame reception is required for 1000BT @@ -1466,15 +1458,14 @@ static void genesis_link_up(struct skge_port *skge) */ if (skge->flow_control == FLOW_MODE_NONE || skge->flow_control == FLOW_MODE_LOC_SEND) - /* Disable Pause Frame Reception */ cmd |= XM_MMU_IGN_PF; else /* Enable Pause Frame Reception */ cmd &= ~XM_MMU_IGN_PF; - xm_write16(hw, port, XM_MMU_CMD, cmd); + skge_xm_write16(hw, port, XM_MMU_CMD, cmd); - mode = xm_read32(hw, port, XM_MODE); + mode = skge_xm_read32(hw, port, XM_MODE); if (skge->flow_control == FLOW_MODE_SYMMETRIC || skge->flow_control == FLOW_MODE_LOC_SEND) { /* @@ -1488,10 +1479,10 @@ static void genesis_link_up(struct skge_port *skge) /* XM_PAUSE_DA = '010000C28001' (default) */ /* XM_MAC_PTIME = 0xffff (maximum) */ /* remember this value is defined in big endian (!) */ - xm_write16(hw, port, XM_MAC_PTIME, 0xffff); + skge_xm_write16(hw, port, XM_MAC_PTIME, 0xffff); mode |= XM_PAUSE_MODE; - skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE); + skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE); } else { /* * disable pause frame generation is required for 1000BT @@ -1500,68 +1491,125 @@ static void genesis_link_up(struct skge_port *skge) /* Disable Pause Mode in Mode Register */ mode &= ~XM_PAUSE_MODE; - skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE); + skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE); } - xm_write32(hw, port, XM_MODE, mode); + skge_xm_write32(hw, port, XM_MODE, mode); msk = XM_DEF_MSK; - /* disable GP0 interrupt bit for external Phy */ - msk |= XM_IS_INP_ASS; + if (hw->phy_type != SK_PHY_XMAC) + msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */ - xm_write16(hw, port, XM_IMSK, msk); - xm_read16(hw, port, XM_ISRC); + skge_xm_write16(hw, port, XM_IMSK, msk); + skge_xm_read16(hw, port, XM_ISRC); /* get MMU Command Reg. */ - cmd = xm_read16(hw, port, XM_MMU_CMD); - if (skge->duplex == DUPLEX_FULL) + cmd = skge_xm_read16(hw, port, XM_MMU_CMD); + if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL) cmd |= XM_MMU_GMII_FD; - /* - * Workaround BCOM Errata (#10523) for all BCom Phys - * Enable Power Management after link up - */ - xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, - xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL) - & ~PHY_B_AC_DIS_PM); - xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); + if (hw->phy_type == SK_PHY_BCOM) { + /* + * Workaround BCOM Errata (#10523) for all BCom Phys + * Enable Power Management after link up + */ + skge_xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, + skge_xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL) + & ~PHY_B_AC_DIS_PM); + skge_xm_phy_write(hw, port, PHY_BCOM_INT_MASK, + PHY_B_DEF_MSK); + } /* enable Rx/Tx */ - xm_write16(hw, port, XM_MMU_CMD, + skge_xm_write16(hw, port, XM_MMU_CMD, cmd | XM_MMU_ENA_RX | XM_MMU_ENA_TX); skge_link_up(skge); } -static inline void bcom_phy_intr(struct skge_port *skge) +static void genesis_bcom_intr(struct skge_port *skge) { struct skge_hw *hw = skge->hw; int port = skge->port; - u16 isrc; - - isrc = xm_phy_read(hw, port, PHY_BCOM_INT_STAT); - if (netif_msg_intr(skge)) - printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x\n", - skge->netdev->name, isrc); + u16 stat = skge_xm_phy_read(hw, port, PHY_BCOM_INT_STAT); - if (isrc & PHY_B_IS_PSE) - printk(KERN_ERR PFX "%s: uncorrectable pair swap error\n", - hw->dev[port]->name); + pr_debug("genesis_bcom intr stat=%x\n", stat); /* Workaround BCom Errata: * enable and disable loopback mode if "NO HCD" occurs. */ - if (isrc & PHY_B_IS_NO_HDCL) { - u16 ctrl = xm_phy_read(hw, port, PHY_BCOM_CTRL); - xm_phy_write(hw, port, PHY_BCOM_CTRL, + if (stat & PHY_B_IS_NO_HDCL) { + u16 ctrl = skge_xm_phy_read(hw, port, PHY_BCOM_CTRL); + skge_xm_phy_write(hw, port, PHY_BCOM_CTRL, ctrl | PHY_CT_LOOP); - xm_phy_write(hw, port, PHY_BCOM_CTRL, + skge_xm_phy_write(hw, port, PHY_BCOM_CTRL, ctrl & ~PHY_CT_LOOP); } - if (isrc & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) - bcom_check_link(hw, port); + stat = skge_xm_phy_read(hw, port, PHY_BCOM_STAT); + if (stat & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) { + u16 aux = skge_xm_phy_read(hw, port, PHY_BCOM_AUX_STAT); + if ( !(aux & PHY_B_AS_LS) && netif_carrier_ok(skge->netdev)) + genesis_link_down(skge); + + else if (stat & PHY_B_IS_LST_CHANGE) { + if (aux & PHY_B_AS_AN_C) { + switch (aux & PHY_B_AS_AN_RES_MSK) { + case PHY_B_RES_1000FD: + skge->duplex = DUPLEX_FULL; + break; + case PHY_B_RES_1000HD: + skge->duplex = DUPLEX_HALF; + break; + } + + switch (aux & PHY_B_AS_PAUSE_MSK) { + case PHY_B_AS_PAUSE_MSK: + skge->flow_control = FLOW_MODE_SYMMETRIC; + break; + case PHY_B_AS_PRR: + skge->flow_control = FLOW_MODE_REM_SEND; + break; + case PHY_B_AS_PRT: + skge->flow_control = FLOW_MODE_LOC_SEND; + break; + default: + skge->flow_control = FLOW_MODE_NONE; + } + skge->speed = SPEED_1000; + } + genesis_link_up(skge); + } + else + mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ); + } +} +/* Perodic poll of phy status to check for link transistion */ +static void skge_link_timer(unsigned long __arg) +{ + struct skge_port *skge = (struct skge_port *) __arg; + struct skge_hw *hw = skge->hw; + int port = skge->port; + + if (hw->chip_id != CHIP_ID_GENESIS || !netif_running(skge->netdev)) + return; + + spin_lock_bh(&hw->phy_lock); + if (hw->phy_type == SK_PHY_BCOM) + genesis_bcom_intr(skge); + else { + int i; + for (i = 0; i < 3; i++) + if (skge_xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS) + break; + + if (i == 3) + mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ); + else + genesis_link_up(skge); + } + spin_unlock_bh(&hw->phy_lock); } /* Marvell Phy Initailization */ @@ -1573,27 +1621,31 @@ static void yukon_init(struct skge_hw *hw, int port) pr_debug("yukon_init\n"); if (skge->autoneg == AUTONEG_ENABLE) { - u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); + u16 ectrl = skge_gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK | PHY_M_EC_MAC_S_MSK); ectrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ); - ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1); + /* on PHY 88E1111 there is a change for downshift control */ + if (hw->chip_id == CHIP_ID_YUKON_EC) + ectrl |= PHY_M_EC_M_DSC_2(0) | PHY_M_EC_DOWN_S_ENA; + else + ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1); - gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl); + skge_gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl); } - ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL); + ctrl = skge_gm_phy_read(hw, port, PHY_MARV_CTRL); if (skge->autoneg == AUTONEG_DISABLE) ctrl &= ~PHY_CT_ANE; ctrl |= PHY_CT_RESET; - gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); + skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); ctrl = 0; ct1000 = 0; - adv = PHY_AN_CSMA; + adv = PHY_SEL_TYPE; if (skge->autoneg == AUTONEG_ENABLE) { if (iscopper(hw)) { @@ -1609,12 +1661,41 @@ static void yukon_init(struct skge_hw *hw, int port) adv |= PHY_M_AN_10_FD; if (skge->advertising & ADVERTISED_10baseT_Half) adv |= PHY_M_AN_10_HD; - } else /* special defines for FIBER (88E1011S only) */ - adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD; - /* Set Flow-control capabilities */ - adv |= phy_pause_map[skge->flow_control]; + /* Set Flow-control capabilities */ + switch (skge->flow_control) { + case FLOW_MODE_NONE: + adv |= PHY_B_P_NO_PAUSE; + break; + case FLOW_MODE_LOC_SEND: + adv |= PHY_B_P_ASYM_MD; + break; + case FLOW_MODE_SYMMETRIC: + adv |= PHY_B_P_SYM_MD; + break; + case FLOW_MODE_REM_SEND: + adv |= PHY_B_P_BOTH_MD; + break; + } + } else { /* special defines for FIBER (88E1011S only) */ + adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD; + /* Set Flow-control capabilities */ + switch (skge->flow_control) { + case FLOW_MODE_NONE: + adv |= PHY_M_P_NO_PAUSE_X; + break; + case FLOW_MODE_LOC_SEND: + adv |= PHY_M_P_ASYM_MD_X; + break; + case FLOW_MODE_SYMMETRIC: + adv |= PHY_M_P_SYM_MD_X; + break; + case FLOW_MODE_REM_SEND: + adv |= PHY_M_P_BOTH_MD_X; + break; + } + } /* Restart Auto-negotiation */ ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG; } else { @@ -1636,23 +1717,36 @@ static void yukon_init(struct skge_hw *hw, int port) ctrl |= PHY_CT_RESET; } - gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000); + if (hw->chip_id != CHIP_ID_YUKON_FE) + skge_gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000); - gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv); - gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); + skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv); + skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); /* Setup Phy LED's */ ledctrl = PHY_M_LED_PULS_DUR(PULS_170MS); ledover = 0; - ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL; + if (hw->chip_id == CHIP_ID_YUKON_FE) { + /* on 88E3082 these bits are at 11..9 (shifted left) */ + ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) << 1; + + skge_gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, + ((skge_gm_phy_read(hw, port, PHY_MARV_FE_LED_PAR) + + & ~PHY_M_FELP_LED1_MSK) + | PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_ACT_BL))); + } else { + /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */ + ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL; - /* turn off the Rx LED (LED_RX) */ - ledover |= PHY_M_LED_MO_RX(MO_LED_OFF); + /* turn off the Rx LED (LED_RX) */ + ledover |= PHY_M_LED_MO_RX(MO_LED_OFF); + } /* disable blink mode (LED_DUPLEX) on collisions */ ctrl |= PHY_M_LEDC_DP_CTRL; - gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); + skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); if (skge->autoneg == AUTONEG_DISABLE || skge->speed == SPEED_100) { /* turn on 100 Mbps LED (LED_LINK100) */ @@ -1660,25 +1754,25 @@ static void yukon_init(struct skge_hw *hw, int port) } if (ledover) - gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover); + skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover); /* Enable phy interrupt on autonegotiation complete (or link up) */ if (skge->autoneg == AUTONEG_ENABLE) - gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL); + skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL); else - gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); + skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); } static void yukon_reset(struct skge_hw *hw, int port) { - gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);/* disable PHY IRQs */ - gma_write16(hw, port, GM_MC_ADDR_H1, 0); /* clear MC hash */ - gma_write16(hw, port, GM_MC_ADDR_H2, 0); - gma_write16(hw, port, GM_MC_ADDR_H3, 0); - gma_write16(hw, port, GM_MC_ADDR_H4, 0); + skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);/* disable PHY IRQs */ + skge_gma_write16(hw, port, GM_MC_ADDR_H1, 0); /* clear MC hash */ + skge_gma_write16(hw, port, GM_MC_ADDR_H2, 0); + skge_gma_write16(hw, port, GM_MC_ADDR_H3, 0); + skge_gma_write16(hw, port, GM_MC_ADDR_H4, 0); - gma_write16(hw, port, GM_RX_CTRL, - gma_read16(hw, port, GM_RX_CTRL) + skge_gma_write16(hw, port, GM_RX_CTRL, + skge_gma_read16(hw, port, GM_RX_CTRL) | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); } @@ -1691,17 +1785,17 @@ static void yukon_mac_init(struct skge_hw *hw, int port) /* WA code for COMA mode -- set PHY reset */ if (hw->chip_id == CHIP_ID_YUKON_LITE && - hw->chip_rev == CHIP_REV_YU_LITE_A3) + chip_rev(hw) == CHIP_REV_YU_LITE_A3) skge_write32(hw, B2_GP_IO, (skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9)); /* hard reset */ - skge_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); - skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET); + skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), GPC_RST_SET); + skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_RST_SET); /* WA code for COMA mode -- clear PHY reset */ if (hw->chip_id == CHIP_ID_YUKON_LITE && - hw->chip_rev == CHIP_REV_YU_LITE_A3) + chip_rev(hw) == CHIP_REV_YU_LITE_A3) skge_write32(hw, B2_GP_IO, (skge_read32(hw, B2_GP_IO) | GP_DIR_9) & ~GP_IO_9); @@ -1712,13 +1806,13 @@ static void yukon_mac_init(struct skge_hw *hw, int port) reg |= iscopper(hw) ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB; /* Clear GMC reset */ - skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_SET); - skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_CLR); - skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR); + skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), reg | GPC_RST_SET); + skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), reg | GPC_RST_CLR); + skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR); if (skge->autoneg == AUTONEG_DISABLE) { reg = GM_GPCR_AU_ALL_DIS; - gma_write16(hw, port, GM_GP_CTRL, - gma_read16(hw, port, GM_GP_CTRL) | reg); + skge_gma_write16(hw, port, GM_GP_CTRL, + skge_gma_read16(hw, port, GM_GP_CTRL) | reg); switch (skge->speed) { case SPEED_1000: @@ -1734,7 +1828,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port) reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL; switch (skge->flow_control) { case FLOW_MODE_NONE: - skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); + skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); reg |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; break; case FLOW_MODE_LOC_SEND: @@ -1742,7 +1836,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port) reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; } - gma_write16(hw, port, GM_GP_CTRL, reg); + skge_gma_write16(hw, port, GM_GP_CTRL, reg); skge_read16(hw, GMAC_IRQ_SRC); spin_lock_bh(&hw->phy_lock); @@ -1750,25 +1844,25 @@ static void yukon_mac_init(struct skge_hw *hw, int port) spin_unlock_bh(&hw->phy_lock); /* MIB clear */ - reg = gma_read16(hw, port, GM_PHY_ADDR); - gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR); + reg = skge_gma_read16(hw, port, GM_PHY_ADDR); + skge_gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR); for (i = 0; i < GM_MIB_CNT_SIZE; i++) - gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i); - gma_write16(hw, port, GM_PHY_ADDR, reg); + skge_gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i); + skge_gma_write16(hw, port, GM_PHY_ADDR, reg); /* transmit control */ - gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF)); + skge_gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF)); /* receive control reg: unicast + multicast + no FCS */ - gma_write16(hw, port, GM_RX_CTRL, + skge_gma_write16(hw, port, GM_RX_CTRL, GM_RXCR_UCF_ENA | GM_RXCR_CRC_DIS | GM_RXCR_MCF_ENA); /* transmit flow control */ - gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff); + skge_gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff); /* transmit parameter */ - gma_write16(hw, port, GM_TX_PARAM, + skge_gma_write16(hw, port, GM_TX_PARAM, TX_JAM_LEN_VAL(TX_JAM_LEN_DEF) | TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) | TX_IPG_JAM_DATA(TX_IPG_JAM_DEF)); @@ -1778,33 +1872,33 @@ static void yukon_mac_init(struct skge_hw *hw, int port) if (hw->dev[port]->mtu > 1500) reg |= GM_SMOD_JUMBO_ENA; - gma_write16(hw, port, GM_SERIAL_MODE, reg); + skge_gma_write16(hw, port, GM_SERIAL_MODE, reg); /* physical address: used for pause frames */ - gma_set_addr(hw, port, GM_SRC_ADDR_1L, addr); + skge_gm_set_addr(hw, port, GM_SRC_ADDR_1L, addr); /* virtual address for data */ - gma_set_addr(hw, port, GM_SRC_ADDR_2L, addr); + skge_gm_set_addr(hw, port, GM_SRC_ADDR_2L, addr); /* enable interrupt mask for counter overflows */ - gma_write16(hw, port, GM_TX_IRQ_MSK, 0); - gma_write16(hw, port, GM_RX_IRQ_MSK, 0); - gma_write16(hw, port, GM_TR_IRQ_MSK, 0); + skge_gma_write16(hw, port, GM_TX_IRQ_MSK, 0); + skge_gma_write16(hw, port, GM_RX_IRQ_MSK, 0); + skge_gma_write16(hw, port, GM_TR_IRQ_MSK, 0); /* Initialize Mac Fifo */ /* Configure Rx MAC FIFO */ - skge_write16(hw, SK_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK); + skge_write16(hw, SKGEMAC_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK); reg = GMF_OPER_ON | GMF_RX_F_FL_ON; if (hw->chip_id == CHIP_ID_YUKON_LITE && - hw->chip_rev == CHIP_REV_YU_LITE_A3) + chip_rev(hw) == CHIP_REV_YU_LITE_A3) reg &= ~GMF_RX_F_FL_ON; - skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR); - skge_write16(hw, SK_REG(port, RX_GMF_CTRL_T), reg); - skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF); + skge_write8(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR); + skge_write16(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), reg); + skge_write16(hw, SKGEMAC_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF); /* Configure Tx MAC FIFO */ - skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); - skge_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); + skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); + skge_write16(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); } static void yukon_stop(struct skge_port *skge) @@ -1813,19 +1907,19 @@ static void yukon_stop(struct skge_port *skge) int port = skge->port; if (hw->chip_id == CHIP_ID_YUKON_LITE && - hw->chip_rev == CHIP_REV_YU_LITE_A3) { + chip_rev(hw) == CHIP_REV_YU_LITE_A3) { skge_write32(hw, B2_GP_IO, skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9); } - gma_write16(hw, port, GM_GP_CTRL, - gma_read16(hw, port, GM_GP_CTRL) + skge_gma_write16(hw, port, GM_GP_CTRL, + skge_gma_read16(hw, port, GM_GP_CTRL) & ~(GM_GPCR_RX_ENA|GM_GPCR_RX_ENA)); - gma_read16(hw, port, GM_GP_CTRL); + skge_gma_read16(hw, port, GM_GP_CTRL); /* set GPHY Control reset */ - gma_write32(hw, port, GPHY_CTRL, GPC_RST_SET); - gma_write32(hw, port, GMAC_CTRL, GMC_RST_SET); + skge_gma_write32(hw, port, GPHY_CTRL, GPC_RST_SET); + skge_gma_write32(hw, port, GMAC_CTRL, GMC_RST_SET); } static void yukon_get_stats(struct skge_port *skge, u64 *data) @@ -1834,40 +1928,39 @@ static void yukon_get_stats(struct skge_port *skge, u64 *data) int port = skge->port; int i; - data[0] = (u64) gma_read32(hw, port, GM_TXO_OK_HI) << 32 - | gma_read32(hw, port, GM_TXO_OK_LO); - data[1] = (u64) gma_read32(hw, port, GM_RXO_OK_HI) << 32 - | gma_read32(hw, port, GM_RXO_OK_LO); + data[0] = (u64) skge_gma_read32(hw, port, GM_TXO_OK_HI) << 32 + | skge_gma_read32(hw, port, GM_TXO_OK_LO); + data[1] = (u64) skge_gma_read32(hw, port, GM_RXO_OK_HI) << 32 + | skge_gma_read32(hw, port, GM_RXO_OK_LO); for (i = 2; i < ARRAY_SIZE(skge_stats); i++) - data[i] = gma_read32(hw, port, + data[i] = skge_gma_read32(hw, port, skge_stats[i].gma_offset); } static void yukon_mac_intr(struct skge_hw *hw, int port) { - struct net_device *dev = hw->dev[port]; - struct skge_port *skge = netdev_priv(dev); - u8 status = skge_read8(hw, SK_REG(port, GMAC_IRQ_SRC)); - - if (netif_msg_intr(skge)) - printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", - dev->name, status); + struct skge_port *skge = netdev_priv(hw->dev[port]); + u8 status = skge_read8(hw, SKGEMAC_REG(port, GMAC_IRQ_SRC)); + pr_debug("yukon_intr status %x\n", status); if (status & GM_IS_RX_FF_OR) { ++skge->net_stats.rx_fifo_errors; - gma_write8(hw, port, RX_GMF_CTRL_T, GMF_CLI_RX_FO); + skge_gma_write8(hw, port, RX_GMF_CTRL_T, GMF_CLI_RX_FO); } if (status & GM_IS_TX_FF_UR) { ++skge->net_stats.tx_fifo_errors; - gma_write8(hw, port, TX_GMF_CTRL_T, GMF_CLI_TX_FU); + skge_gma_write8(hw, port, TX_GMF_CTRL_T, GMF_CLI_TX_FU); } } static u16 yukon_speed(const struct skge_hw *hw, u16 aux) { - switch (aux & PHY_M_PS_SPEED_MSK) { + if (hw->chip_id == CHIP_ID_YUKON_FE) + return (aux & PHY_M_PS_SPEED_100) ? SPEED_100 : SPEED_10; + + switch(aux & PHY_M_PS_SPEED_MSK) { case PHY_M_PS_SPEED_1000: return SPEED_1000; case PHY_M_PS_SPEED_100: @@ -1888,15 +1981,15 @@ static void yukon_link_up(struct skge_port *skge) /* Enable Transmit FIFO Underrun */ skge_write8(hw, GMAC_IRQ_MSK, GMAC_DEF_MSK); - reg = gma_read16(hw, port, GM_GP_CTRL); + reg = skge_gma_read16(hw, port, GM_GP_CTRL); if (skge->duplex == DUPLEX_FULL || skge->autoneg == AUTONEG_ENABLE) reg |= GM_GPCR_DUP_FULL; /* enable Rx/Tx */ reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA; - gma_write16(hw, port, GM_GP_CTRL, reg); + skge_gma_write16(hw, port, GM_GP_CTRL, reg); - gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); + skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); skge_link_up(skge); } @@ -1906,15 +1999,16 @@ static void yukon_link_down(struct skge_port *skge) int port = skge->port; pr_debug("yukon_link_down\n"); - gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0); - gm_phy_write(hw, port, GM_GP_CTRL, - gm_phy_read(hw, port, GM_GP_CTRL) + skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0); + skge_gm_phy_write(hw, port, GM_GP_CTRL, + skge_gm_phy_read(hw, port, GM_GP_CTRL) & ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA)); - if (skge->flow_control == FLOW_MODE_REM_SEND) { + if (hw->chip_id != CHIP_ID_YUKON_FE && + skge->flow_control == FLOW_MODE_REM_SEND) { /* restore Asymmetric Pause bit */ - gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, - gm_phy_read(hw, port, + skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, + skge_gm_phy_read(hw, port, PHY_MARV_AUNE_ADV) | PHY_M_AN_ASP); @@ -1933,21 +2027,20 @@ static void yukon_phy_intr(struct skge_port *skge) const char *reason = NULL; u16 istatus, phystat; - istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT); - phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT); - - if (netif_msg_intr(skge)) - printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x 0x%x\n", - skge->netdev->name, istatus, phystat); + istatus = skge_gm_phy_read(hw, port, PHY_MARV_INT_STAT); + phystat = skge_gm_phy_read(hw, port, PHY_MARV_PHY_STAT); + pr_debug("yukon phy intr istat=%x phy_stat=%x\n", istatus, phystat); if (istatus & PHY_M_IS_AN_COMPL) { - if (gm_phy_read(hw, port, PHY_MARV_AUNE_LP) + if (skge_gm_phy_read(hw, port, PHY_MARV_AUNE_LP) & PHY_M_AN_RF) { reason = "remote fault"; goto failed; } - if (gm_phy_read(hw, port, PHY_MARV_1000T_STAT) & PHY_B_1000S_MSF) { + if (!(hw->chip_id == CHIP_ID_YUKON_FE || hw->chip_id == CHIP_ID_YUKON_EC) + && (skge_gm_phy_read(hw, port, PHY_MARV_1000T_STAT) + & PHY_B_1000S_MSF)) { reason = "master/slave fault"; goto failed; } @@ -1961,6 +2054,10 @@ static void yukon_phy_intr(struct skge_port *skge) ? DUPLEX_FULL : DUPLEX_HALF; skge->speed = yukon_speed(hw, phystat); + /* Tx & Rx Pause Enabled bits are at 9..8 */ + if (hw->chip_id == CHIP_ID_YUKON_XL) + phystat >>= 6; + /* We are using IEEE 802.3z/D5.0 Table 37-4 */ switch (phystat & PHY_M_PS_PAUSE_MSK) { case PHY_M_PS_PAUSE_MSK: @@ -1978,9 +2075,9 @@ static void yukon_phy_intr(struct skge_port *skge) if (skge->flow_control == FLOW_MODE_NONE || (skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF)) - skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); + skge_write8(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); else - skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); + skge_write8(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_ON); yukon_link_up(skge); return; } @@ -2064,12 +2161,6 @@ static int skge_up(struct net_device *dev) if (netif_msg_ifup(skge)) printk(KERN_INFO PFX "%s: enabling interface\n", dev->name); - if (dev->mtu > RX_BUF_SIZE) - skge->rx_buf_size = dev->mtu + ETH_HLEN + NET_IP_ALIGN; - else - skge->rx_buf_size = RX_BUF_SIZE; - - rx_size = skge->rx_ring.count * sizeof(struct skge_rx_desc); tx_size = skge->tx_ring.count * sizeof(struct skge_tx_desc); skge->mem_size = tx_size + rx_size; @@ -2082,8 +2173,7 @@ static int skge_up(struct net_device *dev) if ((err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma))) goto free_pci_mem; - err = skge_rx_fill(skge); - if (err) + if (skge_rx_fill(skge)) goto free_rx_ring; if ((err = skge_ring_alloc(&skge->tx_ring, skge->mem + rx_size, @@ -2092,10 +2182,6 @@ static int skge_up(struct net_device *dev) skge->tx_avail = skge->tx_ring.count - 1; - /* Enable IRQ from port */ - hw->intr_mask |= portirqmask[port]; - skge_write32(hw, B0_IMSK, hw->intr_mask); - /* Initialze MAC */ if (hw->chip_id == CHIP_ID_GENESIS) genesis_mac_init(hw, port); @@ -2103,7 +2189,7 @@ static int skge_up(struct net_device *dev) yukon_mac_init(hw, port); /* Configure RAMbuffers */ - chunk = hw->ram_size / ((hw->ports + 1)*2); + chunk = hw->ram_size / (isdualport(hw) ? 4 : 2); ram_addr = hw->ram_offset + 2 * chunk * port; skge_ramset(hw, rxqaddr[port], ram_addr, chunk); @@ -2141,6 +2227,7 @@ static int skge_down(struct net_device *dev) netif_stop_queue(dev); del_timer_sync(&skge->led_blink); + del_timer_sync(&skge->link_check); /* Stop transmitter */ skge_write8(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_STOP); @@ -2153,12 +2240,12 @@ static int skge_down(struct net_device *dev) yukon_stop(skge); /* Disable Force Sync bit and Enable Alloc bit */ - skge_write8(hw, SK_REG(port, TXA_CTRL), + skge_write8(hw, SKGEMAC_REG(port, TXA_CTRL), TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); /* Stop Interval Timer and Limit Counter of Tx Arbiter */ - skge_write32(hw, SK_REG(port, TXA_ITI_INI), 0L); - skge_write32(hw, SK_REG(port, TXA_LIM_INI), 0L); + skge_write32(hw, SKGEMAC_REG(port, TXA_ITI_INI), 0L); + skge_write32(hw, SKGEMAC_REG(port, TXA_LIM_INI), 0L); /* Reset PCI FIFO */ skge_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_SET_RESET); @@ -2173,13 +2260,13 @@ static int skge_down(struct net_device *dev) skge_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_SET_RESET); if (hw->chip_id == CHIP_ID_GENESIS) { - skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_SET); - skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_SET); - skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_STOP); - skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_STOP); + skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_RST_SET); + skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_RST_SET); + skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_STOP); + skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_STOP); } else { - skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); - skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); + skge_write8(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); + skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); } /* turn off led's */ @@ -2212,10 +2299,10 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) local_irq_save(flags); if (!spin_trylock(&skge->tx_lock)) { - /* Collision - tell upper layer to requeue */ - local_irq_restore(flags); - return NETDEV_TX_LOCKED; - } + /* Collision - tell upper layer to requeue */ + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } if (unlikely(skge->tx_avail < skb_shinfo(skb)->nr_frags +1)) { netif_stop_queue(dev); @@ -2246,7 +2333,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) * does. Looks like hardware is wrong? */ if (ip->protocol == IPPROTO_UDP - && hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON) + && chip_rev(hw) == 0 && hw->chip_id == CHIP_ID_YUKON) control = BMU_TCP_CHECK; else control = BMU_UDP_CHECK; @@ -2307,7 +2394,6 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) static inline void skge_tx_free(struct skge_hw *hw, struct skge_element *e) { - /* This ring element can be skb or fragment */ if (e->skb) { pci_unmap_single(hw->pdev, pci_unmap_addr(e, mapaddr), @@ -2352,17 +2438,16 @@ static void skge_tx_timeout(struct net_device *dev) static int skge_change_mtu(struct net_device *dev, int new_mtu) { int err = 0; - int running = netif_running(dev); - if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) + if(new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) return -EINVAL; + dev->mtu = new_mtu; - if (running) + if (netif_running(dev)) { skge_down(dev); - dev->mtu = new_mtu; - if (running) skge_up(dev); + } return err; } @@ -2377,9 +2462,7 @@ static void genesis_set_multicast(struct net_device *dev) u32 mode; u8 filter[8]; - pr_debug("genesis_set_multicast flags=%x count=%d\n", dev->flags, dev->mc_count); - - mode = xm_read32(hw, port, XM_MODE); + mode = skge_xm_read32(hw, port, XM_MODE); mode |= XM_MD_ENA_HASH; if (dev->flags & IFF_PROMISC) mode |= XM_MD_ENA_PROM; @@ -2390,16 +2473,17 @@ static void genesis_set_multicast(struct net_device *dev) memset(filter, 0xff, sizeof(filter)); else { memset(filter, 0, sizeof(filter)); - for (i = 0; list && i < count; i++, list = list->next) { - u32 crc, bit; - crc = ether_crc_le(ETH_ALEN, list->dmi_addr); - bit = ~crc & 0x3f; + for(i = 0; list && i < count; i++, list = list->next) { + u32 crc = crc32_le(~0, list->dmi_addr, ETH_ALEN); + u8 bit = 63 - (crc & 63); + filter[bit/8] |= 1 << (bit%8); } } - xm_write32(hw, port, XM_MODE, mode); - xm_outhash(hw, port, XM_HSM, filter); + skge_xm_outhash(hw, port, XM_HSM, filter); + + skge_xm_write32(hw, port, XM_MODE, mode); } static void yukon_set_multicast(struct net_device *dev) @@ -2413,7 +2497,7 @@ static void yukon_set_multicast(struct net_device *dev) memset(filter, 0, sizeof(filter)); - reg = gma_read16(hw, port, GM_RX_CTRL); + reg = skge_gma_read16(hw, port, GM_RX_CTRL); reg |= GM_RXCR_UCF_ENA; if (dev->flags & IFF_PROMISC) /* promiscious */ @@ -2426,23 +2510,23 @@ static void yukon_set_multicast(struct net_device *dev) int i; reg |= GM_RXCR_MCF_ENA; - for (i = 0; list && i < dev->mc_count; i++, list = list->next) { + for(i = 0; list && i < dev->mc_count; i++, list = list->next) { u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f; filter[bit/8] |= 1 << (bit%8); } } - gma_write16(hw, port, GM_MC_ADDR_H1, + skge_gma_write16(hw, port, GM_MC_ADDR_H1, (u16)filter[0] | ((u16)filter[1] << 8)); - gma_write16(hw, port, GM_MC_ADDR_H2, + skge_gma_write16(hw, port, GM_MC_ADDR_H2, (u16)filter[2] | ((u16)filter[3] << 8)); - gma_write16(hw, port, GM_MC_ADDR_H3, + skge_gma_write16(hw, port, GM_MC_ADDR_H3, (u16)filter[4] | ((u16)filter[5] << 8)); - gma_write16(hw, port, GM_MC_ADDR_H4, + skge_gma_write16(hw, port, GM_MC_ADDR_H4, (u16)filter[6] | ((u16)filter[7] << 8)); - gma_write16(hw, port, GM_RX_CTRL, reg); + skge_gma_write16(hw, port, GM_RX_CTRL, reg); } static inline int bad_phy_status(const struct skge_hw *hw, u32 status) @@ -2461,76 +2545,28 @@ static void skge_rx_error(struct skge_port *skge, int slot, printk(KERN_DEBUG PFX "%s: rx err, slot %d control 0x%x status 0x%x\n", skge->netdev->name, slot, control, status); - if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)) + if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF) + || (control & BMU_BBC) > skge->netdev->mtu + VLAN_ETH_HLEN) skge->net_stats.rx_length_errors++; - else if (skge->hw->chip_id == CHIP_ID_GENESIS) { - if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR)) - skge->net_stats.rx_length_errors++; - if (status & XMR_FS_FRA_ERR) - skge->net_stats.rx_frame_errors++; - if (status & XMR_FS_FCS_ERR) - skge->net_stats.rx_crc_errors++; - } else { - if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE)) - skge->net_stats.rx_length_errors++; - if (status & GMR_FS_FRAGMENT) - skge->net_stats.rx_frame_errors++; - if (status & GMR_FS_CRC_ERR) - skge->net_stats.rx_crc_errors++; - } -} - -/* Get receive buffer from descriptor. - * Handles copy of small buffers and reallocation failures - */ -static inline struct sk_buff *skge_rx_get(struct skge_port *skge, - struct skge_element *e, - unsigned int len) -{ - struct sk_buff *nskb, *skb; - - if (len < RX_COPY_THRESHOLD) { - nskb = skge_rx_alloc(skge->netdev, len + NET_IP_ALIGN); - if (unlikely(!nskb)) - return NULL; - - pci_dma_sync_single_for_cpu(skge->hw->pdev, - pci_unmap_addr(e, mapaddr), - len, PCI_DMA_FROMDEVICE); - memcpy(nskb->data, e->skb->data, len); - pci_dma_sync_single_for_device(skge->hw->pdev, - pci_unmap_addr(e, mapaddr), - len, PCI_DMA_FROMDEVICE); - - if (skge->rx_csum) { - struct skge_rx_desc *rd = e->desc; - nskb->csum = le16_to_cpu(rd->csum2); - nskb->ip_summed = CHECKSUM_HW; - } - skge_rx_reuse(e, skge->rx_buf_size); - return nskb; - } else { - nskb = skge_rx_alloc(skge->netdev, skge->rx_buf_size); - if (unlikely(!nskb)) - return NULL; - - pci_unmap_single(skge->hw->pdev, - pci_unmap_addr(e, mapaddr), - pci_unmap_len(e, maplen), - PCI_DMA_FROMDEVICE); - skb = e->skb; - if (skge->rx_csum) { - struct skge_rx_desc *rd = e->desc; - skb->csum = le16_to_cpu(rd->csum2); - skb->ip_summed = CHECKSUM_HW; + else { + if (skge->hw->chip_id == CHIP_ID_GENESIS) { + if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR)) + skge->net_stats.rx_length_errors++; + if (status & XMR_FS_FRA_ERR) + skge->net_stats.rx_frame_errors++; + if (status & XMR_FS_FCS_ERR) + skge->net_stats.rx_crc_errors++; + } else { + if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE)) + skge->net_stats.rx_length_errors++; + if (status & GMR_FS_FRAGMENT) + skge->net_stats.rx_frame_errors++; + if (status & GMR_FS_CRC_ERR) + skge->net_stats.rx_crc_errors++; } - - skge_rx_setup(skge, e, nskb, skge->rx_buf_size); - return skb; } } - static int skge_poll(struct net_device *dev, int *budget) { struct skge_port *skge = netdev_priv(dev); @@ -2539,12 +2575,13 @@ static int skge_poll(struct net_device *dev, int *budget) struct skge_element *e; unsigned int to_do = min(dev->quota, *budget); unsigned int work_done = 0; + int done; + static const u32 irqmask[] = { IS_PORT_1, IS_PORT_2 }; - pr_debug("skge_poll\n"); - - for (e = ring->to_clean; work_done < to_do; e = e->next) { + for (e = ring->to_clean; e != ring->to_use && work_done < to_do; + e = e->next) { struct skge_rx_desc *rd = e->desc; - struct sk_buff *skb; + struct sk_buff *skb = e->skb; u32 control, len, status; rmb(); @@ -2553,12 +2590,19 @@ static int skge_poll(struct net_device *dev, int *budget) break; len = control & BMU_BBC; - status = rd->status; + e->skb = NULL; + + pci_unmap_single(hw->pdev, + pci_unmap_addr(e, mapaddr), + pci_unmap_len(e, maplen), + PCI_DMA_FROMDEVICE); - if (unlikely((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF) - || bad_phy_status(hw, status))) { + status = rd->status; + if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF) + || len > dev->mtu + VLAN_ETH_HLEN + || bad_phy_status(hw, status)) { skge_rx_error(skge, e - ring->start, control, status); - skge_rx_reuse(e, skge->rx_buf_size); + dev_kfree_skb(skb); continue; } @@ -2566,37 +2610,43 @@ static int skge_poll(struct net_device *dev, int *budget) printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n", dev->name, e - ring->start, rd->status, len); - skb = skge_rx_get(skge, e, len); - if (likely(skb)) { - skb_put(skb, len); - skb->protocol = eth_type_trans(skb, dev); + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; - netif_receive_skb(skb); + if (skge->rx_csum) { + skb->csum = le16_to_cpu(rd->csum2); + skb->ip_summed = CHECKSUM_HW; + } - ++work_done; - } else - skge_rx_reuse(e, skge->rx_buf_size); + dev->last_rx = jiffies; + netif_receive_skb(skb); + + ++work_done; } ring->to_clean = e; + *budget -= work_done; + dev->quota -= work_done; + done = work_done < to_do; + + if (skge_rx_fill(skge)) + done = 0; + /* restart receiver */ wmb(); skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_START | CSR_IRQ_CL_F); - *budget -= work_done; - dev->quota -= work_done; - - if (work_done >= to_do) - return 1; /* not done */ + if (done) { + local_irq_disable(); + hw->intr_mask |= irqmask[skge->port]; + /* Order is important since data can get interrupted */ + skge_write32(hw, B0_IMSK, hw->intr_mask); + __netif_rx_complete(dev); + local_irq_enable(); + } - local_irq_disable(); - __netif_rx_complete(dev); - hw->intr_mask |= portirqmask[skge->port]; - skge_write32(hw, B0_IMSK, hw->intr_mask); - local_irq_enable(); - return 0; + return !done; } static inline void skge_tx_intr(struct net_device *dev) @@ -2607,7 +2657,7 @@ static inline void skge_tx_intr(struct net_device *dev) struct skge_element *e; spin_lock(&skge->tx_lock); - for (e = ring->to_clean; e != ring->to_use; e = e->next) { + for(e = ring->to_clean; e != ring->to_use; e = e->next) { struct skge_tx_desc *td = e->desc; u32 control; @@ -2640,12 +2690,12 @@ static void skge_mac_parity(struct skge_hw *hw, int port) : (port == 0 ? "(port A)": "(port B")); if (hw->chip_id == CHIP_ID_GENESIS) - skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), + skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_CLR_PERR); else /* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */ - skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), - (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0) + skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), + (hw->chip_id == CHIP_ID_YUKON && chip_rev(hw) == 0) ? GMF_CLI_TX_FC : GMF_CLI_TX_PE); } @@ -2653,16 +2703,16 @@ static void skge_pci_clear(struct skge_hw *hw) { u16 status; - pci_read_config_word(hw->pdev, PCI_STATUS, &status); + status = skge_read16(hw, SKGEPCI_REG(PCI_STATUS)); skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); - pci_write_config_word(hw->pdev, PCI_STATUS, - status | PCI_STATUS_ERROR_BITS); + skge_write16(hw, SKGEPCI_REG(PCI_STATUS), + status | PCI_STATUS_ERROR_BITS); skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); } static void skge_mac_intr(struct skge_hw *hw, int port) { - if (hw->chip_id == CHIP_ID_GENESIS) + if (hw->chip_id == CHIP_ID_GENESIS) genesis_mac_intr(hw, port); else yukon_mac_intr(hw, port); @@ -2676,9 +2726,9 @@ static void skge_error_irq(struct skge_hw *hw) if (hw->chip_id == CHIP_ID_GENESIS) { /* clear xmac errors */ if (hwstatus & (IS_NO_STAT_M1|IS_NO_TIST_M1)) - skge_write16(hw, SK_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT); + skge_write16(hw, SKGEMAC_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT); if (hwstatus & (IS_NO_STAT_M2|IS_NO_TIST_M2)) - skge_write16(hw, SK_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT); + skge_write16(hw, SKGEMAC_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT); } else { /* Timestamp (unused) overflow */ if (hwstatus & IS_IRQ_TIST_OV) @@ -2753,8 +2803,8 @@ static void skge_extirq(unsigned long data) if (hw->chip_id != CHIP_ID_GENESIS) yukon_phy_intr(skge); - else - bcom_phy_intr(skge); + else if (hw->phy_type == SK_PHY_BCOM) + genesis_bcom_intr(skge); } } spin_unlock(&hw->phy_lock); @@ -2774,14 +2824,19 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; status &= hw->intr_mask; - if (status & IS_R1_F) { + + if ((status & IS_R1_F) && netif_rx_schedule_prep(hw->dev[0])) { + status &= ~IS_R1_F; hw->intr_mask &= ~IS_R1_F; - netif_rx_schedule(hw->dev[0]); + skge_write32(hw, B0_IMSK, hw->intr_mask); + __netif_rx_schedule(hw->dev[0]); } - if (status & IS_R2_F) { + if ((status & IS_R2_F) && netif_rx_schedule_prep(hw->dev[1])) { + status &= ~IS_R2_F; hw->intr_mask &= ~IS_R2_F; - netif_rx_schedule(hw->dev[1]); + skge_write32(hw, B0_IMSK, hw->intr_mask); + __netif_rx_schedule(hw->dev[1]); } if (status & IS_XA1_F) @@ -2790,27 +2845,9 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) if (status & IS_XA2_F) skge_tx_intr(hw->dev[1]); - if (status & IS_PA_TO_RX1) { - struct skge_port *skge = netdev_priv(hw->dev[0]); - ++skge->net_stats.rx_over_errors; - skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX1); - } - - if (status & IS_PA_TO_RX2) { - struct skge_port *skge = netdev_priv(hw->dev[1]); - ++skge->net_stats.rx_over_errors; - skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2); - } - - if (status & IS_PA_TO_TX1) - skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX1); - - if (status & IS_PA_TO_TX2) - skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX2); - if (status & IS_MAC1) skge_mac_intr(hw, 0); - + if (status & IS_MAC2) skge_mac_intr(hw, 1); @@ -2822,7 +2859,8 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) tasklet_schedule(&hw->ext_tasklet); } - skge_write32(hw, B0_IMSK, hw->intr_mask); + if (status) + skge_write32(hw, B0_IMSK, hw->intr_mask); return IRQ_HANDLED; } @@ -2866,6 +2904,9 @@ static const struct { { CHIP_ID_YUKON, "Yukon" }, { CHIP_ID_YUKON_LITE, "Yukon-Lite"}, { CHIP_ID_YUKON_LP, "Yukon-LP"}, + { CHIP_ID_YUKON_XL, "Yukon-2 XL"}, + { CHIP_ID_YUKON_EC, "YUKON-2 EC"}, + { CHIP_ID_YUKON_FE, "YUKON-2 FE"}, }; static const char *skge_board_name(const struct skge_hw *hw) @@ -2889,8 +2930,8 @@ static const char *skge_board_name(const struct skge_hw *hw) static int skge_reset(struct skge_hw *hw) { u16 ctst; - u8 t8, mac_cfg; - int i; + u8 t8; + int i, ports; ctst = skge_read16(hw, B0_CTST); @@ -2911,9 +2952,12 @@ static int skge_reset(struct skge_hw *hw) hw->phy_type = skge_read8(hw, B2_E_1) & 0xf; hw->pmd_type = skge_read8(hw, B2_PMD_TYP); - switch (hw->chip_id) { + switch(hw->chip_id) { case CHIP_ID_GENESIS: switch (hw->phy_type) { + case SK_PHY_XMAC: + hw->phy_addr = PHY_ADDR_XMAC; + break; case SK_PHY_BCOM: hw->phy_addr = PHY_ADDR_BCOM; break; @@ -2942,9 +2986,8 @@ static int skge_reset(struct skge_hw *hw) return -EOPNOTSUPP; } - mac_cfg = skge_read8(hw, B2_MAC_CFG); - hw->ports = (mac_cfg & CFG_SNG_MAC) ? 1 : 2; - hw->chip_rev = (mac_cfg & CFG_CHIP_R_MSK) >> 4; + hw->mac_cfg = skge_read8(hw, B2_MAC_CFG); + ports = isdualport(hw) ? 2 : 1; /* read the adapters RAM size */ t8 = skge_read8(hw, B2_E_0); @@ -2967,9 +3010,9 @@ static int skge_reset(struct skge_hw *hw) /* switch power to VCC (WA for VAUX problem) */ skge_write8(hw, B0_POWER_CTRL, PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON); - for (i = 0; i < hw->ports; i++) { - skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET); - skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR); + for (i = 0; i < ports; i++) { + skge_write16(hw, SKGEMAC_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET); + skge_write16(hw, SKGEMAC_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR); } } @@ -2979,8 +3022,8 @@ static int skge_reset(struct skge_hw *hw) skge_write8(hw, B0_LED, LED_STAT_ON); /* enable the Tx Arbiters */ - for (i = 0; i < hw->ports; i++) - skge_write8(hw, SK_REG(i, TXA_CTRL), TXA_ENA_ARB); + for (i = 0; i < ports; i++) + skge_write8(hw, SKGEMAC_REG(i, TXA_CTRL), TXA_ENA_ARB); /* Initialize ram interface */ skge_write16(hw, B3_RI_CTRL, RI_RST_CLR); @@ -3007,14 +3050,16 @@ static int skge_reset(struct skge_hw *hw) skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100)); skge_write32(hw, B2_IRQM_CTRL, TIM_START); - hw->intr_mask = IS_HW_ERR | IS_EXT_REG; + hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1; + if (isdualport(hw)) + hw->intr_mask |= IS_PORT_2; skge_write32(hw, B0_IMSK, hw->intr_mask); if (hw->chip_id != CHIP_ID_GENESIS) skge_write8(hw, GMAC_IRQ_MSK, 0); spin_lock_bh(&hw->phy_lock); - for (i = 0; i < hw->ports; i++) { + for (i = 0; i < ports; i++) { if (hw->chip_id == CHIP_ID_GENESIS) genesis_reset(hw, i); else @@ -3026,8 +3071,7 @@ static int skge_reset(struct skge_hw *hw) } /* Initialize network device */ -static struct net_device *skge_devinit(struct skge_hw *hw, int port, - int highmem) +static struct net_device *skge_devinit(struct skge_hw *hw, int port) { struct skge_port *skge; struct net_device *dev = alloc_etherdev(sizeof(*skge)); @@ -3060,8 +3104,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, #endif dev->irq = hw->pdev->irq; dev->features = NETIF_F_LLTX; - if (highmem) - dev->features |= NETIF_F_HIGHDMA; skge = netdev_priv(dev); skge->netdev = dev; @@ -3075,7 +3117,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, skge->flow_control = FLOW_MODE_SYMMETRIC; skge->duplex = -1; skge->speed = -1; - skge->advertising = skge_supported_modes(hw); + skge->advertising = skge_modes(hw); hw->dev[port] = dev; @@ -3083,6 +3125,10 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, spin_lock_init(&skge->tx_lock); + init_timer(&skge->link_check); + skge->link_check.function = skge_link_timer; + skge->link_check.data = (unsigned long) skge; + init_timer(&skge->led_blink); skge->led_blink.function = skge_blink_timer; skge->led_blink.data = (unsigned long) skge; @@ -3186,11 +3232,14 @@ static int __devinit skge_probe(struct pci_dev *pdev, printk(KERN_INFO PFX "addr 0x%lx irq %d chip %s rev %d\n", pci_resource_start(pdev, 0), pdev->irq, - skge_board_name(hw), hw->chip_rev); + skge_board_name(hw), chip_rev(hw)); - if ((dev = skge_devinit(hw, 0, using_dac)) == NULL) + if ((dev = skge_devinit(hw, 0)) == NULL) goto err_out_led_off; + if (using_dac) + dev->features |= NETIF_F_HIGHDMA; + if ((err = register_netdev(dev))) { printk(KERN_ERR PFX "%s: cannot register net device\n", pci_name(pdev)); @@ -3199,7 +3248,10 @@ static int __devinit skge_probe(struct pci_dev *pdev, skge_show_addr(dev); - if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) { + if (isdualport(hw) && (dev1 = skge_devinit(hw, 1))) { + if (using_dac) + dev1->features |= NETIF_F_HIGHDMA; + if (register_netdev(dev1) == 0) skge_show_addr(dev1); else { @@ -3236,7 +3288,7 @@ static void __devexit skge_remove(struct pci_dev *pdev) struct skge_hw *hw = pci_get_drvdata(pdev); struct net_device *dev0, *dev1; - if (!hw) + if(!hw) return; if ((dev1 = hw->dev[1])) @@ -3264,7 +3316,7 @@ static int skge_suspend(struct pci_dev *pdev, u32 state) struct skge_hw *hw = pci_get_drvdata(pdev); int i, wol = 0; - for (i = 0; i < 2; i++) { + for(i = 0; i < 2; i++) { struct net_device *dev = hw->dev[i]; if (dev) { @@ -3297,11 +3349,11 @@ static int skge_resume(struct pci_dev *pdev) skge_reset(hw); - for (i = 0; i < 2; i++) { + for(i = 0; i < 2; i++) { struct net_device *dev = hw->dev[i]; if (dev) { netif_device_attach(dev); - if (netif_running(dev)) + if(netif_running(dev)) skge_up(dev); } } diff --git a/trunk/drivers/net/skge.h b/trunk/drivers/net/skge.h index 14d0cc01fb9a..36c62b68fab4 100644 --- a/trunk/drivers/net/skge.h +++ b/trunk/drivers/net/skge.h @@ -7,6 +7,31 @@ /* PCI config registers */ #define PCI_DEV_REG1 0x40 #define PCI_DEV_REG2 0x44 +#ifndef PCI_VPD +#define PCI_VPD 0x50 +#endif + +/* PCI_OUR_REG_2 32 bit Our Register 2 */ +enum { + PCI_VPD_WR_THR = 0xff<<24, /* Bit 31..24: VPD Write Threshold */ + PCI_DEV_SEL = 0x7f<<17, /* Bit 23..17: EEPROM Device Select */ + PCI_VPD_ROM_SZ = 7 <<14, /* Bit 16..14: VPD ROM Size */ + /* Bit 13..12: reserved */ + PCI_EN_DUMMY_RD = 1<<3, /* Enable Dummy Read */ + PCI_REV_DESC = 1<<2, /* Reverse Desc. Bytes */ + PCI_USEDATA64 = 1<<0, /* Use 64Bit Data bus ext */ +}; + +/* PCI_VPD_ADR_REG 16 bit VPD Address Register */ +enum { + PCI_VPD_FLAG = 1<<15, /* starts VPD rd/wr cycle */ + PCI_VPD_ADR_MSK =0x7fffL, /* Bit 14.. 0: VPD Address Mask */ + VPD_RES_ID = 0x82, + VPD_RES_READ = 0x90, + VPD_RES_WRITE = 0x81, + VPD_RES_END = 0x78, +}; + #define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \ PCI_STATUS_SIG_SYSTEM_ERROR | \ @@ -14,6 +39,7 @@ PCI_STATUS_REC_TARGET_ABORT | \ PCI_STATUS_PARITY) + enum csr_regs { B0_RAP = 0x0000, B0_CTST = 0x0004, @@ -203,11 +229,8 @@ enum { IS_XA2_F = 1<<1, /* Q_XA2 End of Frame */ IS_XA2_C = 1<<0, /* Q_XA2 Encoding Error */ - IS_TO_PORT1 = IS_PA_TO_RX1 | IS_PA_TO_TX1, - IS_TO_PORT2 = IS_PA_TO_RX2 | IS_PA_TO_TX2, - - IS_PORT_1 = IS_XA1_F| IS_R1_F | IS_TO_PORT1 | IS_MAC1, - IS_PORT_2 = IS_XA2_F| IS_R2_F | IS_TO_PORT2 | IS_MAC2, + IS_PORT_1 = IS_XA1_F| IS_R1_F| IS_MAC1, + IS_PORT_2 = IS_XA2_F| IS_R2_F| IS_MAC2, }; @@ -265,6 +288,14 @@ enum { CHIP_REV_YU_LITE_A3 = 7, /* Chip Rev. for YUKON-Lite A3 */ }; +/* B2_LD_TEST 8 bit EPROM loader test register */ +enum { + LD_T_ON = 1<<3, /* Loader Test mode on */ + LD_T_OFF = 1<<2, /* Loader Test mode off */ + LD_T_STEP = 1<<1, /* Decrement FPROM addr. Counter */ + LD_START = 1<<0, /* Start loading FPROM */ +}; + /* B2_TI_CTRL 8 bit Timer control */ /* B2_IRQM_CTRL 8 bit IRQ Moderation Timer Control */ enum { @@ -282,6 +313,16 @@ enum { TIM_T_STEP = 1<<0, /* Test step */ }; +/* B28_DPT_INI 32 bit Descriptor Poll Timer Init Val */ +/* B28_DPT_VAL 32 bit Descriptor Poll Timer Curr Val */ +/* B28_DPT_CTRL 8 bit Descriptor Poll Timer Ctrl Reg */ +enum { + DPT_MSK = 0x00ffffffL, /* Bit 23.. 0: Desc Poll Timer Bits */ + + DPT_START = 1<<1, /* Start Descriptor Poll Timer */ + DPT_STOP = 1<<0, /* Stop Descriptor Poll Timer */ +}; + /* B2_GP_IO 32 bit General Purpose I/O Register */ enum { GP_DIR_9 = 1<<25, /* IO_9 direct, 0=In/1=Out */ @@ -307,6 +348,30 @@ enum { GP_IO_0 = 1<<0, /* IO_0 pin */ }; +/* Rx/Tx Path related Arbiter Test Registers */ +/* B3_MA_TO_TEST 16 bit MAC Arbiter Timeout Test Reg */ +/* B3_MA_RC_TEST 16 bit MAC Arbiter Recovery Test Reg */ +/* B3_PA_TEST 16 bit Packet Arbiter Test Register */ +/* Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */ +enum { + TX2_T_EV = 1<<15,/* TX2 Timeout/Recv Event occured */ + TX2_T_ON = 1<<14,/* TX2 Timeout/Recv Timer Test On */ + TX2_T_OFF = 1<<13,/* TX2 Timeout/Recv Timer Tst Off */ + TX2_T_STEP = 1<<12,/* TX2 Timeout/Recv Timer Step */ + TX1_T_EV = 1<<11,/* TX1 Timeout/Recv Event occured */ + TX1_T_ON = 1<<10,/* TX1 Timeout/Recv Timer Test On */ + TX1_T_OFF = 1<<9, /* TX1 Timeout/Recv Timer Tst Off */ + TX1_T_STEP = 1<<8, /* TX1 Timeout/Recv Timer Step */ + RX2_T_EV = 1<<7, /* RX2 Timeout/Recv Event occured */ + RX2_T_ON = 1<<6, /* RX2 Timeout/Recv Timer Test On */ + RX2_T_OFF = 1<<5, /* RX2 Timeout/Recv Timer Tst Off */ + RX2_T_STEP = 1<<4, /* RX2 Timeout/Recv Timer Step */ + RX1_T_EV = 1<<3, /* RX1 Timeout/Recv Event occured */ + RX1_T_ON = 1<<2, /* RX1 Timeout/Recv Timer Test On */ + RX1_T_OFF = 1<<1, /* RX1 Timeout/Recv Timer Tst Off */ + RX1_T_STEP = 1<<0, /* RX1 Timeout/Recv Timer Step */ +}; + /* Descriptor Bit Definition */ /* TxCtrl Transmit Buffer Control Field */ /* RxCtrl Receive Buffer Control Field */ @@ -363,6 +428,14 @@ enum { RI_RST_SET = 1<<0, /* Set RAM Interface Reset */ }; +/* B3_RI_TEST 8 bit RAM Iface Test Register */ +enum { + RI_T_EV = 1<<3, /* Timeout Event occured */ + RI_T_ON = 1<<2, /* Timeout Timer Test On */ + RI_T_OFF = 1<<1, /* Timeout Timer Test Off */ + RI_T_STEP = 1<<0, /* Timeout Timer Step */ +}; + /* MAC Arbiter Registers */ /* B3_MA_TO_CTRL 16 bit MAC Arbiter Timeout Ctrl Reg */ enum { @@ -379,6 +452,19 @@ enum { #define SK_PKT_TO_MAX 0xffff /* Maximum value */ #define SK_RI_TO_53 36 /* RAM interface timeout */ + +/* B3_MA_RC_CTRL 16 bit MAC Arbiter Recovery Ctrl Reg */ +enum { + MA_ENA_REC_TX2 = 1<<7, /* Enable Recovery Timer TX2 */ + MA_DIS_REC_TX2 = 1<<6, /* Disable Recovery Timer TX2 */ + MA_ENA_REC_TX1 = 1<<5, /* Enable Recovery Timer TX1 */ + MA_DIS_REC_TX1 = 1<<4, /* Disable Recovery Timer TX1 */ + MA_ENA_REC_RX2 = 1<<3, /* Enable Recovery Timer RX2 */ + MA_DIS_REC_RX2 = 1<<2, /* Disable Recovery Timer RX2 */ + MA_ENA_REC_RX1 = 1<<1, /* Enable Recovery Timer RX1 */ + MA_DIS_REC_RX1 = 1<<0, /* Disable Recovery Timer RX1 */ +}; + /* Packet Arbiter Registers */ /* B3_PA_CTRL 16 bit Packet Arbiter Ctrl Register */ enum { @@ -402,7 +488,7 @@ enum { PA_ENA_TO_TX1 | PA_ENA_TO_TX2) -/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */ +/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */ /* TXA_ITI_INI 32 bit Tx Arb Interval Timer Init Val */ /* TXA_ITI_VAL 32 bit Tx Arb Interval Timer Value */ /* TXA_LIM_INI 32 bit Tx Arb Limit Counter Init Val */ @@ -425,7 +511,7 @@ enum { /* * Bank 4 - 5 */ -/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */ +/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */ enum { TXA_ITI_INI = 0x0200,/* 32 bit Tx Arb Interval Timer Init Val*/ TXA_ITI_VAL = 0x0204,/* 32 bit Tx Arb Interval Timer Value */ @@ -451,7 +537,7 @@ enum { /* Queue Register Offsets, use Q_ADDR() to access */ enum { - B8_Q_REGS = 0x0400, /* base of Queue registers */ + B8_Q_REGS = 0x0400, /* base of Queue registers */ Q_D = 0x00, /* 8*32 bit Current Descriptor */ Q_DA_L = 0x20, /* 32 bit Current Descriptor Address Low dWord */ Q_DA_H = 0x24, /* 32 bit Current Descriptor Address High dWord */ @@ -532,7 +618,8 @@ enum { enum { PHY_ADDR_XMAC = 0<<8, PHY_ADDR_BCOM = 1<<8, - + PHY_ADDR_LONE = 3<<8, + PHY_ADDR_NAT = 0<<8, /* GPHY address (bits 15..11 of SMI control reg) */ PHY_ADDR_MARV = 0, }; @@ -899,7 +986,7 @@ enum { LINKLED_BLINK_OFF = 0x10, LINKLED_BLINK_ON = 0x20, }; - + /* GMAC and GPHY Control Registers (YUKON only) */ enum { GMAC_CTRL = 0x0f00,/* 32 bit GMAC Control Reg */ @@ -1064,6 +1151,54 @@ enum { PHY_MARV_FE_SPEC_2 = 0x1c,/* 16 bit r/w Specific Control Reg. 2 */ }; +/* Level One-PHY Registers, indirect addressed over XMAC */ +enum { + PHY_LONE_CTRL = 0x00,/* 16 bit r/w PHY Control Register */ + PHY_LONE_STAT = 0x01,/* 16 bit r/o PHY Status Register */ + PHY_LONE_ID0 = 0x02,/* 16 bit r/o PHY ID0 Register */ + PHY_LONE_ID1 = 0x03,/* 16 bit r/o PHY ID1 Register */ + PHY_LONE_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */ + PHY_LONE_AUNE_LP = 0x05,/* 16 bit r/o Link Part Ability Reg */ + PHY_LONE_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */ + PHY_LONE_NEPG = 0x07,/* 16 bit r/w Next Page Register */ + PHY_LONE_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner */ + /* Level One-specific registers */ + PHY_LONE_1000T_CTRL = 0x09,/* 16 bit r/w 1000Base-T Control Reg */ + PHY_LONE_1000T_STAT = 0x0a,/* 16 bit r/o 1000Base-T Status Reg */ + PHY_LONE_EXT_STAT = 0x0f,/* 16 bit r/o Extended Status Reg */ + PHY_LONE_PORT_CFG = 0x10,/* 16 bit r/w Port Configuration Reg*/ + PHY_LONE_Q_STAT = 0x11,/* 16 bit r/o Quick Status Reg */ + PHY_LONE_INT_ENAB = 0x12,/* 16 bit r/w Interrupt Enable Reg */ + PHY_LONE_INT_STAT = 0x13,/* 16 bit r/o Interrupt Status Reg */ + PHY_LONE_LED_CFG = 0x14,/* 16 bit r/w LED Configuration Reg */ + PHY_LONE_PORT_CTRL = 0x15,/* 16 bit r/w Port Control Reg */ + PHY_LONE_CIM = 0x16,/* 16 bit r/o CIM Reg */ +}; + +/* National-PHY Registers, indirect addressed over XMAC */ +enum { + PHY_NAT_CTRL = 0x00,/* 16 bit r/w PHY Control Register */ + PHY_NAT_STAT = 0x01,/* 16 bit r/w PHY Status Register */ + PHY_NAT_ID0 = 0x02,/* 16 bit r/o PHY ID0 Register */ + PHY_NAT_ID1 = 0x03,/* 16 bit r/o PHY ID1 Register */ + PHY_NAT_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */ + PHY_NAT_AUNE_LP = 0x05,/* 16 bit r/o Link Partner Ability Reg */ + PHY_NAT_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */ + PHY_NAT_NEPG = 0x07,/* 16 bit r/w Next Page Register */ + PHY_NAT_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner Reg */ + /* National-specific registers */ + PHY_NAT_1000T_CTRL = 0x09,/* 16 bit r/w 1000Base-T Control Reg */ + PHY_NAT_1000T_STAT = 0x0a,/* 16 bit r/o 1000Base-T Status Reg */ + PHY_NAT_EXT_STAT = 0x0f,/* 16 bit r/o Extended Status Register */ + PHY_NAT_EXT_CTRL1 = 0x10,/* 16 bit r/o Extended Control Reg1 */ + PHY_NAT_Q_STAT1 = 0x11,/* 16 bit r/o Quick Status Reg1 */ + PHY_NAT_10B_OP = 0x12,/* 16 bit r/o 10Base-T Operations Reg */ + PHY_NAT_EXT_CTRL2 = 0x13,/* 16 bit r/o Extended Control Reg1 */ + PHY_NAT_Q_STAT2 = 0x14,/* 16 bit r/o Quick Status Reg2 */ + + PHY_NAT_PHY_ADDR = 0x19,/* 16 bit r/o PHY Address Register */ +}; + enum { PHY_CT_RESET = 1<<15, /* Bit 15: (sc) clear all PHY related regs */ PHY_CT_LOOP = 1<<14, /* Bit 14: enable Loopback over PHY */ @@ -1118,29 +1253,8 @@ enum { PHY_MARV_ID1_Y2 = 0x0C91, /* Yukon-2 (PHY 88E1112) */ }; -/* Advertisement register bits */ enum { PHY_AN_NXT_PG = 1<<15, /* Bit 15: Request Next Page */ - PHY_AN_ACK = 1<<14, /* Bit 14: (ro) Acknowledge Received */ - PHY_AN_RF = 1<<13, /* Bit 13: Remote Fault Bits */ - - PHY_AN_PAUSE_ASYM = 1<<11,/* Bit 11: Try for asymmetric */ - PHY_AN_PAUSE_CAP = 1<<10, /* Bit 10: Try for pause */ - PHY_AN_100BASE4 = 1<<9, /* Bit 9: Try for 100mbps 4k packets */ - PHY_AN_100FULL = 1<<8, /* Bit 8: Try for 100mbps full-duplex */ - PHY_AN_100HALF = 1<<7, /* Bit 7: Try for 100mbps half-duplex */ - PHY_AN_10FULL = 1<<6, /* Bit 6: Try for 10mbps full-duplex */ - PHY_AN_10HALF = 1<<5, /* Bit 5: Try for 10mbps half-duplex */ - PHY_AN_CSMA = 1<<0, /* Bit 0: Only selector supported */ - PHY_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/ - PHY_AN_FULL = PHY_AN_100FULL | PHY_AN_10FULL | PHY_AN_CSMA, - PHY_AN_ALL = PHY_AN_10HALF | PHY_AN_10FULL | - PHY_AN_100HALF | PHY_AN_100FULL, -}; - -/* Xmac Specific */ -enum { - PHY_X_AN_NXT_PG = 1<<15, /* Bit 15: Request Next Page */ PHY_X_AN_ACK = 1<<14, /* Bit 14: (ro) Acknowledge Received */ PHY_X_AN_RFB = 3<<12,/* Bit 13..12: Remote Fault Bits */ @@ -1149,6 +1263,82 @@ enum { PHY_X_AN_FD = 1<<5, /* Bit 5: Full Duplex */ }; +enum { + PHY_B_AN_RF = 1<<13, /* Bit 13: Remote Fault */ + + PHY_B_AN_ASP = 1<<11, /* Bit 11: Asymmetric Pause */ + PHY_B_AN_PC = 1<<10, /* Bit 10: Pause Capable */ + PHY_B_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/ +}; + +enum { + PHY_L_AN_RF = 1<<13, /* Bit 13: Remote Fault */ + /* Bit 12: reserved */ + PHY_L_AN_ASP = 1<<11, /* Bit 11: Asymmetric Pause */ + PHY_L_AN_PC = 1<<10, /* Bit 10: Pause Capable */ + + PHY_L_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/ +}; + +/* PHY_NAT_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement */ +/* PHY_NAT_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/ +/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */ +enum { + PHY_N_AN_RF = 1<<13, /* Bit 13: Remote Fault */ + + PHY_N_AN_100F = 1<<11, /* Bit 11: 100Base-T2 FD Support */ + PHY_N_AN_100H = 1<<10, /* Bit 10: 100Base-T2 HD Support */ + + PHY_N_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/ +}; + +/* field type definition for PHY_x_AN_SEL */ +enum { + PHY_SEL_TYPE = 1, /* 00001 = Ethernet */ +}; + +enum { + PHY_ANE_LP_NP = 1<<3, /* Bit 3: Link Partner can Next Page */ + PHY_ANE_LOC_NP = 1<<2, /* Bit 2: Local PHY can Next Page */ + PHY_ANE_RX_PG = 1<<1, /* Bit 1: Page Received */ +}; + +enum { + PHY_ANE_PAR_DF = 1<<4, /* Bit 4: Parallel Detection Fault */ + + PHY_ANE_LP_CAP = 1<<0, /* Bit 0: Link Partner Auto-Neg. Cap. */ +}; + +enum { + PHY_NP_MORE = 1<<15, /* Bit 15: More, Next Pages to follow */ + PHY_NP_ACK1 = 1<<14, /* Bit 14: (ro) Ack1, for receiving a message */ + PHY_NP_MSG_VAL = 1<<13, /* Bit 13: Message Page valid */ + PHY_NP_ACK2 = 1<<12, /* Bit 12: Ack2, comply with msg content */ + PHY_NP_TOG = 1<<11, /* Bit 11: Toggle Bit, ensure sync */ + PHY_NP_MSG = 0x07ff, /* Bit 10..0: Message from/to Link Partner */ +}; + +enum { + PHY_X_EX_FD = 1<<15, /* Bit 15: Device Supports Full Duplex */ + PHY_X_EX_HD = 1<<14, /* Bit 14: Device Supports Half Duplex */ +}; + +enum { + PHY_X_RS_PAUSE = 3<<7,/* Bit 8..7: selected Pause Mode */ + PHY_X_RS_HD = 1<<6, /* Bit 6: Half Duplex Mode selected */ + PHY_X_RS_FD = 1<<5, /* Bit 5: Full Duplex Mode selected */ + PHY_X_RS_ABLMIS = 1<<4, /* Bit 4: duplex or pause cap mismatch */ + PHY_X_RS_PAUMIS = 1<<3, /* Bit 3: pause capability mismatch */ +}; + +/** Remote Fault Bits (PHY_X_AN_RFB) encoding */ +enum { + X_RFB_OK = 0<<12,/* Bit 13..12 No errors, Link OK */ + X_RFB_LF = 1<<12, /* Bit 13..12 Link Failure */ + X_RFB_OFF = 2<<12,/* Bit 13..12 Offline */ + X_RFB_AN_ERR = 3<<12,/* Bit 13..12 Auto-Negotiation Error */ +}; + /* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */ enum { PHY_X_P_NO_PAUSE = 0<<7,/* Bit 8..7: no Pause Mode */ @@ -1228,16 +1418,6 @@ enum { PHY_B_PES_MLT3_ER = 1<<0, /* Bit 0: MLT3 code Error */ }; -/* PHY_BCOM_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/ -/* PHY_BCOM_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/ -enum { - PHY_B_AN_RF = 1<<13, /* Bit 13: Remote Fault */ - - PHY_B_AN_ASP = 1<<11, /* Bit 11: Asymmetric Pause */ - PHY_B_AN_PC = 1<<10, /* Bit 10: Pause Capable */ -}; - - /***** PHY_BCOM_FC_CTR 16 bit r/w False Carrier Counter *****/ enum { PHY_B_FC_CTR = 0xff, /* Bit 7..0: False Carrier Counter */ @@ -1298,9 +1478,7 @@ enum { PHY_B_IS_LST_CHANGE = 1<<1, /* Bit 1: Link Status Changed */ PHY_B_IS_CRC_ER = 1<<0, /* Bit 0: CRC Error */ }; -#define PHY_B_DEF_MSK \ - (~(PHY_B_IS_PSE | PHY_B_IS_AN_PR | PHY_B_IS_DUP_CHANGE | \ - PHY_B_IS_LSP_CHANGE | PHY_B_IS_LST_CHANGE)) +#define PHY_B_DEF_MSK (~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) /* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */ enum { @@ -1317,6 +1495,166 @@ enum { PHY_B_RES_1000HD = 6<<8,/* Bit 10..8: 1000Base-T Half Dup. */ }; +/* + * Level One-Specific + */ +/***** PHY_LONE_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/ +enum { + PHY_L_1000C_TEST = 7<<13,/* Bit 15..13: Test Modes */ + PHY_L_1000C_MSE = 1<<12, /* Bit 12: Master/Slave Enable */ + PHY_L_1000C_MSC = 1<<11, /* Bit 11: M/S Configuration */ + PHY_L_1000C_RD = 1<<10, /* Bit 10: Repeater/DTE */ + PHY_L_1000C_AFD = 1<<9, /* Bit 9: Advertise Full Duplex */ + PHY_L_1000C_AHD = 1<<8, /* Bit 8: Advertise Half Duplex */ +}; + +/***** PHY_LONE_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/ +enum { + PHY_L_1000S_MSF = 1<<15, /* Bit 15: Master/Slave Fault */ + PHY_L_1000S_MSR = 1<<14, /* Bit 14: Master/Slave Result */ + PHY_L_1000S_LRS = 1<<13, /* Bit 13: Local Receiver Status */ + PHY_L_1000S_RRS = 1<<12, /* Bit 12: Remote Receiver Status */ + PHY_L_1000S_LP_FD = 1<<11, /* Bit 11: Link Partner can FD */ + PHY_L_1000S_LP_HD = 1<<10, /* Bit 10: Link Partner can HD */ + + PHY_L_1000S_IEC = 0xff, /* Bit 7..0: Idle Error Count */ + +/***** PHY_LONE_EXT_STAT 16 bit r/o Extended Status Register *****/ + PHY_L_ES_X_FD_CAP = 1<<15, /* Bit 15: 1000Base-X FD capable */ + PHY_L_ES_X_HD_CAP = 1<<14, /* Bit 14: 1000Base-X HD capable */ + PHY_L_ES_T_FD_CAP = 1<<13, /* Bit 13: 1000Base-T FD capable */ + PHY_L_ES_T_HD_CAP = 1<<12, /* Bit 12: 1000Base-T HD capable */ +}; + +/***** PHY_LONE_PORT_CFG 16 bit r/w Port Configuration Reg *****/ +enum { + PHY_L_PC_REP_MODE = 1<<15, /* Bit 15: Repeater Mode */ + + PHY_L_PC_TX_DIS = 1<<13, /* Bit 13: Tx output Disabled */ + PHY_L_PC_BY_SCR = 1<<12, /* Bit 12: Bypass Scrambler */ + PHY_L_PC_BY_45 = 1<<11, /* Bit 11: Bypass 4B5B-Decoder */ + PHY_L_PC_JAB_DIS = 1<<10, /* Bit 10: Jabber Disabled */ + PHY_L_PC_SQE = 1<<9, /* Bit 9: Enable Heartbeat */ + PHY_L_PC_TP_LOOP = 1<<8, /* Bit 8: TP Loopback */ + PHY_L_PC_SSS = 1<<7, /* Bit 7: Smart Speed Selection */ + PHY_L_PC_FIFO_SIZE = 1<<6, /* Bit 6: FIFO Size */ + PHY_L_PC_PRE_EN = 1<<5, /* Bit 5: Preamble Enable */ + PHY_L_PC_CIM = 1<<4, /* Bit 4: Carrier Integrity Mon */ + PHY_L_PC_10_SER = 1<<3, /* Bit 3: Use Serial Output */ + PHY_L_PC_ANISOL = 1<<2, /* Bit 2: Unisolate Port */ + PHY_L_PC_TEN_BIT = 1<<1, /* Bit 1: 10bit iface mode on */ + PHY_L_PC_ALTCLOCK = 1<<0, /* Bit 0: (ro) ALTCLOCK Mode on */ +}; + +/***** PHY_LONE_Q_STAT 16 bit r/o Quick Status Reg *****/ +enum { + PHY_L_QS_D_RATE = 3<<14,/* Bit 15..14: Data Rate */ + PHY_L_QS_TX_STAT = 1<<13, /* Bit 13: Transmitting */ + PHY_L_QS_RX_STAT = 1<<12, /* Bit 12: Receiving */ + PHY_L_QS_COL_STAT = 1<<11, /* Bit 11: Collision */ + PHY_L_QS_L_STAT = 1<<10, /* Bit 10: Link is up */ + PHY_L_QS_DUP_MOD = 1<<9, /* Bit 9: Full/Half Duplex */ + PHY_L_QS_AN = 1<<8, /* Bit 8: AutoNeg is On */ + PHY_L_QS_AN_C = 1<<7, /* Bit 7: AN is Complete */ + PHY_L_QS_LLE = 7<<4,/* Bit 6..4: Line Length Estim. */ + PHY_L_QS_PAUSE = 1<<3, /* Bit 3: LP advertised Pause */ + PHY_L_QS_AS_PAUSE = 1<<2, /* Bit 2: LP adv. asym. Pause */ + PHY_L_QS_ISOLATE = 1<<1, /* Bit 1: CIM Isolated */ + PHY_L_QS_EVENT = 1<<0, /* Bit 0: Event has occurred */ +}; + +/***** PHY_LONE_INT_ENAB 16 bit r/w Interrupt Enable Reg *****/ +/***** PHY_LONE_INT_STAT 16 bit r/o Interrupt Status Reg *****/ +enum { + PHY_L_IS_AN_F = 1<<13, /* Bit 13: Auto-Negotiation fault */ + PHY_L_IS_CROSS = 1<<11, /* Bit 11: Crossover used */ + PHY_L_IS_POL = 1<<10, /* Bit 10: Polarity correct. used */ + PHY_L_IS_SS = 1<<9, /* Bit 9: Smart Speed Downgrade */ + PHY_L_IS_CFULL = 1<<8, /* Bit 8: Counter Full */ + PHY_L_IS_AN_C = 1<<7, /* Bit 7: AutoNeg Complete */ + PHY_L_IS_SPEED = 1<<6, /* Bit 6: Speed Changed */ + PHY_L_IS_DUP = 1<<5, /* Bit 5: Duplex Changed */ + PHY_L_IS_LS = 1<<4, /* Bit 4: Link Status Changed */ + PHY_L_IS_ISOL = 1<<3, /* Bit 3: Isolate Occured */ + PHY_L_IS_MDINT = 1<<2, /* Bit 2: (ro) STAT: MII Int Pending */ + PHY_L_IS_INTEN = 1<<1, /* Bit 1: ENAB: Enable IRQs */ + PHY_L_IS_FORCE = 1<<0, /* Bit 0: ENAB: Force Interrupt */ +}; + +/* int. mask */ +#define PHY_L_DEF_MSK (PHY_L_IS_LS | PHY_L_IS_ISOL | PHY_L_IS_INTEN) + +/***** PHY_LONE_LED_CFG 16 bit r/w LED Configuration Reg *****/ +enum { + PHY_L_LC_LEDC = 3<<14,/* Bit 15..14: Col/Blink/On/Off */ + PHY_L_LC_LEDR = 3<<12,/* Bit 13..12: Rx/Blink/On/Off */ + PHY_L_LC_LEDT = 3<<10,/* Bit 11..10: Tx/Blink/On/Off */ + PHY_L_LC_LEDG = 3<<8,/* Bit 9..8: Giga/Blink/On/Off */ + PHY_L_LC_LEDS = 3<<6,/* Bit 7..6: 10-100/Blink/On/Off */ + PHY_L_LC_LEDL = 3<<4,/* Bit 5..4: Link/Blink/On/Off */ + PHY_L_LC_LEDF = 3<<2,/* Bit 3..2: Duplex/Blink/On/Off */ + PHY_L_LC_PSTRECH= 1<<1, /* Bit 1: Strech LED Pulses */ + PHY_L_LC_FREQ = 1<<0, /* Bit 0: 30/100 ms */ +}; + +/***** PHY_LONE_PORT_CTRL 16 bit r/w Port Control Reg *****/ +enum { + PHY_L_PC_TX_TCLK = 1<<15, /* Bit 15: Enable TX_TCLK */ + PHY_L_PC_ALT_NP = 1<<13, /* Bit 14: Alternate Next Page */ + PHY_L_PC_GMII_ALT= 1<<12, /* Bit 13: Alternate GMII driver */ + PHY_L_PC_TEN_CRS = 1<<10, /* Bit 10: Extend CRS*/ +}; + +/***** PHY_LONE_CIM 16 bit r/o CIM Reg *****/ +enum { + PHY_L_CIM_ISOL = 0xff<<8,/* Bit 15..8: Isolate Count */ + PHY_L_CIM_FALSE_CAR = 0xff, /* Bit 7..0: False Carrier Count */ +}; + +/* + * Pause Bits (PHY_L_AN_ASP and PHY_L_AN_PC) encoding + */ +enum { + PHY_L_P_NO_PAUSE= 0<<10,/* Bit 11..10: no Pause Mode */ + PHY_L_P_SYM_MD = 1<<10, /* Bit 11..10: symmetric Pause Mode */ + PHY_L_P_ASYM_MD = 2<<10,/* Bit 11..10: asymmetric Pause Mode */ + PHY_L_P_BOTH_MD = 3<<10,/* Bit 11..10: both Pause Mode */ +}; + +/* + * National-Specific + */ +/***** PHY_NAT_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/ +enum { + PHY_N_1000C_TEST= 7<<13,/* Bit 15..13: Test Modes */ + PHY_N_1000C_MSE = 1<<12, /* Bit 12: Master/Slave Enable */ + PHY_N_1000C_MSC = 1<<11, /* Bit 11: M/S Configuration */ + PHY_N_1000C_RD = 1<<10, /* Bit 10: Repeater/DTE */ + PHY_N_1000C_AFD = 1<<9, /* Bit 9: Advertise Full Duplex */ + PHY_N_1000C_AHD = 1<<8, /* Bit 8: Advertise Half Duplex */ + PHY_N_1000C_APC = 1<<7, /* Bit 7: Asymmetric Pause Cap. */}; + + +/***** PHY_NAT_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/ +enum { + PHY_N_1000S_MSF = 1<<15, /* Bit 15: Master/Slave Fault */ + PHY_N_1000S_MSR = 1<<14, /* Bit 14: Master/Slave Result */ + PHY_N_1000S_LRS = 1<<13, /* Bit 13: Local Receiver Status */ + PHY_N_1000S_RRS = 1<<12, /* Bit 12: Remote Receiver Status*/ + PHY_N_1000S_LP_FD= 1<<11, /* Bit 11: Link Partner can FD */ + PHY_N_1000S_LP_HD= 1<<10, /* Bit 10: Link Partner can HD */ + PHY_N_1000C_LP_APC= 1<<9, /* Bit 9: LP Asym. Pause Cap. */ + PHY_N_1000S_IEC = 0xff, /* Bit 7..0: Idle Error Count */ +}; + +/***** PHY_NAT_EXT_STAT 16 bit r/o Extended Status Register *****/ +enum { + PHY_N_ES_X_FD_CAP= 1<<15, /* Bit 15: 1000Base-X FD capable */ + PHY_N_ES_X_HD_CAP= 1<<14, /* Bit 14: 1000Base-X HD capable */ + PHY_N_ES_T_FD_CAP= 1<<13, /* Bit 13: 1000Base-T FD capable */ + PHY_N_ES_T_HD_CAP= 1<<12, /* Bit 12: 1000Base-T HD capable */ +}; + /** Marvell-Specific */ enum { PHY_M_AN_NXT_PG = 1<<15, /* Request Next Page */ @@ -1380,7 +1718,7 @@ enum { PHY_M_PC_EN_DET_PLUS = 3<<8, /* Energy Detect Plus (Mode 2) */ }; -#define PHY_M_PC_MDI_XMODE(x) (((x)<<5) & PHY_M_PC_MDIX_MSK) +#define PHY_M_PC_MDI_XMODE(x) (((x)<<5) & PHY_M_PC_MDIX_MSK) enum { PHY_M_PC_MAN_MDI = 0, /* 00 = Manual MDI configuration */ @@ -1767,7 +2105,7 @@ enum { GM_GPSR_FC_RX_DIS = 1<<2, /* Bit 2: Rx Flow-Control Mode Disabled */ GM_GPSR_PROM_EN = 1<<1, /* Bit 1: Promiscuous Mode Enabled */ }; - + /* GM_GP_CTRL 16 bit r/w General Purpose Control Register */ enum { GM_GPCR_PROM_ENA = 1<<14, /* Bit 14: Enable Promiscuous Mode */ @@ -1789,7 +2127,7 @@ enum { #define GM_GPCR_SPEED_1000 (GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100) #define GM_GPCR_AU_ALL_DIS (GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS|GM_GPCR_AU_SPD_DIS) - + /* GM_TX_CTRL 16 bit r/w Transmit Control Register */ enum { GM_TXCR_FORCE_JAM = 1<<15, /* Bit 15: Force Jam / Flow-Control */ @@ -1800,7 +2138,7 @@ enum { #define TX_COL_THR(x) (((x)<<10) & GM_TXCR_COL_THR_MSK) #define TX_COL_DEF 0x04 - + /* GM_RX_CTRL 16 bit r/w Receive Control Register */ enum { GM_RXCR_UCF_ENA = 1<<15, /* Bit 15: Enable Unicast filtering */ @@ -1808,7 +2146,7 @@ enum { GM_RXCR_CRC_DIS = 1<<13, /* Bit 13: Remove 4-byte CRC */ GM_RXCR_PASS_FC = 1<<12, /* Bit 12: Pass FC packets to FIFO */ }; - + /* GM_TX_PARAM 16 bit r/w Transmit Parameter Register */ enum { GM_TXPA_JAMLEN_MSK = 0x03<<14, /* Bit 15..14: Jam Length */ @@ -1833,7 +2171,7 @@ enum { GM_SMOD_JUMBO_ENA = 1<<8, /* Bit 8: Enable Jumbo (Max. Frame Len) */ GM_SMOD_IPG_MSK = 0x1f /* Bit 4..0: Inter-Packet Gap (IPG) */ }; - + #define DATA_BLIND_VAL(x) (((x)<<11) & GM_SMOD_DATABL_MSK) #define DATA_BLIND_DEF 0x04 @@ -1848,7 +2186,7 @@ enum { GM_SMI_CT_RD_VAL = 1<<4, /* Bit 4: Read Valid (Read completed) */ GM_SMI_CT_BUSY = 1<<3, /* Bit 3: Busy (Operation in progress) */ }; - + #define GM_SMI_CT_PHY_AD(x) (((x)<<11) & GM_SMI_CT_PHY_A_MSK) #define GM_SMI_CT_REG_AD(x) (((x)<<6) & GM_SMI_CT_REG_A_MSK) @@ -1857,7 +2195,7 @@ enum { GM_PAR_MIB_CLR = 1<<5, /* Bit 5: Set MIB Clear Counter Mode */ GM_PAR_MIB_TST = 1<<4, /* Bit 4: MIB Load Counter (Test Mode) */ }; - + /* Receive Frame Status Encoding */ enum { GMR_FS_LEN = 0xffff<<16, /* Bit 31..16: Rx Frame Length */ @@ -1879,12 +2217,12 @@ enum { /* * GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR) */ - GMR_FS_ANY_ERR = GMR_FS_CRC_ERR | GMR_FS_LONG_ERR | - GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC | + GMR_FS_ANY_ERR = GMR_FS_CRC_ERR | GMR_FS_LONG_ERR | + GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_JABBER, /* Rx GMAC FIFO Flush Mask (default) */ RX_FF_FL_DEF_MSK = GMR_FS_CRC_ERR | GMR_FS_RX_FF_OV |GMR_FS_MII_ERR | - GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE | + GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE | GMR_FS_JABBER, }; @@ -2202,6 +2540,10 @@ enum { }; +/* XM_PHY_ADDR 16 bit r/w PHY Address Register */ +#define XM_PHY_ADDR_SZ 0x1f /* Bit 4..0: PHY Address bits */ + + /* XM_GP_PORT 32 bit r/w General Purpose Port Register */ enum { XM_GP_ANIP = 1<<6, /* Bit 6: (ro) Auto-Neg. in progress */ @@ -2320,8 +2662,8 @@ enum { }; #define XM_PAUSE_MODE (XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I) -#define XM_DEF_MODE (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\ - XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA) +#define XM_DEF_MODE (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\ + XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA | XM_MD_CAA) /* XM_STAT_CMD 16 bit r/w Statistics Command Register */ enum { @@ -2451,20 +2793,28 @@ struct skge_hw { u32 intr_mask; struct net_device *dev[2]; + u8 mac_cfg; u8 chip_id; - u8 chip_rev; u8 phy_type; u8 pmd_type; u16 phy_addr; - u8 ports; u32 ram_size; u32 ram_offset; - + struct tasklet_struct ext_tasklet; spinlock_t phy_lock; }; +static inline int isdualport(const struct skge_hw *hw) +{ + return !(hw->mac_cfg & CFG_SNG_MAC); +} + +static inline u8 chip_rev(const struct skge_hw *hw) +{ + return (hw->mac_cfg & CFG_CHIP_R_MSK) >> 4; +} static inline int iscopper(const struct skge_hw *hw) { @@ -2477,7 +2827,7 @@ enum { FLOW_MODE_REM_SEND = 2, /* Symmetric or just remote */ FLOW_MODE_SYMMETRIC = 3, /* Both stations may send PAUSE */ }; - + struct skge_port { u32 msg_enable; struct skge_hw *hw; @@ -2503,8 +2853,8 @@ struct skge_port { void *mem; /* PCI memory for rings */ dma_addr_t dma; unsigned long mem_size; - unsigned int rx_buf_size; + struct timer_list link_check; struct timer_list led_blink; }; @@ -2513,6 +2863,7 @@ struct skge_port { static inline u32 skge_read32(const struct skge_hw *hw, int reg) { return readl(hw->regs + reg); + } static inline u16 skge_read16(const struct skge_hw *hw, int reg) @@ -2541,87 +2892,114 @@ static inline void skge_write8(const struct skge_hw *hw, int reg, u8 val) } /* MAC Related Registers inside the device. */ -#define SK_REG(port,reg) (((port)<<7)+(reg)) -#define SK_XMAC_REG(port, reg) \ +#define SKGEMAC_REG(port,reg) (((port)<<7)+(reg)) + +/* PCI config space can be accessed via memory mapped space */ +#define SKGEPCI_REG(reg) ((reg)+ 0x380) + +#define SKGEXM_REG(port, reg) \ ((BASE_XMAC_1 + (port) * (BASE_XMAC_2 - BASE_XMAC_1)) | (reg) << 1) -static inline u32 xm_read32(const struct skge_hw *hw, int port, int reg) +static inline u32 skge_xm_read32(const struct skge_hw *hw, int port, int reg) +{ + return skge_read32(hw, SKGEXM_REG(port,reg)); +} + +static inline u16 skge_xm_read16(const struct skge_hw *hw, int port, int reg) { - u32 v; - v = skge_read16(hw, SK_XMAC_REG(port, reg)); - v |= (u32)skge_read16(hw, SK_XMAC_REG(port, reg+2)) << 16; - return v; + return skge_read16(hw, SKGEXM_REG(port,reg)); } -static inline u16 xm_read16(const struct skge_hw *hw, int port, int reg) +static inline u8 skge_xm_read8(const struct skge_hw *hw, int port, int reg) { - return skge_read16(hw, SK_XMAC_REG(port,reg)); + return skge_read8(hw, SKGEXM_REG(port,reg)); } -static inline void xm_write32(const struct skge_hw *hw, int port, int r, u32 v) +static inline void skge_xm_write32(const struct skge_hw *hw, int port, int r, u32 v) { - skge_write16(hw, SK_XMAC_REG(port,r), v & 0xffff); - skge_write16(hw, SK_XMAC_REG(port,r+2), v >> 16); + skge_write32(hw, SKGEXM_REG(port,r), v); } -static inline void xm_write16(const struct skge_hw *hw, int port, int r, u16 v) +static inline void skge_xm_write16(const struct skge_hw *hw, int port, int r, u16 v) { - skge_write16(hw, SK_XMAC_REG(port,r), v); + skge_write16(hw, SKGEXM_REG(port,r), v); } -static inline void xm_outhash(const struct skge_hw *hw, int port, int reg, +static inline void skge_xm_write8(const struct skge_hw *hw, int port, int r, u8 v) +{ + skge_write8(hw, SKGEXM_REG(port,r), v); +} + +static inline void skge_xm_outhash(const struct skge_hw *hw, int port, int reg, const u8 *hash) { - xm_write16(hw, port, reg, (u16)hash[0] | ((u16)hash[1] << 8)); - xm_write16(hw, port, reg+2, (u16)hash[2] | ((u16)hash[3] << 8)); - xm_write16(hw, port, reg+4, (u16)hash[4] | ((u16)hash[5] << 8)); - xm_write16(hw, port, reg+6, (u16)hash[6] | ((u16)hash[7] << 8)); + skge_xm_write16(hw, port, reg, + (u16)hash[0] | ((u16)hash[1] << 8)); + skge_xm_write16(hw, port, reg+2, + (u16)hash[2] | ((u16)hash[3] << 8)); + skge_xm_write16(hw, port, reg+4, + (u16)hash[4] | ((u16)hash[5] << 8)); + skge_xm_write16(hw, port, reg+6, + (u16)hash[6] | ((u16)hash[7] << 8)); } -static inline void xm_outaddr(const struct skge_hw *hw, int port, int reg, +static inline void skge_xm_outaddr(const struct skge_hw *hw, int port, int reg, const u8 *addr) { - xm_write16(hw, port, reg, (u16)addr[0] | ((u16)addr[1] << 8)); - xm_write16(hw, port, reg+2, (u16)addr[2] | ((u16)addr[3] << 8)); - xm_write16(hw, port, reg+4, (u16)addr[4] | ((u16)addr[5] << 8)); + skge_xm_write16(hw, port, reg, + (u16)addr[0] | ((u16)addr[1] << 8)); + skge_xm_write16(hw, port, reg, + (u16)addr[2] | ((u16)addr[3] << 8)); + skge_xm_write16(hw, port, reg, + (u16)addr[4] | ((u16)addr[5] << 8)); } -#define SK_GMAC_REG(port,reg) \ - (BASE_GMAC_1 + (port) * (BASE_GMAC_2-BASE_GMAC_1) + (reg)) -static inline u16 gma_read16(const struct skge_hw *hw, int port, int reg) +#define SKGEGMA_REG(port,reg) \ + ((reg) + BASE_GMAC_1 + \ + (port) * (BASE_GMAC_2-BASE_GMAC_1)) + +static inline u16 skge_gma_read16(const struct skge_hw *hw, int port, int reg) { - return skge_read16(hw, SK_GMAC_REG(port,reg)); + return skge_read16(hw, SKGEGMA_REG(port,reg)); } -static inline u32 gma_read32(const struct skge_hw *hw, int port, int reg) +static inline u32 skge_gma_read32(const struct skge_hw *hw, int port, int reg) { - return (u32) skge_read16(hw, SK_GMAC_REG(port,reg)) - | ((u32)skge_read16(hw, SK_GMAC_REG(port,reg+4)) << 16); + return (u32) skge_read16(hw, SKGEGMA_REG(port,reg)) + | ((u32)skge_read16(hw, SKGEGMA_REG(port,reg+4)) << 16); } -static inline void gma_write16(const struct skge_hw *hw, int port, int r, u16 v) +static inline u8 skge_gma_read8(const struct skge_hw *hw, int port, int reg) { - skge_write16(hw, SK_GMAC_REG(port,r), v); + return skge_read8(hw, SKGEGMA_REG(port,reg)); } -static inline void gma_write32(const struct skge_hw *hw, int port, int r, u32 v) +static inline void skge_gma_write16(const struct skge_hw *hw, int port, int r, u16 v) { - skge_write16(hw, SK_GMAC_REG(port, r), (u16) v); - skge_write32(hw, SK_GMAC_REG(port, r+4), (u16)(v >> 16)); + skge_write16(hw, SKGEGMA_REG(port,r), v); } -static inline void gma_write8(const struct skge_hw *hw, int port, int r, u8 v) +static inline void skge_gma_write32(const struct skge_hw *hw, int port, int r, u32 v) { - skge_write8(hw, SK_GMAC_REG(port,r), v); + skge_write16(hw, SKGEGMA_REG(port, r), (u16) v); + skge_write32(hw, SKGEGMA_REG(port, r+4), (u16)(v >> 16)); } -static inline void gma_set_addr(struct skge_hw *hw, int port, int reg, - const u8 *addr) +static inline void skge_gma_write8(const struct skge_hw *hw, int port, int r, u8 v) { - gma_write16(hw, port, reg, (u16) addr[0] | ((u16) addr[1] << 8)); - gma_write16(hw, port, reg+4,(u16) addr[2] | ((u16) addr[3] << 8)); - gma_write16(hw, port, reg+8,(u16) addr[4] | ((u16) addr[5] << 8)); + skge_write8(hw, SKGEGMA_REG(port,r), v); } +static inline void skge_gm_set_addr(struct skge_hw *hw, int port, int reg, + const u8 *addr) +{ + skge_gma_write16(hw, port, reg, + (u16) addr[0] | ((u16) addr[1] << 8)); + skge_gma_write16(hw, port, reg+4, + (u16) addr[2] | ((u16) addr[3] << 8)); + skge_gma_write16(hw, port, reg+8, + (u16) addr[4] | ((u16) addr[5] << 8)); +} + #endif diff --git a/trunk/drivers/net/smc91x.c b/trunk/drivers/net/smc91x.c index 1438fdd20826..cfb9d3cdb04a 100644 --- a/trunk/drivers/net/smc91x.c +++ b/trunk/drivers/net/smc91x.c @@ -1998,7 +1998,7 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) if (retval) goto err_out; - set_irq_type(dev->irq, SMC_IRQ_TRIGGER_TYPE); + set_irq_type(dev->irq, IRQT_RISING); #ifdef SMC_USE_PXA_DMA { diff --git a/trunk/drivers/net/smc91x.h b/trunk/drivers/net/smc91x.h index 7089d86e857a..946528e6b742 100644 --- a/trunk/drivers/net/smc91x.h +++ b/trunk/drivers/net/smc91x.h @@ -182,16 +182,6 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) #define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) -#include -#include - -#define SMC_IRQ_TRIGGER_TYPE (( \ - machine_is_omap_h2() \ - || machine_is_omap_h3() \ - || (machine_is_omap_innovator() && !cpu_is_omap150()) \ - ) ? IRQT_FALLING : IRQT_RISING) - - #elif defined(CONFIG_SH_SH4202_MICRODEV) #define SMC_CAN_USE_8BIT 0 @@ -310,9 +300,6 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l) #endif -#ifndef SMC_IRQ_TRIGGER_TYPE -#define SMC_IRQ_TRIGGER_TYPE IRQT_RISING -#endif #ifdef SMC_USE_PXA_DMA /* diff --git a/trunk/drivers/net/via-rhine.c b/trunk/drivers/net/via-rhine.c index eb0e7bd4dcf8..be1c1047b9ba 100644 --- a/trunk/drivers/net/via-rhine.c +++ b/trunk/drivers/net/via-rhine.c @@ -507,7 +507,7 @@ static struct net_device_stats *rhine_get_stats(struct net_device *dev); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static struct ethtool_ops netdev_ethtool_ops; static int rhine_close(struct net_device *dev); -static void rhine_shutdown (struct pci_dev *pdev); +static void rhine_shutdown (struct device *gdev); #define RHINE_WAIT_FOR(condition) do { \ int i=1024; \ @@ -1895,8 +1895,9 @@ static void __devexit rhine_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } -static void rhine_shutdown (struct pci_dev *pdev) +static void rhine_shutdown (struct device *gendev) { + struct pci_dev *pdev = to_pci_dev(gendev); struct net_device *dev = pci_get_drvdata(pdev); struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; @@ -1955,7 +1956,7 @@ static int rhine_suspend(struct pci_dev *pdev, pm_message_t state) pci_save_state(pdev); spin_lock_irqsave(&rp->lock, flags); - rhine_shutdown(pdev); + rhine_shutdown(&pdev->dev); spin_unlock_irqrestore(&rp->lock, flags); free_irq(dev->irq, dev); @@ -2009,7 +2010,9 @@ static struct pci_driver rhine_driver = { .suspend = rhine_suspend, .resume = rhine_resume, #endif /* CONFIG_PM */ - .shutdown = rhine_shutdown, + .driver = { + .shutdown = rhine_shutdown, + } }; diff --git a/trunk/drivers/parisc/dino.c b/trunk/drivers/parisc/dino.c index 2f2dbef2c3b7..b0d2a73d1d47 100644 --- a/trunk/drivers/parisc/dino.c +++ b/trunk/drivers/parisc/dino.c @@ -993,7 +993,6 @@ dino_driver_callback(struct parisc_device *dev) bus = pci_scan_bus_parented(&dev->dev, dino_current_bus, &dino_cfg_ops, NULL); if(bus) { - pci_bus_add_devices(bus); /* This code *depends* on scanning being single threaded * if it isn't, this global bus number count will fail */ diff --git a/trunk/drivers/parisc/lba_pci.c b/trunk/drivers/parisc/lba_pci.c index 7fdd80b7eb47..dc838804c0dd 100644 --- a/trunk/drivers/parisc/lba_pci.c +++ b/trunk/drivers/parisc/lba_pci.c @@ -1570,8 +1570,6 @@ lba_driver_probe(struct parisc_device *dev) lba_bus = lba_dev->hba.hba_bus = pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start, cfg_ops, NULL); - if (lba_bus) - pci_bus_add_devices(lba_bus); /* This is in lieu of calling pci_assign_unassigned_resources() */ if (is_pdc_pat()) { diff --git a/trunk/drivers/pci/bus.c b/trunk/drivers/pci/bus.c index fedae89d8f7d..dbd33605cc10 100644 --- a/trunk/drivers/pci/bus.c +++ b/trunk/drivers/pci/bus.c @@ -121,13 +121,10 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus) * If there is an unattached subordinate bus, attach * it and then scan for unattached PCI devices. */ - if (dev->subordinate) { - if (list_empty(&dev->subordinate->node)) { - spin_lock(&pci_bus_lock); - list_add_tail(&dev->subordinate->node, - &dev->bus->children); - spin_unlock(&pci_bus_lock); - } + if (dev->subordinate && list_empty(&dev->subordinate->node)) { + spin_lock(&pci_bus_lock); + list_add_tail(&dev->subordinate->node, &dev->bus->children); + spin_unlock(&pci_bus_lock); pci_bus_add_devices(dev->subordinate); sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge"); diff --git a/trunk/drivers/pci/hotplug/Makefile b/trunk/drivers/pci/hotplug/Makefile index 3e632ff8c717..93c120ddbd39 100644 --- a/trunk/drivers/pci/hotplug/Makefile +++ b/trunk/drivers/pci/hotplug/Makefile @@ -36,7 +36,9 @@ ibmphp-objs := ibmphp_core.o \ ibmphp_hpc.o acpiphp-objs := acpiphp_core.o \ - acpiphp_glue.o + acpiphp_glue.o \ + acpiphp_pci.o \ + acpiphp_res.o rpaphp-objs := rpaphp_core.o \ rpaphp_pci.o \ diff --git a/trunk/drivers/pci/hotplug/acpiphp.h b/trunk/drivers/pci/hotplug/acpiphp.h index 293603e1b7c3..d9499874c8a9 100644 --- a/trunk/drivers/pci/hotplug/acpiphp.h +++ b/trunk/drivers/pci/hotplug/acpiphp.h @@ -7,8 +7,6 @@ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (C) 2002,2003 NEC Corporation - * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) - * Copyright (C) 2003-2005 Hewlett Packard * * All rights reserved. * @@ -54,6 +52,7 @@ struct acpiphp_bridge; struct acpiphp_slot; +struct pci_resource; /* * struct slot - slot information for each *physical* slot @@ -66,6 +65,15 @@ struct slot { struct acpiphp_slot *acpi_slot; }; +/* + * struct pci_resource - describes pci resource (mem, pfmem, io, bus) + */ +struct pci_resource { + struct pci_resource * next; + u64 base; + u32 length; +}; + /** * struct hpp_param - ACPI 2.0 _HPP Hot Plug Parameters * @cache_line_size in DWORD @@ -93,6 +101,10 @@ struct acpiphp_bridge { int type; int nr_slots; + u8 seg; + u8 bus; + u8 sub; + u32 flags; /* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */ @@ -105,6 +117,12 @@ struct acpiphp_bridge { struct hpp_param hpp; spinlock_t res_lock; + + /* available resources on this bus */ + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; }; @@ -145,6 +163,12 @@ struct acpiphp_func { u8 function; /* pci function# */ u32 flags; /* see below */ + + /* resources used for this function */ + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; }; /** @@ -219,6 +243,25 @@ extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); extern u32 acpiphp_get_address (struct acpiphp_slot *slot); +/* acpiphp_pci.c */ +extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn); +extern int acpiphp_configure_slot (struct acpiphp_slot *slot); +extern int acpiphp_configure_function (struct acpiphp_func *func); +extern void acpiphp_unconfigure_function (struct acpiphp_func *func); +extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge); +extern int acpiphp_init_func_resource (struct acpiphp_func *func); + +/* acpiphp_res.c */ +extern struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size); +extern struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size); +extern struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size); +extern int acpiphp_resource_sort_and_combine (struct pci_resource **head); +extern struct pci_resource *acpiphp_make_resource (u64 base, u32 length); +extern void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to); +extern void acpiphp_free_resource (struct pci_resource **res); +extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */ +extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */ + /* variables */ extern int acpiphp_debug; diff --git a/trunk/drivers/pci/hotplug/acpiphp_core.c b/trunk/drivers/pci/hotplug/acpiphp_core.c index 60c4c38047a3..4539e61a3dc1 100644 --- a/trunk/drivers/pci/hotplug/acpiphp_core.c +++ b/trunk/drivers/pci/hotplug/acpiphp_core.c @@ -7,8 +7,6 @@ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (C) 2002,2003 NEC Corporation - * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) - * Copyright (C) 2003-2005 Hewlett Packard * * All rights reserved. * @@ -55,8 +53,8 @@ int acpiphp_debug; static int num_slots; static struct acpiphp_attention_info *attention_info; -#define DRIVER_VERSION "0.5" -#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi , Matthew Wilcox " +#define DRIVER_VERSION "0.4" +#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi " #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver" MODULE_AUTHOR(DRIVER_AUTHOR); @@ -283,7 +281,8 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) /** * get_address - get pci address of a slot * @hotplug_slot: slot to get status - * @value: pointer to struct pci_busdev (seg, bus, dev) + * @busdev: pointer to struct pci_busdev (seg, bus, dev) + * */ static int get_address(struct hotplug_slot *hotplug_slot, u32 *value) { diff --git a/trunk/drivers/pci/hotplug/acpiphp_glue.c b/trunk/drivers/pci/hotplug/acpiphp_glue.c index 424e7de181ae..e7f41294f811 100644 --- a/trunk/drivers/pci/hotplug/acpiphp_glue.c +++ b/trunk/drivers/pci/hotplug/acpiphp_glue.c @@ -4,10 +4,6 @@ * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) * Copyright (C) 2002,2003 NEC Corporation - * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) - * Copyright (C) 2003-2005 Hewlett Packard - * Copyright (C) 2005 Rajesh Shah (rajesh.shah@intel.com) - * Copyright (C) 2005 Intel Corporation * * All rights reserved. * @@ -30,16 +26,6 @@ * */ -/* - * Lifetime rules for pci_dev: - * - The one in acpiphp_func has its refcount elevated by pci_get_slot() - * when the driver is loaded or when an insertion event occurs. It loses - * a refcount when its ejected or the driver unloads. - * - The one in acpiphp_bridge has its refcount elevated by pci_get_slot() - * when the bridge is scanned and it loses a refcount when the bridge - * is removed. - */ - #include #include @@ -192,18 +178,21 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) bridge->nr_slots++; - dbg("found ACPI PCI Hotplug slot %d at PCI %04x:%02x:%02x\n", - slot->sun, pci_domain_nr(bridge->pci_bus), - bridge->pci_bus->number, slot->device); + dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n", + slot->bridge->bus, slot->device, slot->sun); } newfunc->slot = slot; list_add_tail(&newfunc->sibling, &slot->funcs); /* associate corresponding pci_dev */ - newfunc->pci_dev = pci_get_slot(bridge->pci_bus, + newfunc->pci_dev = pci_find_slot(bridge->bus, PCI_DEVFN(device, function)); if (newfunc->pci_dev) { + if (acpiphp_init_func_resource(newfunc) < 0) { + kfree(newfunc); + return AE_ERROR; + } slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); } @@ -238,6 +227,62 @@ static int detect_ejectable_slots(acpi_handle *bridge_handle) } +/* decode ACPI _CRS data and convert into our internal resource list + * TBD: _TRA, etc. + */ +static acpi_status +decode_acpi_resource(struct acpi_resource *resource, void *context) +{ + struct acpiphp_bridge *bridge = (struct acpiphp_bridge *) context; + struct acpi_resource_address64 address; + struct pci_resource *res; + + if (resource->id != ACPI_RSTYPE_ADDRESS16 && + resource->id != ACPI_RSTYPE_ADDRESS32 && + resource->id != ACPI_RSTYPE_ADDRESS64) + return AE_OK; + + acpi_resource_to_address64(resource, &address); + + if (address.producer_consumer == ACPI_PRODUCER && address.address_length > 0) { + dbg("resource type: %d: 0x%llx - 0x%llx\n", address.resource_type, + (unsigned long long)address.min_address_range, + (unsigned long long)address.max_address_range); + res = acpiphp_make_resource(address.min_address_range, + address.address_length); + if (!res) { + err("out of memory\n"); + return AE_OK; + } + + switch (address.resource_type) { + case ACPI_MEMORY_RANGE: + if (address.attribute.memory.cache_attribute == ACPI_PREFETCHABLE_MEMORY) { + res->next = bridge->p_mem_head; + bridge->p_mem_head = res; + } else { + res->next = bridge->mem_head; + bridge->mem_head = res; + } + break; + case ACPI_IO_RANGE: + res->next = bridge->io_head; + bridge->io_head = res; + break; + case ACPI_BUS_NUMBER_RANGE: + res->next = bridge->bus_head; + bridge->bus_head = res; + break; + default: + /* invalid type */ + kfree(res); + break; + } + } + + return AE_OK; +} + /* decode ACPI 2.0 _HPP hot plug parameters */ static void decode_hpp(struct acpiphp_bridge *bridge) { @@ -301,29 +346,34 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) /* decode ACPI 2.0 _HPP (hot plug parameters) */ decode_hpp(bridge); + /* subtract all resources already allocated */ + acpiphp_detect_pci_resource(bridge); + /* register all slot objects under this bridge */ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, register_slot, bridge, NULL); /* install notify handler */ - if (bridge->type != BRIDGE_TYPE_HOST) { - status = acpi_install_notify_handler(bridge->handle, + status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_bridge, bridge); - if (ACPI_FAILURE(status)) { - err("failed to register interrupt notify handler\n"); - } + if (ACPI_FAILURE(status)) { + err("failed to register interrupt notify handler\n"); } list_add(&bridge->list, &bridge_list); + + dbg("Bridge resource:\n"); + acpiphp_dump_resource(bridge); } /* allocate and initialize host bridge data structure */ -static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) +static void add_host_bridge(acpi_handle *handle, int seg, int bus) { + acpi_status status; struct acpiphp_bridge *bridge; bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); @@ -334,19 +384,52 @@ static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) bridge->type = BRIDGE_TYPE_HOST; bridge->handle = handle; + bridge->seg = seg; + bridge->bus = bus; - bridge->pci_bus = pci_bus; + bridge->pci_bus = pci_find_bus(seg, bus); spin_lock_init(&bridge->res_lock); + /* to be overridden when we decode _CRS */ + bridge->sub = bridge->bus; + + /* decode resources */ + + status = acpi_walk_resources(handle, METHOD_NAME__CRS, + decode_acpi_resource, bridge); + + if (ACPI_FAILURE(status)) { + err("failed to decode bridge resources\n"); + kfree(bridge); + return; + } + + acpiphp_resource_sort_and_combine(&bridge->io_head); + acpiphp_resource_sort_and_combine(&bridge->mem_head); + acpiphp_resource_sort_and_combine(&bridge->p_mem_head); + acpiphp_resource_sort_and_combine(&bridge->bus_head); + + dbg("ACPI _CRS resource:\n"); + acpiphp_dump_resource(bridge); + + if (bridge->bus_head) { + bridge->bus = bridge->bus_head->base; + bridge->sub = bridge->bus_head->base + bridge->bus_head->length - 1; + } + init_bridge_misc(bridge); } /* allocate and initialize PCI-to-PCI bridge data structure */ -static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev) +static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int fn) { struct acpiphp_bridge *bridge; + u8 tmp8; + u16 tmp16; + u64 base64, limit64; + u32 base, limit, base32u, limit32u; bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); if (bridge == NULL) { @@ -358,22 +441,133 @@ static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev) bridge->type = BRIDGE_TYPE_P2P; bridge->handle = handle; + bridge->seg = seg; + + bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn)); + if (!bridge->pci_dev) { + err("Can't get pci_dev\n"); + kfree(bridge); + return; + } - bridge->pci_dev = pci_dev_get(pci_dev); - bridge->pci_bus = pci_dev->subordinate; + bridge->pci_bus = bridge->pci_dev->subordinate; if (!bridge->pci_bus) { err("This is not a PCI-to-PCI bridge!\n"); - goto err; + kfree(bridge); + return; } spin_lock_init(&bridge->res_lock); + bridge->bus = bridge->pci_bus->number; + bridge->sub = bridge->pci_bus->subordinate; + + /* + * decode resources under this P2P bridge + */ + + /* I/O resources */ + pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8); + base = tmp8; + pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8); + limit = tmp8; + + switch (base & PCI_IO_RANGE_TYPE_MASK) { + case PCI_IO_RANGE_TYPE_16: + base = (base << 8) & 0xf000; + limit = ((limit << 8) & 0xf000) + 0xfff; + bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); + if (!bridge->io_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("16bit I/O range: %04x-%04x\n", + (u32)bridge->io_head->base, + (u32)(bridge->io_head->base + bridge->io_head->length - 1)); + break; + case PCI_IO_RANGE_TYPE_32: + pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16); + base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000); + pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16); + limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff; + bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); + if (!bridge->io_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("32bit I/O range: %08x-%08x\n", + (u32)bridge->io_head->base, + (u32)(bridge->io_head->base + bridge->io_head->length - 1)); + break; + case 0x0f: + dbg("I/O space unsupported\n"); + break; + default: + warn("Unknown I/O range type\n"); + } + + /* Memory resources (mandatory for P2P bridge) */ + pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16); + base = (tmp16 & 0xfff0) << 16; + pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16); + limit = ((tmp16 & 0xfff0) << 16) | 0xfffff; + bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1); + if (!bridge->mem_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("32bit Memory range: %08x-%08x\n", + (u32)bridge->mem_head->base, + (u32)(bridge->mem_head->base + bridge->mem_head->length-1)); + + /* Prefetchable Memory resources (optional) */ + pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16); + base = tmp16; + pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16); + limit = tmp16; + + switch (base & PCI_MEMORY_RANGE_TYPE_MASK) { + case PCI_PREF_RANGE_TYPE_32: + base = (base & 0xfff0) << 16; + limit = ((limit & 0xfff0) << 16) | 0xfffff; + bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1); + if (!bridge->p_mem_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("32bit Prefetchable memory range: %08x-%08x\n", + (u32)bridge->p_mem_head->base, + (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1)); + break; + case PCI_PREF_RANGE_TYPE_64: + pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u); + pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u); + base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16); + limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff; + + bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1); + if (!bridge->p_mem_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n", + (u32)(bridge->p_mem_head->base >> 32), + (u32)(bridge->p_mem_head->base & 0xffffffff), + (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32), + (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff)); + break; + case 0x0f: + break; + default: + warn("Unknown prefetchale memory type\n"); + } + init_bridge_misc(bridge); - return; - err: - pci_dev_put(pci_dev); - kfree(bridge); - return; } @@ -383,10 +577,14 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) { acpi_status status; acpi_handle dummy_handle; + unsigned long *segbus = context; unsigned long tmp; - int device, function; + int seg, bus, device, function; struct pci_dev *dev; - struct pci_bus *pci_bus = context; + + /* get PCI address */ + seg = (*segbus >> 8) & 0xff; + bus = *segbus & 0xff; status = acpi_get_handle(handle, "_ADR", &dummy_handle); if (ACPI_FAILURE(status)) @@ -401,19 +599,20 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) device = (tmp >> 16) & 0xffff; function = tmp & 0xffff; - dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function)); + dev = pci_find_slot(bus, PCI_DEVFN(device, function)); - if (!dev || !dev->subordinate) - goto out; + if (!dev) + return AE_OK; + + if (!dev->subordinate) + return AE_OK; /* check if this bridge has ejectable slots */ if (detect_ejectable_slots(handle) > 0) { dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); - add_p2p_bridge(handle, dev); + add_p2p_bridge(handle, seg, bus, device, function); } - out: - pci_dev_put(dev); return AE_OK; } @@ -425,7 +624,6 @@ static int add_bridge(acpi_handle handle) unsigned long tmp; int seg, bus; acpi_handle dummy_handle; - struct pci_bus *pci_bus; /* if the bridge doesn't have _STA, we assume it is always there */ status = acpi_get_handle(handle, "_STA", &dummy_handle); @@ -455,22 +653,18 @@ static int add_bridge(acpi_handle handle) bus = 0; } - pci_bus = pci_find_bus(seg, bus); - if (!pci_bus) { - err("Can't find bus %04x:%02x\n", seg, bus); - return 0; - } - /* check if this bridge has ejectable slots */ if (detect_ejectable_slots(handle) > 0) { dbg("found PCI host-bus bridge with hot-pluggable slots\n"); - add_host_bridge(handle, pci_bus); + add_host_bridge(handle, seg, bus); return 0; } + tmp = seg << 8 | bus; + /* search P2P bridges under this host bridge */ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, - find_p2p_bridge, pci_bus, NULL); + find_p2p_bridge, &tmp, NULL); if (ACPI_FAILURE(status)) warn("find_p2p_bridge faied (error code = 0x%x)\n",status); @@ -478,205 +672,12 @@ static int add_bridge(acpi_handle handle) return 0; } -static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) -{ - struct list_head *head; - list_for_each(head, &bridge_list) { - struct acpiphp_bridge *bridge = list_entry(head, - struct acpiphp_bridge, list); - if (bridge->handle == handle) - return bridge; - } - - return NULL; -} - -static void cleanup_bridge(struct acpiphp_bridge *bridge) -{ - struct list_head *list, *tmp; - struct acpiphp_slot *slot; - acpi_status status; - acpi_handle handle = bridge->handle; - - status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - - slot = bridge->slots; - while (slot) { - struct acpiphp_slot *next = slot->next; - list_for_each_safe (list, tmp, &slot->funcs) { - struct acpiphp_func *func; - func = list_entry(list, struct acpiphp_func, sibling); - status = acpi_remove_notify_handler(func->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - pci_dev_put(func->pci_dev); - list_del(list); - kfree(func); - } - kfree(slot); - slot = next; - } - - pci_dev_put(bridge->pci_dev); - list_del(&bridge->list); - kfree(bridge); -} - -static acpi_status -cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - struct acpiphp_bridge *bridge; - - if (!(bridge = acpiphp_handle_to_bridge(handle))) - return AE_OK; - cleanup_bridge(bridge); - return AE_OK; -} static void remove_bridge(acpi_handle handle) { - struct acpiphp_bridge *bridge; - - bridge = acpiphp_handle_to_bridge(handle); - if (bridge) { - cleanup_bridge(bridge); - } else { - /* clean-up p2p bridges under this host bridge */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - (u32)1, cleanup_p2p_bridge, NULL, NULL); - } -} - -static struct pci_dev * get_apic_pci_info(acpi_handle handle) -{ - struct acpi_pci_id id; - struct pci_bus *bus; - struct pci_dev *dev; - - if (ACPI_FAILURE(acpi_get_pci_id(handle, &id))) - return NULL; - - bus = pci_find_bus(id.segment, id.bus); - if (!bus) - return NULL; - - dev = pci_get_slot(bus, PCI_DEVFN(id.device, id.function)); - if (!dev) - return NULL; - - if ((dev->class != PCI_CLASS_SYSTEM_PIC_IOAPIC) && - (dev->class != PCI_CLASS_SYSTEM_PIC_IOXAPIC)) - { - pci_dev_put(dev); - return NULL; - } - - return dev; -} - -static int get_gsi_base(acpi_handle handle, u32 *gsi_base) -{ - acpi_status status; - int result = -1; - unsigned long gsb; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object *obj; - void *table; - - status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb); - if (ACPI_SUCCESS(status)) { - *gsi_base = (u32)gsb; - return 0; - } - - status = acpi_evaluate_object(handle, "_MAT", NULL, &buffer); - if (ACPI_FAILURE(status) || !buffer.length || !buffer.pointer) - return -1; - - obj = buffer.pointer; - if (obj->type != ACPI_TYPE_BUFFER) - 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; - result = 0; - break; - case ACPI_MADT_IOAPIC: - *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base; - result = 0; - break; - default: - break; - } - out: - acpi_os_free(buffer.pointer); - return result; -} - -static acpi_status -ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - acpi_status status; - unsigned long sta; - acpi_handle tmp; - struct pci_dev *pdev; - u32 gsi_base; - u64 phys_addr; - - /* Evaluate _STA if present */ - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); - if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL) - return AE_CTRL_DEPTH; - - /* Scan only PCI bus scope */ - status = acpi_get_handle(handle, "_HID", &tmp); - if (ACPI_SUCCESS(status)) - return AE_CTRL_DEPTH; - - if (get_gsi_base(handle, &gsi_base)) - return AE_OK; - - pdev = get_apic_pci_info(handle); - if (!pdev) - return AE_OK; - - if (pci_enable_device(pdev)) { - pci_dev_put(pdev); - return AE_OK; - } - - pci_set_master(pdev); - - if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) { - pci_disable_device(pdev); - pci_dev_put(pdev); - return AE_OK; - } - - phys_addr = pci_resource_start(pdev, 0); - if (acpi_register_ioapic(handle, phys_addr, gsi_base)) { - pci_release_region(pdev, 0); - pci_disable_device(pdev); - pci_dev_put(pdev); - return AE_OK; - } - - return AE_OK; + /* No-op for now .. */ } -static int acpiphp_configure_ioapics(acpi_handle handle) -{ - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - ACPI_UINT32_MAX, ioapic_add, NULL, NULL); - return 0; -} static int power_on_slot(struct acpiphp_slot *slot) { @@ -718,6 +719,8 @@ static int power_off_slot(struct acpiphp_slot *slot) acpi_status status; struct acpiphp_func *func; struct list_head *l; + struct acpi_object_list arg_list; + union acpi_object arg; int retval = 0; @@ -728,7 +731,7 @@ static int power_off_slot(struct acpiphp_slot *slot) list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - if (func->flags & FUNC_HAS_PS3) { + if (func->pci_dev && (func->flags & FUNC_HAS_PS3)) { status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS3 failed\n", __FUNCTION__); @@ -739,6 +742,27 @@ static int power_off_slot(struct acpiphp_slot *slot) } } + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + /* We don't want to call _EJ0 on non-existing functions. */ + if (func->pci_dev && (func->flags & FUNC_HAS_EJ0)) { + /* _EJ0 method take one argument */ + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; + + status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: _EJ0 failed\n", __FUNCTION__); + retval = -1; + goto err_exit; + } else + break; + } + } + /* TBD: evaluate _STA to check if the slot is disabled */ slot->flags &= (~SLOT_POWEREDON); @@ -758,56 +782,70 @@ static int power_off_slot(struct acpiphp_slot *slot) */ static int enable_device(struct acpiphp_slot *slot) { + u8 bus; struct pci_dev *dev; - struct pci_bus *bus = slot->bridge->pci_bus; + struct pci_bus *child; struct list_head *l; struct acpiphp_func *func; int retval = 0; - int num, max, pass; + int num; if (slot->flags & SLOT_ENABLED) goto err_exit; /* sanity check: dev should be NULL when hot-plugged in */ - dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0)); + dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); if (dev) { /* This case shouldn't happen */ err("pci_dev structure already exists.\n"); - pci_dev_put(dev); retval = -1; goto err_exit; } - num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); - if (num == 0) { + /* allocate resources to device */ + retval = acpiphp_configure_slot(slot); + if (retval) + goto err_exit; + + /* returned `dev' is the *first function* only! */ + num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0)); + if (num) + pci_bus_add_devices(slot->bridge->pci_bus); + dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); + + if (!dev) { err("No new device found\n"); retval = -1; goto err_exit; } - max = bus->secondary; - for (pass = 0; pass < 2; pass++) { - list_for_each_entry(dev, &bus->devices, bus_list) { - if (PCI_SLOT(dev->devfn) != slot->device) - continue; - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) - max = pci_scan_bridge(bus, dev, max, pass); - } + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus); + pci_do_scan_bus(child); } - pci_bus_assign_resources(bus); - pci_bus_add_devices(bus); - /* associate pci_dev to our representation */ list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device, + + func->pci_dev = pci_find_slot(slot->bridge->bus, + PCI_DEVFN(slot->device, func->function)); + if (!func->pci_dev) + continue; + + /* configure device */ + retval = acpiphp_configure_function(func); + if (retval) + goto err_exit; } slot->flags |= SLOT_ENABLED; + dbg("Available resources:\n"); + acpiphp_dump_resource(slot->bridge); + err_exit: return retval; } @@ -828,12 +866,9 @@ static int disable_device(struct acpiphp_slot *slot) list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - if (!func->pci_dev) - continue; - pci_remove_bus_device(func->pci_dev); - pci_dev_put(func->pci_dev); - func->pci_dev = NULL; + if (func->pci_dev) + acpiphp_unconfigure_function(func); } slot->flags &= (~SLOT_ENABLED); @@ -884,39 +919,6 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) return (unsigned int)sta; } -/** - * acpiphp_eject_slot - physically eject the slot - */ -static int acpiphp_eject_slot(struct acpiphp_slot *slot) -{ - acpi_status status; - struct acpiphp_func *func; - struct list_head *l; - struct acpi_object_list arg_list; - union acpi_object arg; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - /* We don't want to call _EJ0 on non-existing functions. */ - if ((func->flags & FUNC_HAS_EJ0)) { - /* _EJ0 method take one argument */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _EJ0 failed\n", __FUNCTION__); - return -1; - } else - break; - } - } - return 0; -} - /** * acpiphp_check_bridge - re-enumerate devices * @@ -940,8 +942,6 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge) if (retval) { err("Error occurred in disabling\n"); goto err_exit; - } else { - acpiphp_eject_slot(slot); } disabled++; } else { @@ -962,144 +962,6 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge) return retval; } -static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) -{ - u16 pci_cmd, pci_bctl; - struct pci_dev *cdev; - - /* Program hpp values for this device */ - if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || - (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) - return; - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, - bridge->hpp.cache_line_size); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, - bridge->hpp.latency_timer); - pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); - if (bridge->hpp.enable_SERR) - pci_cmd |= PCI_COMMAND_SERR; - else - pci_cmd &= ~PCI_COMMAND_SERR; - if (bridge->hpp.enable_PERR) - pci_cmd |= PCI_COMMAND_PARITY; - else - pci_cmd &= ~PCI_COMMAND_PARITY; - pci_write_config_word(dev, PCI_COMMAND, pci_cmd); - - /* Program bridge control value and child devices */ - if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { - pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, - bridge->hpp.latency_timer); - pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); - if (bridge->hpp.enable_SERR) - pci_bctl |= PCI_BRIDGE_CTL_SERR; - else - pci_bctl &= ~PCI_BRIDGE_CTL_SERR; - if (bridge->hpp.enable_PERR) - pci_bctl |= PCI_BRIDGE_CTL_PARITY; - else - pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; - pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); - if (dev->subordinate) { - list_for_each_entry(cdev, &dev->subordinate->devices, - bus_list) - program_hpp(cdev, bridge); - } - } -} - -static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus) -{ - struct acpiphp_bridge bridge; - struct pci_dev *dev; - - memset(&bridge, 0, sizeof(bridge)); - bridge.handle = handle; - decode_hpp(&bridge); - list_for_each_entry(dev, &bus->devices, bus_list) - program_hpp(dev, &bridge); - -} - -/* - * Remove devices for which we could not assign resources, call - * arch specific code to fix-up the bus - */ -static void acpiphp_sanitize_bus(struct pci_bus *bus) -{ - struct pci_dev *dev; - int i; - unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; - - list_for_each_entry(dev, &bus->devices, bus_list) { - for (i=0; iresource[i]; - if ((res->flags & type_mask) && !res->start && - res->end) { - /* Could not assign a required resources - * for this device, remove it */ - pci_remove_bus_device(dev); - break; - } - } - } -} - -/* Program resources in newly inserted bridge */ -static int acpiphp_configure_bridge (acpi_handle handle) -{ - struct acpi_pci_id pci_id; - struct pci_bus *bus; - - if (ACPI_FAILURE(acpi_get_pci_id(handle, &pci_id))) { - err("cannot get PCI domain and bus number for bridge\n"); - return -EINVAL; - } - bus = pci_find_bus(pci_id.segment, pci_id.bus); - if (!bus) { - err("cannot find bus %d:%d\n", - pci_id.segment, pci_id.bus); - return -EINVAL; - } - - pci_bus_size_bridges(bus); - pci_bus_assign_resources(bus); - acpiphp_sanitize_bus(bus); - acpiphp_set_hpp_values(handle, bus); - pci_enable_bridges(bus); - acpiphp_configure_ioapics(handle); - return 0; -} - -static void handle_bridge_insertion(acpi_handle handle, u32 type) -{ - struct acpi_device *device, *pdevice; - acpi_handle phandle; - - if ((type != ACPI_NOTIFY_BUS_CHECK) && - (type != ACPI_NOTIFY_DEVICE_CHECK)) { - err("unexpected notification type %d\n", type); - return; - } - - acpi_get_parent(handle, &phandle); - if (acpi_bus_get_device(phandle, &pdevice)) { - dbg("no parent device, assuming NULL\n"); - pdevice = NULL; - } - if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) { - err("cannot add bridge to acpi list\n"); - return; - } - if (!acpiphp_configure_bridge(handle) && - !acpi_bus_start(device)) - add_bridge(handle); - else - err("cannot configure and start bridge\n"); - -} - /* * ACPI event handlers */ @@ -1120,19 +982,8 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; - struct acpi_device *device; - if (acpi_bus_get_device(handle, &device)) { - /* This bridge must have just been physically inserted */ - handle_bridge_insertion(handle, type); - return; - } - - bridge = acpiphp_handle_to_bridge(handle); - if (!bridge) { - err("cannot get bridge info\n"); - return; - } + bridge = (struct acpiphp_bridge *)context; acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); @@ -1180,6 +1031,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont } } + /** * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) * @@ -1222,8 +1074,7 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); - if (!(acpiphp_disable_slot(func->slot))) - acpiphp_eject_slot(func->slot); + acpiphp_disable_slot(func->slot); break; default: @@ -1232,47 +1083,6 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex } } -static int is_root_bridge(acpi_handle handle) -{ - acpi_status status; - struct acpi_device_info *info; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - int i; - - status = acpi_get_object_info(handle, &buffer); - if (ACPI_SUCCESS(status)) { - info = buffer.pointer; - if ((info->valid & ACPI_VALID_HID) && - !strcmp(PCI_ROOT_HID_STRING, - info->hardware_id.value)) { - acpi_os_free(buffer.pointer); - return 1; - } - if (info->valid & ACPI_VALID_CID) { - for (i=0; i < info->compatibility_id.count; i++) { - if (!strcmp(PCI_ROOT_HID_STRING, - info->compatibility_id.id[i].value)) { - acpi_os_free(buffer.pointer); - return 1; - } - } - } - } - return 0; -} - -static acpi_status -find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - int *count = (int *)context; - - if (is_root_bridge(handle)) { - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge, NULL); - (*count)++; - } - return AE_OK ; -} static struct acpi_pci_driver acpi_pci_hp_driver = { .add = add_bridge, @@ -1285,15 +1095,15 @@ static struct acpi_pci_driver acpi_pci_hp_driver = { */ int __init acpiphp_glue_init(void) { - int num = 0; + int num; + + if (list_empty(&pci_root_buses)) + return -1; - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_root_bridges, &num, NULL); + num = acpi_pci_register_driver(&acpi_pci_hp_driver); if (num <= 0) return -1; - else - acpi_pci_register_driver(&acpi_pci_hp_driver); return 0; } @@ -1306,6 +1116,46 @@ int __init acpiphp_glue_init(void) */ void __exit acpiphp_glue_exit(void) { + struct list_head *l1, *l2, *n1, *n2; + struct acpiphp_bridge *bridge; + struct acpiphp_slot *slot, *next; + struct acpiphp_func *func; + acpi_status status; + + list_for_each_safe (l1, n1, &bridge_list) { + bridge = (struct acpiphp_bridge *)l1; + slot = bridge->slots; + while (slot) { + next = slot->next; + list_for_each_safe (l2, n2, &slot->funcs) { + func = list_entry(l2, struct acpiphp_func, sibling); + acpiphp_free_resource(&func->io_head); + acpiphp_free_resource(&func->mem_head); + acpiphp_free_resource(&func->p_mem_head); + acpiphp_free_resource(&func->bus_head); + status = acpi_remove_notify_handler(func->handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_func); + if (ACPI_FAILURE(status)) + err("failed to remove notify handler\n"); + kfree(func); + } + kfree(slot); + slot = next; + } + status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge); + if (ACPI_FAILURE(status)) + err("failed to remove notify handler\n"); + + acpiphp_free_resource(&bridge->io_head); + acpiphp_free_resource(&bridge->mem_head); + acpiphp_free_resource(&bridge->p_mem_head); + acpiphp_free_resource(&bridge->bus_head); + + kfree(bridge); + } + acpi_pci_unregister_driver(&acpi_pci_hp_driver); } @@ -1323,14 +1173,11 @@ int __init acpiphp_get_num_slots(void) list_for_each (node, &bridge_list) { bridge = (struct acpiphp_bridge *)node; - dbg("Bus %04x:%02x has %d slot%s\n", - pci_domain_nr(bridge->pci_bus), - bridge->pci_bus->number, bridge->nr_slots, - bridge->nr_slots == 1 ? "" : "s"); + dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots); num_slots += bridge->nr_slots; } - dbg("Total %d slots\n", num_slots); + dbg("Total %dslots\n", num_slots); return num_slots; } @@ -1407,6 +1254,7 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) return retval; } + /** * acpiphp_disable_slot - power off slot */ @@ -1426,6 +1274,13 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot) if (retval) goto err_exit; + acpiphp_resource_sort_and_combine(&slot->bridge->io_head); + acpiphp_resource_sort_and_combine(&slot->bridge->mem_head); + acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head); + acpiphp_resource_sort_and_combine(&slot->bridge->bus_head); + dbg("Available resources:\n"); + acpiphp_dump_resource(slot->bridge); + err_exit: up(&slot->crit_sect); return retval; @@ -1438,7 +1293,11 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot) */ u8 acpiphp_get_power_status(struct acpiphp_slot *slot) { - return (slot->flags & SLOT_POWEREDON); + unsigned int sta; + + sta = get_slot_status(slot); + + return (sta & ACPI_STA_ENABLED) ? 1 : 0; } @@ -1476,10 +1335,9 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) u32 acpiphp_get_address(struct acpiphp_slot *slot) { u32 address; - struct pci_bus *pci_bus = slot->bridge->pci_bus; - address = (pci_domain_nr(pci_bus) << 16) | - (pci_bus->number << 8) | + address = ((slot->bridge->seg) << 16) | + ((slot->bridge->bus) << 8) | slot->device; return address; diff --git a/trunk/drivers/pci/hotplug/acpiphp_pci.c b/trunk/drivers/pci/hotplug/acpiphp_pci.c new file mode 100644 index 000000000000..54d97c9d1dff --- /dev/null +++ b/trunk/drivers/pci/hotplug/acpiphp_pci.c @@ -0,0 +1,449 @@ +/* + * ACPI PCI HotPlug PCI configuration space management + * + * Copyright (C) 1995,2001 Compaq Computer Corporation + * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001,2002 IBM Corp. + * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com) + * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (C) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to + * + */ + +#include +#include + +#include +#include +#include +#include "../pci.h" +#include "pci_hotplug.h" +#include "acpiphp.h" + +#define MY_NAME "acpiphp_pci" + + +/* allocate mem/pmem/io resource to a new function */ +static int init_config_space (struct acpiphp_func *func) +{ + u32 bar, len; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + int count; + struct acpiphp_bridge *bridge; + struct pci_resource *res; + struct pci_bus *pbus; + int bus, device, function; + unsigned int devfn; + u16 tmp; + + bridge = func->slot->bridge; + pbus = bridge->pci_bus; + bus = bridge->bus; + device = func->slot->device; + function = func->function; + devfn = PCI_DEVFN(device, function); + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + pci_bus_write_config_dword(pbus, devfn, + address[count], 0xFFFFFFFF); + pci_bus_read_config_dword(pbus, devfn, address[count], &bar); + + if (!bar) /* This BAR is not implemented */ + continue; + + dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar); + + if (bar & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + + len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); + len = len & ~(len - 1); + + dbg("len in IO %x, BAR %d\n", len, count); + + spin_lock(&bridge->res_lock); + res = acpiphp_get_io_resource(&bridge->io_head, len); + spin_unlock(&bridge->res_lock); + + if (!res) { + err("cannot allocate requested io for %02x:%02x.%d len %x\n", + bus, device, function, len); + return -1; + } + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)res->base); + res->next = func->io_head; + func->io_head = res; + + } else { + /* This is Memory */ + if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + + len = bar & 0xFFFFFFF0; + len = ~len + 1; + + dbg("len in PFMEM %x, BAR %d\n", len, count); + + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource(&bridge->p_mem_head, len); + spin_unlock(&bridge->res_lock); + + if (!res) { + err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", + bus, device, function, len); + return -1; + } + + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)res->base); + + if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ + dbg("inside the pfmem 64 case, count %d\n", count); + count += 1; + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)(res->base >> 32)); + } + + res->next = func->p_mem_head; + func->p_mem_head = res; + + } else { + /* regular memory */ + + len = bar & 0xFFFFFFF0; + len = ~len + 1; + + dbg("len in MEM %x, BAR %d\n", len, count); + + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource(&bridge->mem_head, len); + spin_unlock(&bridge->res_lock); + + if (!res) { + err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", + bus, device, function, len); + return -1; + } + + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)res->base); + + if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + dbg("inside mem 64 case, reg. mem, count %d\n", count); + count += 1; + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)(res->base >> 32)); + } + + res->next = func->mem_head; + func->mem_head = res; + + } + } + } + + /* disable expansion rom */ + pci_bus_write_config_dword(pbus, devfn, PCI_ROM_ADDRESS, 0x00000000); + + /* set PCI parameters from _HPP */ + pci_bus_write_config_byte(pbus, devfn, PCI_CACHE_LINE_SIZE, + bridge->hpp.cache_line_size); + pci_bus_write_config_byte(pbus, devfn, PCI_LATENCY_TIMER, + bridge->hpp.latency_timer); + + pci_bus_read_config_word(pbus, devfn, PCI_COMMAND, &tmp); + if (bridge->hpp.enable_SERR) + tmp |= PCI_COMMAND_SERR; + if (bridge->hpp.enable_PERR) + tmp |= PCI_COMMAND_PARITY; + pci_bus_write_config_word(pbus, devfn, PCI_COMMAND, tmp); + + return 0; +} + +/* detect_used_resource - subtract resource under dev from bridge */ +static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev) +{ + int count; + + dbg("Device %s\n", pci_name(dev)); + + for (count = 0; count < DEVICE_COUNT_RESOURCE; count++) { + struct pci_resource *res; + struct pci_resource **head; + unsigned long base = dev->resource[count].start; + unsigned long len = dev->resource[count].end - base + 1; + unsigned long flags = dev->resource[count].flags; + + if (!flags) + continue; + + dbg("BAR[%d] 0x%lx - 0x%lx (0x%lx)\n", count, base, + base + len - 1, flags); + + if (flags & IORESOURCE_IO) { + head = &bridge->io_head; + } else if (flags & IORESOURCE_PREFETCH) { + head = &bridge->p_mem_head; + } else { + head = &bridge->mem_head; + } + + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource_with_base(head, base, len); + spin_unlock(&bridge->res_lock); + if (res) + kfree(res); + } + + return 0; +} + + +/** + * acpiphp_detect_pci_resource - detect resources under bridge + * @bridge: detect all resources already used under this bridge + * + * collect all resources already allocated for all devices under a bridge. + */ +int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge) +{ + struct list_head *l; + struct pci_dev *dev; + + list_for_each (l, &bridge->pci_bus->devices) { + dev = pci_dev_b(l); + detect_used_resource(bridge, dev); + } + + return 0; +} + + +/** + * acpiphp_init_slot_resource - gather resource usage information of a slot + * @slot: ACPI slot object to be checked, should have valid pci_dev member + * + * TBD: PCI-to-PCI bridge case + * use pci_dev->resource[] + */ +int acpiphp_init_func_resource (struct acpiphp_func *func) +{ + u64 base; + u32 bar, len; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + int count; + struct pci_resource *res; + struct pci_dev *dev; + + dev = func->pci_dev; + dbg("Hot-pluggable device %s\n", pci_name(dev)); + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + pci_read_config_dword(dev, address[count], &bar); + + if (!bar) /* This BAR is not implemented */ + continue; + + pci_write_config_dword(dev, address[count], 0xFFFFFFFF); + pci_read_config_dword(dev, address[count], &len); + + if (len & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + base = bar & 0xFFFFFFFC; + len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); + len = len & ~(len - 1); + + dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); + + res = acpiphp_make_resource(base, len); + if (!res) + goto no_memory; + + res->next = func->io_head; + func->io_head = res; + + } else { + /* This is Memory */ + base = bar & 0xFFFFFFF0; + if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + + len &= 0xFFFFFFF0; + len = ~len + 1; + + if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ + dbg("prefetch mem 64\n"); + count += 1; + } + dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1); + res = acpiphp_make_resource(base, len); + if (!res) + goto no_memory; + + res->next = func->p_mem_head; + func->p_mem_head = res; + + } else { + /* regular memory */ + + len &= 0xFFFFFFF0; + len = ~len + 1; + + if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + dbg("mem 64\n"); + count += 1; + } + dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1); + res = acpiphp_make_resource(base, len); + if (!res) + goto no_memory; + + res->next = func->mem_head; + func->mem_head = res; + + } + } + + pci_write_config_dword(dev, address[count], bar); + } +#if 1 + acpiphp_dump_func_resource(func); +#endif + + return 0; + + no_memory: + err("out of memory\n"); + acpiphp_free_resource(&func->io_head); + acpiphp_free_resource(&func->mem_head); + acpiphp_free_resource(&func->p_mem_head); + + return -1; +} + + +/** + * acpiphp_configure_slot - allocate PCI resources + * @slot: slot to be configured + * + * initializes a PCI functions on a device inserted + * into the slot + * + */ +int acpiphp_configure_slot (struct acpiphp_slot *slot) +{ + struct acpiphp_func *func; + struct list_head *l; + u8 hdr; + u32 dvid; + int retval = 0; + int is_multi = 0; + + pci_bus_read_config_byte(slot->bridge->pci_bus, + PCI_DEVFN(slot->device, 0), + PCI_HEADER_TYPE, &hdr); + + if (hdr & 0x80) + is_multi = 1; + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + if (is_multi || func->function == 0) { + pci_bus_read_config_dword(slot->bridge->pci_bus, + PCI_DEVFN(slot->device, + func->function), + PCI_VENDOR_ID, &dvid); + if (dvid != 0xffffffff) { + retval = init_config_space(func); + if (retval) + break; + } + } + } + + return retval; +} + +/** + * acpiphp_configure_function - configure PCI function + * @func: function to be configured + * + * initializes a PCI functions on a device inserted + * into the slot + * + */ +int acpiphp_configure_function (struct acpiphp_func *func) +{ + /* all handled by the pci core now */ + return 0; +} + +/** + * acpiphp_unconfigure_function - unconfigure PCI function + * @func: function to be unconfigured + * + */ +void acpiphp_unconfigure_function (struct acpiphp_func *func) +{ + struct acpiphp_bridge *bridge; + + /* if pci_dev is NULL, ignore it */ + if (!func->pci_dev) + return; + + pci_remove_bus_device(func->pci_dev); + + /* free all resources */ + bridge = func->slot->bridge; + + spin_lock(&bridge->res_lock); + acpiphp_move_resource(&func->io_head, &bridge->io_head); + acpiphp_move_resource(&func->mem_head, &bridge->mem_head); + acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head); + acpiphp_move_resource(&func->bus_head, &bridge->bus_head); + spin_unlock(&bridge->res_lock); +} diff --git a/trunk/drivers/pci/hotplug/acpiphp_res.c b/trunk/drivers/pci/hotplug/acpiphp_res.c new file mode 100644 index 000000000000..f54b1fa7b75a --- /dev/null +++ b/trunk/drivers/pci/hotplug/acpiphp_res.c @@ -0,0 +1,700 @@ +/* + * ACPI PCI HotPlug Utility functions + * + * Copyright (C) 1995,2001 Compaq Computer Corporation + * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001 IBM Corp. + * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com) + * Copyright (C) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Send feedback to , + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "pci_hotplug.h" +#include "acpiphp.h" + +#define MY_NAME "acpiphp_res" + + +/* + * sort_by_size - sort nodes by their length, smallest first + */ +static int sort_by_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return 1; + + if (!((*head)->next)) + return 0; + + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->length > (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length > current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } /* End of out_of_order loop */ + + return 0; +} + +#if 0 +/* + * sort_by_max_size - sort nodes by their length, largest first + */ +static int sort_by_max_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return 1; + + if (!((*head)->next)) + return 0; + + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->length < (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length < current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } /* End of out_of_order loop */ + + return 0; +} +#endif + +/** + * get_io_resource - get resource for I/O ports + * + * this function sorts the resource list by size and then + * returns the first node of "size" length that is not in the + * ISA aliasing window. If it finds a node larger than "size" + * it will split it up. + * + * size must be a power of two. + * + * difference from get_resource is handling of ISA aliasing space. + * + */ +struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u64 temp_qword; + + if (!(*head)) + return NULL; + + if (acpiphp_resource_sort_and_combine(head)) + return NULL; + + if (sort_by_size(head)) + return NULL; + + for (node = *head; node; node = node->next) { + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + /* this one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_qword = (node->base | (size-1)) + 1; + + /* Short circuit if adjusted size is too small */ + if ((node->length - (temp_qword - node->base)) < size) + continue; + + split_node = acpiphp_make_resource(node->base, temp_qword - node->base); + + if (!split_node) + return NULL; + + node->base = temp_qword; + node->length -= split_node->length; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of non-aligned base */ + + /* Don't need to check if too small since we already did */ + if (node->length > size) { + /* this one is longer than we need + so we'll make a new entry and split it up */ + split_node = acpiphp_make_resource(node->base + size, node->length - size); + + if (!split_node) + return NULL; + + node->length = size; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of too big on top end */ + + /* For IO make sure it's not in the ISA aliasing space */ + if ((node->base & 0x300L) && !(node->base & 0xfffff000)) + continue; + + /* If we got here, then it is the right size + Now take it out of the list */ + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + /* Stop looping */ + break; + } + + return node; +} + + +#if 0 +/** + * get_max_resource - get the largest resource + * + * Gets the largest node that is at least "size" big from the + * list pointed to by head. It aligns the node on top and bottom + * to "size" alignment before returning it. + */ +static struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *max; + struct pci_resource *temp; + struct pci_resource *split_node; + u64 temp_qword; + + if (!(*head)) + return NULL; + + if (acpiphp_resource_sort_and_combine(head)) + return NULL; + + if (sort_by_max_size(head)) + return NULL; + + for (max = *head;max; max = max->next) { + + /* If not big enough we could probably just bail, + instead we'll continue to the next. */ + if (max->length < size) + continue; + + if (max->base & (size - 1)) { + /* this one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_qword = (max->base | (size-1)) + 1; + + /* Short circuit if adjusted size is too small */ + if ((max->length - (temp_qword - max->base)) < size) + continue; + + split_node = acpiphp_make_resource(max->base, temp_qword - max->base); + + if (!split_node) + return NULL; + + max->base = temp_qword; + max->length -= split_node->length; + + /* Put it next in the list */ + split_node->next = max->next; + max->next = split_node; + } + + if ((max->base + max->length) & (size - 1)) { + /* this one isn't end aligned properly at the top + so we'll make a new entry and split it up */ + temp_qword = ((max->base + max->length) & ~(size - 1)); + + split_node = acpiphp_make_resource(temp_qword, + max->length + max->base - temp_qword); + + if (!split_node) + return NULL; + + max->length -= split_node->length; + + /* Put it in the list */ + split_node->next = max->next; + max->next = split_node; + } + + /* Make sure it didn't shrink too much when we aligned it */ + if (max->length < size) + continue; + + /* Now take it out of the list */ + temp = (struct pci_resource*) *head; + if (temp == max) { + *head = max->next; + } else { + while (temp && temp->next != max) { + temp = temp->next; + } + + temp->next = max->next; + } + + max->next = NULL; + return max; + } + + /* If we get here, we couldn't find one */ + return NULL; +} +#endif + +/** + * get_resource - get resource (mem, pfmem) + * + * this function sorts the resource list by size and then + * returns the first node of "size" length. If it finds a node + * larger than "size" it will split it up. + * + * size must be a power of two. + * + */ +struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u64 temp_qword; + + if (!(*head)) + return NULL; + + if (acpiphp_resource_sort_and_combine(head)) + return NULL; + + if (sort_by_size(head)) + return NULL; + + for (node = *head; node; node = node->next) { + dbg("%s: req_size =%x node=%p, base=%x, length=%x\n", + __FUNCTION__, size, node, (u32)node->base, node->length); + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + dbg("%s: not aligned\n", __FUNCTION__); + /* this one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_qword = (node->base | (size-1)) + 1; + + /* Short circuit if adjusted size is too small */ + if ((node->length - (temp_qword - node->base)) < size) + continue; + + split_node = acpiphp_make_resource(node->base, temp_qword - node->base); + + if (!split_node) + return NULL; + + node->base = temp_qword; + node->length -= split_node->length; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of non-aligned base */ + + /* Don't need to check if too small since we already did */ + if (node->length > size) { + dbg("%s: too big\n", __FUNCTION__); + /* this one is longer than we need + so we'll make a new entry and split it up */ + split_node = acpiphp_make_resource(node->base + size, node->length - size); + + if (!split_node) + return NULL; + + node->length = size; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of too big on top end */ + + dbg("%s: got one!!!\n", __FUNCTION__); + /* If we got here, then it is the right size + Now take it out of the list */ + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + /* Stop looping */ + break; + } + return node; +} + +/** + * get_resource_with_base - get resource with specific base address + * + * this function + * returns the first node of "size" length located at specified base address. + * If it finds a node larger than "size" it will split it up. + * + * size must be a power of two. + * + */ +struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u64 temp_qword; + + if (!(*head)) + return NULL; + + if (acpiphp_resource_sort_and_combine(head)) + return NULL; + + for (node = *head; node; node = node->next) { + dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n", + (u32)base, size, node, (u32)node->base, node->length); + if (node->base > base) + continue; + + if ((node->base + node->length) < (base + size)) + continue; + + if (node->base < base) { + dbg(": split 1\n"); + /* this one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_qword = base; + + /* Short circuit if adjusted size is too small */ + if ((node->length - (temp_qword - node->base)) < size) + continue; + + split_node = acpiphp_make_resource(node->base, temp_qword - node->base); + + if (!split_node) + return NULL; + + node->base = temp_qword; + node->length -= split_node->length; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } + + dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n", + (u32)base, size, node, (u32)node->base, node->length); + + /* Don't need to check if too small since we already did */ + if (node->length > size) { + dbg(": split 2\n"); + /* this one is longer than we need + so we'll make a new entry and split it up */ + split_node = acpiphp_make_resource(node->base + size, node->length - size); + + if (!split_node) + return NULL; + + node->length = size; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of too big on top end */ + + dbg(": got one!!!\n"); + /* If we got here, then it is the right size + Now take it out of the list */ + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + /* Stop looping */ + break; + } + return node; +} + + +/** + * acpiphp_resource_sort_and_combine + * + * Sorts all of the nodes in the list in ascending order by + * their base addresses. Also does garbage collection by + * combining adjacent nodes. + * + * returns 0 if success + */ +int acpiphp_resource_sort_and_combine (struct pci_resource **head) +{ + struct pci_resource *node1; + struct pci_resource *node2; + int out_of_order = 1; + + if (!(*head)) + return 1; + + dbg("*head->next = %p\n",(*head)->next); + + if (!(*head)->next) + return 0; /* only one item on the list, already sorted! */ + + dbg("*head->base = 0x%x\n",(u32)(*head)->base); + dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base); + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->base > (*head)->next->base)) { + node1 = *head; + (*head) = (*head)->next; + node1->next = (*head)->next; + (*head)->next = node1; + out_of_order++; + } + + node1 = (*head); + + while (node1->next && node1->next->next) { + if (node1->next->base > node1->next->next->base) { + out_of_order++; + node2 = node1->next; + node1->next = node1->next->next; + node1 = node1->next; + node2->next = node1->next; + node1->next = node2; + } else + node1 = node1->next; + } + } /* End of out_of_order loop */ + + node1 = *head; + + while (node1 && node1->next) { + if ((node1->base + node1->length) == node1->next->base) { + /* Combine */ + dbg("8..\n"); + node1->length += node1->next->length; + node2 = node1->next; + node1->next = node1->next->next; + kfree(node2); + } else + node1 = node1->next; + } + + return 0; +} + + +/** + * acpiphp_make_resource - make resource structure + * @base: base address of a resource + * @length: length of a resource + */ +struct pci_resource *acpiphp_make_resource (u64 base, u32 length) +{ + struct pci_resource *res; + + res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (res) { + memset(res, 0, sizeof(struct pci_resource)); + res->base = base; + res->length = length; + } + + return res; +} + + +/** + * acpiphp_move_resource - move linked resources from one to another + * @from: head of linked resource list + * @to: head of linked resource list + */ +void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to) +{ + struct pci_resource *tmp; + + while (*from) { + tmp = (*from)->next; + (*from)->next = *to; + *to = *from; + *from = tmp; + } + + /* *from = NULL is guaranteed */ +} + + +/** + * acpiphp_free_resource - free all linked resources + * @res: head of linked resource list + */ +void acpiphp_free_resource (struct pci_resource **res) +{ + struct pci_resource *tmp; + + while (*res) { + tmp = (*res)->next; + kfree(*res); + *res = tmp; + } + + /* *res = NULL is guaranteed */ +} + + +/* debug support functions; will go away sometime :) */ +static void dump_resource(struct pci_resource *head) +{ + struct pci_resource *p; + int cnt; + + p = head; + cnt = 0; + + while (p) { + dbg("[%02d] %08x - %08x\n", + cnt++, (u32)p->base, (u32)p->base + p->length - 1); + p = p->next; + } +} + +void acpiphp_dump_resource(struct acpiphp_bridge *bridge) +{ + dbg("I/O resource:\n"); + dump_resource(bridge->io_head); + dbg("MEM resource:\n"); + dump_resource(bridge->mem_head); + dbg("PMEM resource:\n"); + dump_resource(bridge->p_mem_head); + dbg("BUS resource:\n"); + dump_resource(bridge->bus_head); +} + +void acpiphp_dump_func_resource(struct acpiphp_func *func) +{ + dbg("I/O resource:\n"); + dump_resource(func->io_head); + dbg("MEM resource:\n"); + dump_resource(func->mem_head); + dbg("PMEM resource:\n"); + dump_resource(func->p_mem_head); + dbg("BUS resource:\n"); + dump_resource(func->bus_head); +} diff --git a/trunk/drivers/pci/hotplug/cpqphp_core.c b/trunk/drivers/pci/hotplug/cpqphp_core.c index 8c6d3987d461..afbccfa5217d 100644 --- a/trunk/drivers/pci/hotplug/cpqphp_core.c +++ b/trunk/drivers/pci/hotplug/cpqphp_core.c @@ -60,7 +60,6 @@ static void __iomem *smbios_start; static void __iomem *cpqhp_rom_start; static int power_mode; static int debug; -static int initialized; #define DRIVER_VERSION "0.9.8" #define DRIVER_AUTHOR "Dan Zink , Greg Kroah-Hartman " @@ -1272,6 +1271,7 @@ static int one_time_init(void) { int loop; int retval = 0; + static int initialized = 0; if (initialized) return 0; @@ -1441,8 +1441,7 @@ static void __exit unload_cpqphpd(void) } // Stop the notification mechanism - if (initialized) - cpqhp_event_stop_thread(); + cpqhp_event_stop_thread(); //unmap the rom address if (cpqhp_rom_start) diff --git a/trunk/drivers/pci/msi.c b/trunk/drivers/pci/msi.c index b5ab9aa6ff7c..30206ac43c44 100644 --- a/trunk/drivers/pci/msi.c +++ b/trunk/drivers/pci/msi.c @@ -28,10 +28,10 @@ static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; static kmem_cache_t* msi_cachep; static int pci_msi_enable = 1; -static int last_alloc_vector; -static int nr_released_vectors; +static int last_alloc_vector = 0; +static int nr_released_vectors = 0; static int nr_reserved_vectors = NR_HP_RESERVED_VECTORS; -static int nr_msix_devices; +static int nr_msix_devices = 0; #ifndef CONFIG_X86_IO_APIC int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; @@ -170,31 +170,45 @@ static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector) return 0; /* never anything pending */ } -static unsigned int startup_msi_irq_w_maskbit(unsigned int vector) +static void release_msi(unsigned int vector); +static void shutdown_msi_irq(unsigned int vector) { - startup_msi_irq_wo_maskbit(vector); - unmask_MSI_irq(vector); - return 0; /* never anything pending */ + release_msi(vector); } -static void shutdown_msi_irq(unsigned int vector) +#define shutdown_msi_irq_wo_maskbit shutdown_msi_irq +static void enable_msi_irq_wo_maskbit(unsigned int vector) {} +static void disable_msi_irq_wo_maskbit(unsigned int vector) {} +static void ack_msi_irq_wo_maskbit(unsigned int vector) {} +static void end_msi_irq_wo_maskbit(unsigned int vector) +{ + move_msi(vector); + ack_APIC_irq(); +} + +static unsigned int startup_msi_irq_w_maskbit(unsigned int vector) { struct msi_desc *entry; unsigned long flags; spin_lock_irqsave(&msi_lock, flags); entry = msi_desc[vector]; - if (entry && entry->dev) - entry->msi_attrib.state = 0; /* Mark it not active */ + if (!entry || !entry->dev) { + spin_unlock_irqrestore(&msi_lock, flags); + return 0; + } + entry->msi_attrib.state = 1; /* Mark it active */ spin_unlock_irqrestore(&msi_lock, flags); -} -static void end_msi_irq_wo_maskbit(unsigned int vector) -{ - move_msi(vector); - ack_APIC_irq(); + unmask_MSI_irq(vector); + return 0; /* never anything pending */ } +#define shutdown_msi_irq_w_maskbit shutdown_msi_irq +#define enable_msi_irq_w_maskbit unmask_MSI_irq +#define disable_msi_irq_w_maskbit mask_MSI_irq +#define ack_msi_irq_w_maskbit mask_MSI_irq + static void end_msi_irq_w_maskbit(unsigned int vector) { move_msi(vector); @@ -202,10 +216,6 @@ static void end_msi_irq_w_maskbit(unsigned int vector) ack_APIC_irq(); } -static void do_nothing(unsigned int vector) -{ -} - /* * Interrupt Type for MSI-X PCI/PCI-X/PCI-Express Devices, * which implement the MSI-X Capability Structure. @@ -213,10 +223,10 @@ static void do_nothing(unsigned int vector) static struct hw_interrupt_type msix_irq_type = { .typename = "PCI-MSI-X", .startup = startup_msi_irq_w_maskbit, - .shutdown = shutdown_msi_irq, - .enable = unmask_MSI_irq, - .disable = mask_MSI_irq, - .ack = mask_MSI_irq, + .shutdown = shutdown_msi_irq_w_maskbit, + .enable = enable_msi_irq_w_maskbit, + .disable = disable_msi_irq_w_maskbit, + .ack = ack_msi_irq_w_maskbit, .end = end_msi_irq_w_maskbit, .set_affinity = set_msi_irq_affinity }; @@ -229,10 +239,10 @@ static struct hw_interrupt_type msix_irq_type = { static struct hw_interrupt_type msi_irq_w_maskbit_type = { .typename = "PCI-MSI", .startup = startup_msi_irq_w_maskbit, - .shutdown = shutdown_msi_irq, - .enable = unmask_MSI_irq, - .disable = mask_MSI_irq, - .ack = mask_MSI_irq, + .shutdown = shutdown_msi_irq_w_maskbit, + .enable = enable_msi_irq_w_maskbit, + .disable = disable_msi_irq_w_maskbit, + .ack = ack_msi_irq_w_maskbit, .end = end_msi_irq_w_maskbit, .set_affinity = set_msi_irq_affinity }; @@ -245,10 +255,10 @@ static struct hw_interrupt_type msi_irq_w_maskbit_type = { static struct hw_interrupt_type msi_irq_wo_maskbit_type = { .typename = "PCI-MSI", .startup = startup_msi_irq_wo_maskbit, - .shutdown = shutdown_msi_irq, - .enable = do_nothing, - .disable = do_nothing, - .ack = do_nothing, + .shutdown = shutdown_msi_irq_wo_maskbit, + .enable = enable_msi_irq_wo_maskbit, + .disable = disable_msi_irq_wo_maskbit, + .ack = ack_msi_irq_wo_maskbit, .end = end_msi_irq_wo_maskbit, .set_affinity = set_msi_irq_affinity }; @@ -397,7 +407,7 @@ static struct msi_desc* alloc_msi_entry(void) { struct msi_desc *entry; - entry = kmem_cache_alloc(msi_cachep, SLAB_KERNEL); + entry = (struct msi_desc*) kmem_cache_alloc(msi_cachep, SLAB_KERNEL); if (!entry) return NULL; @@ -786,6 +796,18 @@ void pci_disable_msi(struct pci_dev* dev) } } +static void release_msi(unsigned int vector) +{ + struct msi_desc *entry; + unsigned long flags; + + spin_lock_irqsave(&msi_lock, flags); + entry = msi_desc[vector]; + if (entry && entry->dev) + entry->msi_attrib.state = 0; /* Mark it not active */ + spin_unlock_irqrestore(&msi_lock, flags); +} + static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) { struct msi_desc *entry; @@ -902,7 +924,7 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec) /** * pci_enable_msix - configure device's MSI-X capability structure * @dev: pointer to the pci_dev data structure of MSI-X device function - * @entries: pointer to an array of MSI-X entries + * @data: pointer to an array of MSI-X entries * @nvec: number of MSI-X vectors requested for allocation by device driver * * Setup the MSI-X capability structure of device function with the number diff --git a/trunk/drivers/pci/msi.h b/trunk/drivers/pci/msi.h index 390f1851c0f1..bef21ae3cbd0 100644 --- a/trunk/drivers/pci/msi.h +++ b/trunk/drivers/pci/msi.h @@ -41,11 +41,11 @@ static inline void move_msi(int vector) {} #define PCI_MSIX_FLAGS_BIRMASK (7 << 0) #define PCI_MSIX_FLAGS_BITMASK (1 << 0) +#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0 +#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4 +#define PCI_MSIX_ENTRY_DATA_OFFSET 8 +#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET 12 #define PCI_MSIX_ENTRY_SIZE 16 -#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0 -#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4 -#define PCI_MSIX_ENTRY_DATA_OFFSET 8 -#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET 12 #define msi_control_reg(base) (base + PCI_MSI_FLAGS) #define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO) @@ -64,6 +64,7 @@ static inline void move_msi(int vector) {} #define msi_enable(control, num) multi_msi_enable(control, num); \ control |= PCI_MSI_FLAGS_ENABLE +#define msix_control_reg msi_control_reg #define msix_table_offset_reg(base) (base + 0x04) #define msix_pba_offset_reg(base) (base + 0x08) #define msix_enable(control) control |= PCI_MSIX_FLAGS_ENABLE diff --git a/trunk/drivers/pci/pci-sysfs.c b/trunk/drivers/pci/pci-sysfs.c index cc9d65388e62..a15f94072a6f 100644 --- a/trunk/drivers/pci/pci-sysfs.c +++ b/trunk/drivers/pci/pci-sysfs.c @@ -60,18 +60,15 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf) char * str = buf; int i; int max = 7; - u64 start, end; if (pci_dev->subordinate) max = DEVICE_COUNT_RESOURCE; for (i = 0; i < max; i++) { - struct resource *res = &pci_dev->resource[i]; - pci_resource_to_user(pci_dev, i, res, &start, &end); - str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n", - (unsigned long long)start, - (unsigned long long)end, - (unsigned long long)res->flags); + str += sprintf(str,"0x%016lx 0x%016lx 0x%016lx\n", + pci_resource_start(pci_dev,i), + pci_resource_end(pci_dev,i), + pci_resource_flags(pci_dev,i)); } return (str - buf); } @@ -316,21 +313,8 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, struct device, kobj)); struct resource *res = (struct resource *)attr->private; enum pci_mmap_state mmap_type; - u64 start, end; - int i; - for (i = 0; i < PCI_ROM_RESOURCE; i++) - if (res == &pdev->resource[i]) - break; - if (i >= PCI_ROM_RESOURCE) - return -ENODEV; - - /* pci_mmap_page_range() expects the same kind of entry as coming - * from /proc/bus/pci/ which is a "user visible" value. If this is - * different from the resource itself, arch will do necessary fixup. - */ - pci_resource_to_user(pdev, i, res, &start, &end); - vma->vm_pgoff += start >> PAGE_SHIFT; + vma->vm_pgoff += res->start >> PAGE_SHIFT; mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; return pci_mmap_page_range(pdev, vma, mmap_type, 0); diff --git a/trunk/drivers/pci/probe.c b/trunk/drivers/pci/probe.c index 6a0a82f0508b..fd48b201eb53 100644 --- a/trunk/drivers/pci/probe.c +++ b/trunk/drivers/pci/probe.c @@ -374,11 +374,8 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de struct pci_bus *child; child = pci_alloc_child_bus(parent, dev, busnr); - if (child) { - spin_lock(&pci_bus_lock); + if (child) list_add_tail(&child->node, &parent->children); - spin_unlock(&pci_bus_lock); - } return child; } @@ -414,7 +411,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max { struct pci_bus *child; int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); - u32 buses, i; + u32 buses; u16 bctl; pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); @@ -450,7 +447,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max return max; } - child = pci_add_new_bus(bus, dev, busnr); + child = pci_alloc_child_bus(bus, dev, busnr); if (!child) return max; child->primary = buses & 0xFF; @@ -473,11 +470,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max /* Clear errors */ pci_write_config_word(dev, PCI_STATUS, 0xffff); - /* Prevent assigning a bus number that already exists. - * This can happen when a bridge is hot-plugged */ - if (pci_find_bus(pci_domain_nr(bus), max+1)) - return max; - child = pci_add_new_bus(bus, dev, ++max); + child = pci_alloc_child_bus(bus, dev, ++max); buses = (buses & 0xff000000) | ((unsigned int)(child->primary) << 0) | ((unsigned int)(child->secondary) << 8) @@ -508,11 +501,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max * as cards with a PCI-to-PCI bridge can be * inserted later. */ - for (i=0; iglobal_list); - spin_lock(&pci_bus_lock); list_add_tail(&dev->bus_list, &bus->devices); - spin_unlock(&pci_bus_lock); return dev; } @@ -891,9 +878,7 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); goto err_out; } - spin_lock(&pci_bus_lock); list_add_tail(&b->node, &pci_root_buses); - spin_unlock(&pci_bus_lock); memset(dev, 0, sizeof(*dev)); dev->parent = parent; @@ -926,6 +911,8 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, b->subordinate = pci_scan_child_bus(b); + pci_bus_add_devices(b); + return b; sys_create_link_err: @@ -935,9 +922,7 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, class_dev_reg_err: device_unregister(dev); dev_reg_err: - spin_lock(&pci_bus_lock); list_del(&b->node); - spin_unlock(&pci_bus_lock); err_out: kfree(dev); kfree(b); diff --git a/trunk/drivers/pci/proc.c b/trunk/drivers/pci/proc.c index 7988fc8df3fd..e68bbfb1e7c3 100644 --- a/trunk/drivers/pci/proc.c +++ b/trunk/drivers/pci/proc.c @@ -355,20 +355,14 @@ static int show_device(struct seq_file *m, void *v) dev->device, dev->irq); /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */ - for (i=0; i<7; i++) { - u64 start, end; - pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); + for(i=0; i<7; i++) seq_printf(m, LONG_FORMAT, - ((unsigned long)start) | + dev->resource[i].start | (dev->resource[i].flags & PCI_REGION_FLAG_MASK)); - } - for (i=0; i<7; i++) { - u64 start, end; - pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); + for(i=0; i<7; i++) seq_printf(m, LONG_FORMAT, dev->resource[i].start < dev->resource[i].end ? - (unsigned long)(end - start) + 1 : 0); - } + dev->resource[i].end - dev->resource[i].start + 1 : 0); seq_putc(m, '\t'); if (drv) seq_printf(m, "%s", drv->name); diff --git a/trunk/drivers/pci/remove.c b/trunk/drivers/pci/remove.c index 27a294b6965d..96f077f9a659 100644 --- a/trunk/drivers/pci/remove.c +++ b/trunk/drivers/pci/remove.c @@ -18,21 +18,17 @@ static void pci_free_resources(struct pci_dev *dev) static void pci_destroy_dev(struct pci_dev *dev) { - if (!list_empty(&dev->global_list)) { - pci_proc_detach_device(dev); - pci_remove_sysfs_dev_files(dev); - device_unregister(&dev->dev); - spin_lock(&pci_bus_lock); - list_del(&dev->global_list); - dev->global_list.next = dev->global_list.prev = NULL; - spin_unlock(&pci_bus_lock); - } + pci_proc_detach_device(dev); + pci_remove_sysfs_dev_files(dev); + device_unregister(&dev->dev); /* Remove the device from the device lists, and prevent any further * list accesses from this device */ spin_lock(&pci_bus_lock); list_del(&dev->bus_list); + list_del(&dev->global_list); dev->bus_list.next = dev->bus_list.prev = NULL; + dev->global_list.next = dev->global_list.prev = NULL; spin_unlock(&pci_bus_lock); pci_free_resources(dev); diff --git a/trunk/drivers/pci/setup-bus.c b/trunk/drivers/pci/setup-bus.c index 6b628de948af..1ba84be0b4c0 100644 --- a/trunk/drivers/pci/setup-bus.c +++ b/trunk/drivers/pci/setup-bus.c @@ -72,10 +72,7 @@ pbus_assign_resources_sorted(struct pci_bus *bus) for (list = head.next; list;) { res = list->res; idx = res - &list->dev->resource[0]; - if (pci_assign_resource(list->dev, idx)) { - res->start = 0; - res->flags = 0; - } + pci_assign_resource(list->dev, idx); tmp = list; list = list->next; kfree(tmp); diff --git a/trunk/drivers/scsi/3w-9xxx.c b/trunk/drivers/scsi/3w-9xxx.c index bc6e4627c7a1..34dbc37a79d4 100644 --- a/trunk/drivers/scsi/3w-9xxx.c +++ b/trunk/drivers/scsi/3w-9xxx.c @@ -1916,9 +1916,9 @@ static void __twa_shutdown(TW_Device_Extension *tw_dev) } /* End __twa_shutdown() */ /* Wrapper for __twa_shutdown */ -static void twa_shutdown(struct pci_dev *pdev) +static void twa_shutdown(struct device *dev) { - struct Scsi_Host *host = pci_get_drvdata(pdev); + struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev)); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; __twa_shutdown(tw_dev); @@ -2140,7 +2140,9 @@ static struct pci_driver twa_driver = { .id_table = twa_pci_tbl, .probe = twa_probe, .remove = twa_remove, - .shutdown = twa_shutdown + .driver = { + .shutdown = twa_shutdown + } }; /* This function is called on driver initialization */ diff --git a/trunk/drivers/scsi/3w-xxxx.c b/trunk/drivers/scsi/3w-xxxx.c index 973c51fb0fe2..b6dc576da430 100644 --- a/trunk/drivers/scsi/3w-xxxx.c +++ b/trunk/drivers/scsi/3w-xxxx.c @@ -2264,9 +2264,9 @@ static void __tw_shutdown(TW_Device_Extension *tw_dev) } /* End __tw_shutdown() */ /* Wrapper for __tw_shutdown */ -static void tw_shutdown(struct pci_dev *pdev) +static void tw_shutdown(struct device *dev) { - struct Scsi_Host *host = pci_get_drvdata(pdev); + struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev)); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; __tw_shutdown(tw_dev); @@ -2451,7 +2451,9 @@ static struct pci_driver tw_driver = { .id_table = tw_pci_tbl, .probe = tw_probe, .remove = tw_remove, - .shutdown = tw_shutdown, + .driver = { + .shutdown = tw_shutdown + } }; /* This function is called on driver initialization */ diff --git a/trunk/drivers/scsi/ahci.c b/trunk/drivers/scsi/ahci.c index c5623694d10f..9a547ca9c864 100644 --- a/trunk/drivers/scsi/ahci.c +++ b/trunk/drivers/scsi/ahci.c @@ -304,19 +304,26 @@ static int ahci_port_start(struct ata_port *ap) struct device *dev = ap->host_set->dev; struct ahci_host_priv *hpriv = ap->host_set->private_data; struct ahci_port_priv *pp; + int rc; void *mem, *mmio = ap->host_set->mmio_base; void *port_mmio = ahci_port_base(mmio, ap->port_no); dma_addr_t mem_dma; + rc = ata_port_start(ap); + if (rc) + return rc; + pp = kmalloc(sizeof(*pp), GFP_KERNEL); - if (!pp) - return -ENOMEM; + if (!pp) { + rc = -ENOMEM; + goto err_out; + } memset(pp, 0, sizeof(*pp)); mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL); if (!mem) { - kfree(pp); - return -ENOMEM; + rc = -ENOMEM; + goto err_out_kfree; } memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); @@ -366,6 +373,12 @@ static int ahci_port_start(struct ata_port *ap) readl(port_mmio + PORT_CMD); /* flush */ return 0; + +err_out_kfree: + kfree(pp); +err_out: + ata_port_stop(ap); + return rc; } @@ -391,6 +404,7 @@ static void ahci_port_stop(struct ata_port *ap) dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, pp->cmd_slot, pp->cmd_slot_dma); kfree(pp); + ata_port_stop(ap); } static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) diff --git a/trunk/drivers/scsi/ipr.c b/trunk/drivers/scsi/ipr.c index babd48363402..80d022625c82 100644 --- a/trunk/drivers/scsi/ipr.c +++ b/trunk/drivers/scsi/ipr.c @@ -6012,7 +6012,7 @@ static int __devinit ipr_probe(struct pci_dev *pdev, /** * ipr_shutdown - Shutdown handler. - * @pdev: pci device struct + * @dev: device struct * * This function is invoked upon system shutdown/reboot. It will issue * an adapter shutdown to the adapter to flush the write cache. @@ -6020,9 +6020,9 @@ static int __devinit ipr_probe(struct pci_dev *pdev, * Return value: * none **/ -static void ipr_shutdown(struct pci_dev *pdev) +static void ipr_shutdown(struct device *dev) { - struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); + struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(to_pci_dev(dev)); unsigned long lock_flags = 0; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); @@ -6068,7 +6068,9 @@ static struct pci_driver ipr_driver = { .id_table = ipr_pci_table, .probe = ipr_probe, .remove = ipr_remove, - .shutdown = ipr_shutdown, + .driver = { + .shutdown = ipr_shutdown, + }, }; /** diff --git a/trunk/drivers/scsi/libata-core.c b/trunk/drivers/scsi/libata-core.c index cb535fa185b9..36b401fee1f1 100644 --- a/trunk/drivers/scsi/libata-core.c +++ b/trunk/drivers/scsi/libata-core.c @@ -1408,9 +1408,7 @@ void __sata_phy_reset(struct ata_port *ap) if (ap->flags & ATA_FLAG_SATA_RESET) { /* issue phy wake/reset */ scr_write_flush(ap, SCR_CONTROL, 0x301); - /* Couldn't find anything in SATA I/II specs, but - * AHCI-1.1 10.4.2 says at least 1 ms. */ - mdelay(1); + udelay(400); /* FIXME: a guess */ } scr_write_flush(ap, SCR_CONTROL, 0x300); /* phy wake/clear reset */ @@ -1922,7 +1920,6 @@ static const char * ata_dma_blacklist [] = { "HITACHI CDR-8335", "HITACHI CDR-8435", "Toshiba CD-ROM XM-6202B", - "TOSHIBA CD-ROM XM-1702BC", "CD-532E-A", "E-IDE CD-ROM CR-840", "CD-ROM Drive/F5A", @@ -1930,6 +1927,7 @@ static const char * ata_dma_blacklist [] = { "SAMSUNG CD-ROM SC-148C", "SAMSUNG CD-ROM SC", "SanDisk SDP3B-64", + "SAMSUNG CD-ROM SN-124", "ATAPI CD-ROM DRIVE 40X MAXIMUM", "_NEC DV5800A", }; diff --git a/trunk/drivers/scsi/megaraid.c b/trunk/drivers/scsi/megaraid.c index a70cdf31311c..ec81532eb845 100644 --- a/trunk/drivers/scsi/megaraid.c +++ b/trunk/drivers/scsi/megaraid.c @@ -5036,9 +5036,9 @@ megaraid_remove_one(struct pci_dev *pdev) } static void -megaraid_shutdown(struct pci_dev *pdev) +megaraid_shutdown(struct device *dev) { - struct Scsi_Host *host = pci_get_drvdata(pdev); + struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev)); adapter_t *adapter = (adapter_t *)host->hostdata; __megaraid_shutdown(adapter); @@ -5070,7 +5070,9 @@ static struct pci_driver megaraid_pci_driver = { .id_table = megaraid_pci_tbl, .probe = megaraid_probe_one, .remove = __devexit_p(megaraid_remove_one), - .shutdown = megaraid_shutdown, + .driver = { + .shutdown = megaraid_shutdown, + }, }; static int __init megaraid_init(void) diff --git a/trunk/include/acpi/acpi_bus.h b/trunk/include/acpi/acpi_bus.h index 9ad142476f33..c627bc408a6b 100644 --- a/trunk/include/acpi/acpi_bus.h +++ b/trunk/include/acpi/acpi_bus.h @@ -108,21 +108,6 @@ typedef int (*acpi_op_unbind) (struct acpi_device *device); typedef int (*acpi_op_match) (struct acpi_device *device, struct acpi_driver *driver); -struct acpi_bus_ops { - u32 acpi_op_add:1; - u32 acpi_op_remove:1; - u32 acpi_op_lock:1; - u32 acpi_op_start:1; - u32 acpi_op_stop:1; - u32 acpi_op_suspend:1; - u32 acpi_op_resume:1; - u32 acpi_op_scan:1; - u32 acpi_op_bind:1; - u32 acpi_op_unbind:1; - u32 acpi_op_match:1; - u32 reserved:21; -}; - struct acpi_device_ops { acpi_op_add add; acpi_op_remove remove; @@ -342,9 +327,9 @@ int acpi_bus_generate_event (struct acpi_device *device, u8 type, int data); int acpi_bus_receive_event (struct acpi_bus_event *event); int acpi_bus_register_driver (struct acpi_driver *driver); int acpi_bus_unregister_driver (struct acpi_driver *driver); +int acpi_bus_scan (struct acpi_device *start); int acpi_bus_add (struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type); -int acpi_bus_start (struct acpi_device *device); int acpi_match_ids (struct acpi_device *device, char *ids); diff --git a/trunk/include/acpi/acpi_drivers.h b/trunk/include/acpi/acpi_drivers.h index 4ec722d73381..c62e92ec43b2 100644 --- a/trunk/include/acpi/acpi_drivers.h +++ b/trunk/include/acpi/acpi_drivers.h @@ -68,7 +68,6 @@ void acpi_pci_irq_del_prt (int segment, int bus); struct pci_bus; -acpi_status acpi_get_pci_id (acpi_handle handle, struct acpi_pci_id *id); int acpi_pci_bind (struct acpi_device *device); int acpi_pci_unbind (struct acpi_device *device); int acpi_pci_bind_root (struct acpi_device *device, struct acpi_pci_id *id, struct pci_bus *bus); diff --git a/trunk/include/asm-alpha/pci.h b/trunk/include/asm-alpha/pci.h index b7806aa3785c..0c7b57bc043a 100644 --- a/trunk/include/asm-alpha/pci.h +++ b/trunk/include/asm-alpha/pci.h @@ -223,25 +223,6 @@ pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, /* Nothing to do. */ } -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - unsigned long cacheline_size; - u8 byte; - - pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte); - if (byte == 0) - cacheline_size = 1024; - else - cacheline_size = (int) byte * 4; - - *strat = PCI_DMA_BURST_BOUNDARY; - *strategy_parameter = cacheline_size; -} -#endif - /* TODO: integrate with include/asm-generic/pci.h ? */ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) { diff --git a/trunk/include/asm-arm/pci.h b/trunk/include/asm-arm/pci.h index e300646fe650..40ffaefbeb1a 100644 --- a/trunk/include/asm-arm/pci.h +++ b/trunk/include/asm-arm/pci.h @@ -42,16 +42,6 @@ static inline void pcibios_penalize_isa_irq(int irq) #define pci_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME) #define pci_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL)) -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - *strat = PCI_DMA_BURST_INFINITY; - *strategy_parameter = ~0UL; -} -#endif - #define HAVE_PCI_MMAP extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine); diff --git a/trunk/include/asm-frv/pci.h b/trunk/include/asm-frv/pci.h index b4efe5e3591a..a6a469231f62 100644 --- a/trunk/include/asm-frv/pci.h +++ b/trunk/include/asm-frv/pci.h @@ -57,16 +57,6 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, */ #define PCI_DMA_BUS_IS_PHYS (1) -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - *strat = PCI_DMA_BURST_INFINITY; - *strategy_parameter = ~0UL; -} -#endif - /* * These are pretty much arbitary with the CoMEM implementation. * We have the whole address space to ourselves. diff --git a/trunk/include/asm-i386/pci.h b/trunk/include/asm-i386/pci.h index 3561899eb826..fb749b85a739 100644 --- a/trunk/include/asm-i386/pci.h +++ b/trunk/include/asm-i386/pci.h @@ -99,16 +99,6 @@ static inline void pcibios_add_platform_entries(struct pci_dev *dev) { } -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - *strat = PCI_DMA_BURST_INFINITY; - *strategy_parameter = ~0UL; -} -#endif - #endif /* __KERNEL__ */ /* implement the pci_ DMA API in terms of the generic device dma_ one */ diff --git a/trunk/include/asm-ia64/iosapic.h b/trunk/include/asm-ia64/iosapic.h index 1093f35b3b90..38a7a72791cc 100644 --- a/trunk/include/asm-ia64/iosapic.h +++ b/trunk/include/asm-ia64/iosapic.h @@ -71,11 +71,8 @@ static inline void iosapic_eoi(char __iomem *iosapic, u32 vector) } extern void __init iosapic_system_init (int pcat_compat); -extern int __devinit iosapic_init (unsigned long address, +extern void __init iosapic_init (unsigned long address, unsigned int gsi_base); -#ifdef CONFIG_HOTPLUG -extern int iosapic_remove (unsigned int gsi_base); -#endif /* CONFIG_HOTPLUG */ extern int gsi_to_vector (unsigned int gsi); extern int gsi_to_irq (unsigned int gsi); extern void iosapic_enable_intr (unsigned int vector); @@ -97,14 +94,11 @@ extern unsigned int iosapic_version (char __iomem *addr); extern void iosapic_pci_fixup (int); #ifdef CONFIG_NUMA -extern void __devinit map_iosapic_to_node (unsigned int, int); +extern void __init map_iosapic_to_node (unsigned int, int); #endif #else #define iosapic_system_init(pcat_compat) do { } while (0) -#define iosapic_init(address,gsi_base) (-EINVAL) -#ifdef CONFIG_HOTPLUG -#define iosapic_remove(gsi_base) (-ENODEV) -#endif /* CONFIG_HOTPLUG */ +#define iosapic_init(address,gsi_base) do { } while (0) #define iosapic_register_intr(gsi,polarity,trigger) (gsi) #define iosapic_unregister_intr(irq) do { } while (0) #define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger) do { } while (0) diff --git a/trunk/include/asm-ia64/pci.h b/trunk/include/asm-ia64/pci.h index 0c4c5d801d3f..a8314ee4e7d2 100644 --- a/trunk/include/asm-ia64/pci.h +++ b/trunk/include/asm-ia64/pci.h @@ -82,25 +82,6 @@ extern int pcibios_prep_mwi (struct pci_dev *); #define sg_dma_len(sg) ((sg)->dma_length) #define sg_dma_address(sg) ((sg)->dma_address) -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - unsigned long cacheline_size; - u8 byte; - - pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte); - if (byte == 0) - cacheline_size = 1024; - else - cacheline_size = (int) byte * 4; - - *strat = PCI_DMA_BURST_MULTIPLE; - *strategy_parameter = cacheline_size; -} -#endif - #define HAVE_PCI_MMAP extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine); diff --git a/trunk/include/asm-mips/pci.h b/trunk/include/asm-mips/pci.h index 2d323b6e147d..c9c576b48556 100644 --- a/trunk/include/asm-mips/pci.h +++ b/trunk/include/asm-mips/pci.h @@ -130,16 +130,6 @@ extern void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, extern void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction); -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - *strat = PCI_DMA_BURST_INFINITY; - *strategy_parameter = ~0UL; -} -#endif - extern void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, struct resource *res); diff --git a/trunk/include/asm-parisc/pci.h b/trunk/include/asm-parisc/pci.h index ee741c150176..0763c2982fb0 100644 --- a/trunk/include/asm-parisc/pci.h +++ b/trunk/include/asm-parisc/pci.h @@ -230,25 +230,6 @@ extern inline void pcibios_register_hba(struct pci_hba_data *x) /* export the pci_ DMA API in terms of the dma_ one */ #include -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - unsigned long cacheline_size; - u8 byte; - - pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte); - if (byte == 0) - cacheline_size = 1024; - else - cacheline_size = (int) byte * 4; - - *strat = PCI_DMA_BURST_MULTIPLE; - *strategy_parameter = cacheline_size; -} -#endif - extern void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, struct resource *res); diff --git a/trunk/include/asm-ppc/pci.h b/trunk/include/asm-ppc/pci.h index db0a2a0ec74d..ce5ae6d048f5 100644 --- a/trunk/include/asm-ppc/pci.h +++ b/trunk/include/asm-ppc/pci.h @@ -69,16 +69,6 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr); #define pci_unmap_len(PTR, LEN_NAME) (0) #define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - *strat = PCI_DMA_BURST_INFINITY; - *strategy_parameter = ~0UL; -} -#endif - /* * At present there are very few 32-bit PPC machines that can have * memory above the 4GB point, and we don't support that. @@ -113,12 +103,6 @@ extern pgprot_t pci_phys_mem_access_prot(struct file *file, unsigned long size, pgprot_t prot); -#define HAVE_ARCH_PCI_RESOURCE_TO_USER -extern void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, - u64 *start, u64 *end); - - #endif /* __KERNEL__ */ #endif /* __PPC_PCI_H */ diff --git a/trunk/include/asm-ppc64/pci.h b/trunk/include/asm-ppc64/pci.h index d12dfce21e20..6cd593f660a0 100644 --- a/trunk/include/asm-ppc64/pci.h +++ b/trunk/include/asm-ppc64/pci.h @@ -78,25 +78,6 @@ static inline int pci_dac_dma_supported(struct pci_dev *hwdev,u64 mask) return 0; } -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - unsigned long cacheline_size; - u8 byte; - - pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte); - if (byte == 0) - cacheline_size = 1024; - else - cacheline_size = (int) byte * 4; - - *strat = PCI_DMA_BURST_MULTIPLE; - *strategy_parameter = cacheline_size; -} -#endif - extern int pci_domain_nr(struct pci_bus *bus); /* Decide whether to display the domain number in /proc */ @@ -155,13 +136,6 @@ extern pgprot_t pci_phys_mem_access_prot(struct file *file, unsigned long size, pgprot_t prot); -#ifdef CONFIG_PPC_MULTIPLATFORM -#define HAVE_ARCH_PCI_RESOURCE_TO_USER -extern void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, - u64 *start, u64 *end); -#endif /* CONFIG_PPC_MULTIPLATFORM */ - #endif /* __KERNEL__ */ diff --git a/trunk/include/asm-sh/pci.h b/trunk/include/asm-sh/pci.h index 26044889c770..9c3b63d0105e 100644 --- a/trunk/include/asm-sh/pci.h +++ b/trunk/include/asm-sh/pci.h @@ -96,16 +96,6 @@ static inline void pcibios_penalize_isa_irq(int irq) #define sg_dma_address(sg) (virt_to_bus((sg)->dma_address)) #define sg_dma_len(sg) ((sg)->length) -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - *strat = PCI_DMA_BURST_INFINITY; - *strategy_parameter = ~0UL; -} -#endif - /* Board-specific fixup routines. */ extern void pcibios_fixup(void); extern void pcibios_fixup_irqs(void); diff --git a/trunk/include/asm-sh64/pci.h b/trunk/include/asm-sh64/pci.h index c68870e02d91..8cc14e139750 100644 --- a/trunk/include/asm-sh64/pci.h +++ b/trunk/include/asm-sh64/pci.h @@ -86,16 +86,6 @@ static inline void pcibios_penalize_isa_irq(int irq) #define sg_dma_address(sg) ((sg)->dma_address) #define sg_dma_len(sg) ((sg)->length) -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - *strat = PCI_DMA_BURST_INFINITY; - *strategy_parameter = ~0UL; -} -#endif - /* Board-specific fixup routines. */ extern void pcibios_fixup(void); extern void pcibios_fixup_irqs(void); diff --git a/trunk/include/asm-sparc/pci.h b/trunk/include/asm-sparc/pci.h index 44bb38758c96..d200a25a7373 100644 --- a/trunk/include/asm-sparc/pci.h +++ b/trunk/include/asm-sparc/pci.h @@ -144,16 +144,6 @@ extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask) #define pci_dac_dma_supported(dev, mask) (0) -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - *strat = PCI_DMA_BURST_INFINITY; - *strategy_parameter = ~0UL; -} -#endif - static inline void pcibios_add_platform_entries(struct pci_dev *dev) { } diff --git a/trunk/include/asm-sparc64/pci.h b/trunk/include/asm-sparc64/pci.h index 84e41c1ef3f8..2a0c85cd1c11 100644 --- a/trunk/include/asm-sparc64/pci.h +++ b/trunk/include/asm-sparc64/pci.h @@ -220,25 +220,6 @@ static inline int pci_dma_mapping_error(dma_addr_t dma_addr) return (dma_addr == PCI_DMA_ERROR_CODE); } -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - unsigned long cacheline_size; - u8 byte; - - pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte); - if (byte == 0) - cacheline_size = 1024; - else - cacheline_size = (int) byte * 4; - - *strat = PCI_DMA_BURST_BOUNDARY; - *strategy_parameter = cacheline_size; -} -#endif - /* Return the index of the PCI controller for device PDEV. */ extern int pci_domain_nr(struct pci_bus *bus); diff --git a/trunk/include/asm-v850/pci.h b/trunk/include/asm-v850/pci.h index 8e79be0fe99d..e41941447b49 100644 --- a/trunk/include/asm-v850/pci.h +++ b/trunk/include/asm-v850/pci.h @@ -81,16 +81,6 @@ extern void pci_free_consistent (struct pci_dev *pdev, size_t size, void *cpu_addr, dma_addr_t dma_addr); -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - *strat = PCI_DMA_BURST_INFINITY; - *strategy_parameter = ~0UL; -} -#endif - static inline void pcibios_add_platform_entries(struct pci_dev *dev) { } diff --git a/trunk/include/asm-x86_64/pci.h b/trunk/include/asm-x86_64/pci.h index c1961db88fac..8712520ca47f 100644 --- a/trunk/include/asm-x86_64/pci.h +++ b/trunk/include/asm-x86_64/pci.h @@ -123,16 +123,6 @@ pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, flush_write_buffers(); } -#ifdef CONFIG_PCI -static inline void pci_dma_burst_advice(struct pci_dev *pdev, - enum pci_dma_burst_strategy *strat, - unsigned long *strategy_parameter) -{ - *strat = PCI_DMA_BURST_INFINITY; - *strategy_parameter = ~0UL; -} -#endif - #define HAVE_PCI_MMAP extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine); diff --git a/trunk/include/linux/acpi.h b/trunk/include/linux/acpi.h index ef8483673aa3..b123cc08773d 100644 --- a/trunk/include/linux/acpi.h +++ b/trunk/include/linux/acpi.h @@ -342,19 +342,11 @@ struct acpi_table_ecdt { /* 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]; + u32 base_address; + u32 base_reserved; } __attribute__ ((packed)); /* Table Handlers */ @@ -399,7 +391,6 @@ 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); @@ -416,13 +407,9 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu); int acpi_unmap_lsapic(int cpu); #endif /* CONFIG_ACPI_HOTPLUG_CPU */ -int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base); -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 int pci_mmcfg_config_num; +extern u32 pci_mmcfg_base_addr; extern int sbf_port ; diff --git a/trunk/include/linux/etherdevice.h b/trunk/include/linux/etherdevice.h index 8a2df4dfbc59..a1478258d002 100644 --- a/trunk/include/linux/etherdevice.h +++ b/trunk/include/linux/etherdevice.h @@ -65,7 +65,7 @@ static inline int is_zero_ether_addr(const u8 *addr) */ static inline int is_multicast_ether_addr(const u8 *addr) { - return ((addr[0] != 0xff) && (0x01 & addr[0])); + return addr[0] & 0x01; } /** diff --git a/trunk/include/linux/pci.h b/trunk/include/linux/pci.h index 66798b46f308..b5238bd18830 100644 --- a/trunk/include/linux/pci.h +++ b/trunk/include/linux/pci.h @@ -734,20 +734,16 @@ void pcibios_update_irq(struct pci_dev *, int irq); /* Generic PCI functions used internally */ extern struct pci_bus *pci_find_bus(int domain, int busnr); -void pci_bus_add_devices(struct pci_bus *bus); struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata); static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata) { - struct pci_bus *root_bus; - root_bus = pci_scan_bus_parented(NULL, bus, ops, sysdata); - if (root_bus) - pci_bus_add_devices(root_bus); - return root_bus; + return pci_scan_bus_parented(NULL, bus, ops, sysdata); } int pci_scan_slot(struct pci_bus *bus, int devfn); struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn); unsigned int pci_scan_child_bus(struct pci_bus *bus); void pci_bus_add_device(struct pci_dev *dev); +void pci_bus_add_devices(struct pci_bus *bus); void pci_name_device(struct pci_dev *dev); char *pci_class_name(u32 class); void pci_read_bridge_bases(struct pci_bus *child); @@ -874,15 +870,6 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass #define pci_pool_alloc(pool, flags, handle) dma_pool_alloc(pool, flags, handle) #define pci_pool_free(pool, vaddr, addr) dma_pool_free(pool, vaddr, addr) -enum pci_dma_burst_strategy { - PCI_DMA_BURST_INFINITY, /* make bursts as large as possible, - strategy_parameter is N/A */ - PCI_DMA_BURST_BOUNDARY, /* disconnect at every strategy_parameter - byte boundaries */ - PCI_DMA_BURST_MULTIPLE, /* disconnect at some multiple of - strategy_parameter byte boundaries */ -}; - #if defined(CONFIG_ISA) || defined(CONFIG_EISA) extern struct pci_dev *isa_bridge; #endif @@ -985,8 +972,6 @@ static inline int pci_proc_domain(struct pci_bus *bus) } #endif -#define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0) - #endif /* !CONFIG_PCI */ /* these helpers provide future and backwards compatibility @@ -1031,20 +1016,6 @@ static inline char *pci_name(struct pci_dev *pdev) #define pci_pretty_name(dev) "" #endif - -/* Some archs don't want to expose struct resource to userland as-is - * in sysfs and /proc - */ -#ifndef HAVE_ARCH_PCI_RESOURCE_TO_USER -static inline void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, u64 *start, u64 *end) -{ - *start = rsrc->start; - *end = rsrc->end; -} -#endif /* HAVE_ARCH_PCI_RESOURCE_TO_USER */ - - /* * The world is not perfect and supplies us with broken PCI devices. * For at least a part of these bugs we need a work-around, so both diff --git a/trunk/include/linux/pci_ids.h b/trunk/include/linux/pci_ids.h index c3ee1ae4545a..1e0bc6a8d653 100644 --- a/trunk/include/linux/pci_ids.h +++ b/trunk/include/linux/pci_ids.h @@ -62,8 +62,6 @@ #define PCI_BASE_CLASS_SYSTEM 0x08 #define PCI_CLASS_SYSTEM_PIC 0x0800 -#define PCI_CLASS_SYSTEM_PIC_IOAPIC 0x080010 -#define PCI_CLASS_SYSTEM_PIC_IOXAPIC 0x080020 #define PCI_CLASS_SYSTEM_DMA 0x0801 #define PCI_CLASS_SYSTEM_TIMER 0x0802 #define PCI_CLASS_SYSTEM_RTC 0x0803 diff --git a/trunk/include/net/ieee80211.h b/trunk/include/net/ieee80211.h index 151c4f203559..7fe57f957a51 100644 --- a/trunk/include/net/ieee80211.h +++ b/trunk/include/net/ieee80211.h @@ -94,8 +94,6 @@ struct eapol { u16 length; } __attribute__ ((packed)); -#define IEEE80211_1ADDR_LEN 10 -#define IEEE80211_2ADDR_LEN 16 #define IEEE80211_3ADDR_LEN 24 #define IEEE80211_4ADDR_LEN 30 #define IEEE80211_FCS_LEN 4 @@ -302,6 +300,23 @@ struct ieee80211_snap_hdr { #define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 +/* Information Element IDs */ +#define WLAN_EID_SSID 0 +#define WLAN_EID_SUPP_RATES 1 +#define WLAN_EID_FH_PARAMS 2 +#define WLAN_EID_DS_PARAMS 3 +#define WLAN_EID_CF_PARAMS 4 +#define WLAN_EID_TIM 5 +#define WLAN_EID_IBSS_PARAMS 6 +#define WLAN_EID_CHALLENGE 16 +#define WLAN_EID_RSN 48 +#define WLAN_EID_GENERIC 221 + +#define IEEE80211_MGMT_HDR_LEN 24 +#define IEEE80211_DATA_HDR3_LEN 24 +#define IEEE80211_DATA_HDR4_LEN 30 + + #define IEEE80211_STATMASK_SIGNAL (1<<0) #define IEEE80211_STATMASK_RSSI (1<<1) #define IEEE80211_STATMASK_NOISE (1<<2) @@ -426,8 +441,6 @@ struct ieee80211_stats { struct ieee80211_device; -#include "ieee80211_crypt.h" - #define SEC_KEY_1 (1<<0) #define SEC_KEY_2 (1<<1) #define SEC_KEY_3 (1<<2) @@ -475,6 +488,15 @@ Total: 28-2340 bytes */ +struct ieee80211_header_data { + u16 frame_ctl; + u16 duration_id; + u8 addr1[6]; + u8 addr2[6]; + u8 addr3[6]; + u16 seq_ctrl; +}; + #define BEACON_PROBE_SSID_ID_POSITION 12 /* Management Frame Information Element Types */ @@ -519,7 +541,7 @@ struct ieee80211_info_element { */ struct ieee80211_authentication { - struct ieee80211_hdr_3addr header; + struct ieee80211_header_data header; u16 algorithm; u16 transaction; u16 status; @@ -528,7 +550,7 @@ struct ieee80211_authentication { struct ieee80211_probe_response { - struct ieee80211_hdr_3addr header; + struct ieee80211_header_data header; u32 time_stamp[2]; u16 beacon_interval; u16 capability; @@ -626,6 +648,12 @@ enum ieee80211_state { #define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] +extern inline int is_broadcast_ether_addr(const u8 *addr) +{ + return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ + (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); +} + #define CFG_IEEE80211_RESERVE_FCS (1<<0) #define CFG_IEEE80211_COMPUTE_FCS (1<<1) @@ -759,21 +787,21 @@ extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mod extern inline int ieee80211_get_hdrlen(u16 fc) { - int hdrlen = IEEE80211_3ADDR_LEN; + int hdrlen = 24; switch (WLAN_FC_GET_TYPE(fc)) { case IEEE80211_FTYPE_DATA: if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) - hdrlen = IEEE80211_4ADDR_LEN; + hdrlen = 30; /* Addr4 */ break; case IEEE80211_FTYPE_CTL: switch (WLAN_FC_GET_STYPE(fc)) { case IEEE80211_STYPE_CTS: case IEEE80211_STYPE_ACK: - hdrlen = IEEE80211_1ADDR_LEN; + hdrlen = 10; break; default: - hdrlen = IEEE80211_2ADDR_LEN; + hdrlen = 16; break; } break; diff --git a/trunk/init/main.c b/trunk/init/main.c index b5e421e39ede..d324801729ba 100644 --- a/trunk/init/main.c +++ b/trunk/init/main.c @@ -383,13 +383,6 @@ static void noinline rest_init(void) numa_default_policy(); unlock_kernel(); preempt_enable_no_resched(); - - /* - * The boot idle thread must execute schedule() - * at least one to get things moving: - */ - schedule(); - cpu_idle(); } diff --git a/trunk/kernel/kexec.c b/trunk/kernel/kexec.c index cdd4dcd8fb63..7843548cf2d9 100644 --- a/trunk/kernel/kexec.c +++ b/trunk/kernel/kexec.c @@ -241,7 +241,7 @@ static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry, static int kimage_crash_alloc(struct kimage **rimage, unsigned long entry, unsigned long nr_segments, - struct kexec_segment __user *segments) + struct kexec_segment *segments) { int result; struct kimage *image; @@ -650,7 +650,7 @@ static kimage_entry_t *kimage_dst_used(struct kimage *image, } } - return NULL; + return 0; } static struct page *kimage_alloc_page(struct kimage *image, @@ -696,7 +696,7 @@ static struct page *kimage_alloc_page(struct kimage *image, /* Allocate a page, if we run out of memory give up */ page = kimage_alloc_pages(gfp_mask, 0); if (!page) - return NULL; + return 0; /* If the page cannot be used file it away */ if (page_to_pfn(page) > (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) { @@ -754,7 +754,7 @@ static int kimage_load_normal_segment(struct kimage *image, unsigned long maddr; unsigned long ubytes, mbytes; int result; - unsigned char __user *buf; + unsigned char *buf; result = 0; buf = segment->buf; @@ -818,7 +818,7 @@ static int kimage_load_crash_segment(struct kimage *image, unsigned long maddr; unsigned long ubytes, mbytes; int result; - unsigned char __user *buf; + unsigned char *buf; result = 0; buf = segment->buf; diff --git a/trunk/kernel/sched.c b/trunk/kernel/sched.c index 5f2182d42241..e2b0d3e4dd06 100644 --- a/trunk/kernel/sched.c +++ b/trunk/kernel/sched.c @@ -4166,14 +4166,6 @@ void show_state(void) read_unlock(&tasklist_lock); } -/** - * init_idle - set up an idle thread for a given CPU - * @idle: task in question - * @cpu: cpu the idle task belongs to - * - * NOTE: this function does not set the idle thread's NEED_RESCHED - * flag, to make booting more robust. - */ void __devinit init_idle(task_t *idle, int cpu) { runqueue_t *rq = cpu_rq(cpu); @@ -4191,6 +4183,7 @@ void __devinit init_idle(task_t *idle, int cpu) #if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW) idle->oncpu = 1; #endif + set_tsk_need_resched(idle); spin_unlock_irqrestore(&rq->lock, flags); /* Set the preempt count _outside_ the spinlocks! */