aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/DocBook/libata.tmpl96
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--arch/i386/kernel/acpi/boot.c57
-rw-r--r--arch/i386/pci/common.c8
-rw-r--r--arch/i386/pci/irq.c51
-rw-r--r--arch/i386/pci/legacy.c2
-rw-r--r--arch/i386/pci/mmconfig.c39
-rw-r--r--arch/i386/pci/numa.c2
-rw-r--r--arch/i386/pci/pci.h1
-rw-r--r--arch/ia64/kernel/acpi.c30
-rw-r--r--arch/ia64/kernel/iosapic.c134
-rw-r--r--arch/ia64/pci/pci.c38
-rw-r--r--arch/ppc/kernel/pci.c21
-rw-r--r--arch/ppc64/kernel/pci.c22
-rw-r--r--arch/x86_64/pci/mmconfig.c68
-rw-r--r--drivers/acpi/container.c2
-rw-r--r--drivers/acpi/pci_bind.c27
-rw-r--r--drivers/acpi/pci_root.c24
-rw-r--r--drivers/acpi/processor_core.c2
-rw-r--r--drivers/acpi/scan.c126
-rw-r--r--drivers/block/cciss.c1
-rw-r--r--drivers/block/ll_rw_blk.c9
-rw-r--r--drivers/char/moxa.c2
-rw-r--r--drivers/char/rio/rio_linux.c4
-rw-r--r--drivers/md/md.c1
-rw-r--r--drivers/message/fusion/mptfc.c4
-rw-r--r--drivers/message/fusion/mptscsih.c10
-rw-r--r--drivers/message/fusion/mptscsih.h2
-rw-r--r--drivers/message/fusion/mptspi.c4
-rwxr-xr-xdrivers/net/amd8111e.c8
-rw-r--r--drivers/net/at1700.c4
-rw-r--r--drivers/net/e100.c9
-rw-r--r--drivers/net/skge.c1710
-rw-r--r--drivers/net/skge.h586
-rw-r--r--drivers/net/smc91x.c2
-rw-r--r--drivers/net/smc91x.h13
-rw-r--r--drivers/net/via-rhine.c11
-rw-r--r--drivers/parisc/dino.c1
-rw-r--r--drivers/parisc/lba_pci.c2
-rw-r--r--drivers/pci/bus.c11
-rw-r--r--drivers/pci/hotplug/Makefile4
-rw-r--r--drivers/pci/hotplug/acpiphp.h47
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c9
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c882
-rw-r--r--drivers/pci/hotplug/acpiphp_pci.c449
-rw-r--r--drivers/pci/hotplug/acpiphp_res.c700
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c5
-rw-r--r--drivers/pci/msi.c88
-rw-r--r--drivers/pci/msi.h9
-rw-r--r--drivers/pci/pci-sysfs.c26
-rw-r--r--drivers/pci/probe.c29
-rw-r--r--drivers/pci/proc.c14
-rw-r--r--drivers/pci/remove.c14
-rw-r--r--drivers/pci/setup-bus.c5
-rw-r--r--drivers/scsi/3w-9xxx.c8
-rw-r--r--drivers/scsi/3w-xxxx.c8
-rw-r--r--drivers/scsi/ahci.c22
-rw-r--r--drivers/scsi/ipr.c10
-rw-r--r--drivers/scsi/libata-core.c6
-rw-r--r--drivers/scsi/megaraid.c8
-rw-r--r--include/acpi/acpi_bus.h17
-rw-r--r--include/acpi/acpi_drivers.h1
-rw-r--r--include/asm-alpha/pci.h19
-rw-r--r--include/asm-arm/pci.h10
-rw-r--r--include/asm-frv/pci.h10
-rw-r--r--include/asm-i386/pci.h10
-rw-r--r--include/asm-ia64/iosapic.h12
-rw-r--r--include/asm-ia64/pci.h19
-rw-r--r--include/asm-mips/pci.h10
-rw-r--r--include/asm-parisc/pci.h19
-rw-r--r--include/asm-ppc/pci.h16
-rw-r--r--include/asm-ppc64/pci.h26
-rw-r--r--include/asm-sh/pci.h10
-rw-r--r--include/asm-sh64/pci.h10
-rw-r--r--include/asm-sparc/pci.h10
-rw-r--r--include/asm-sparc64/pci.h19
-rw-r--r--include/asm-v850/pci.h10
-rw-r--r--include/asm-x86_64/pci.h10
-rw-r--r--include/linux/acpi.h19
-rw-r--r--include/linux/etherdevice.h2
-rw-r--r--include/linux/pci.h33
-rw-r--r--include/linux/pci_ids.h2
-rw-r--r--include/net/ieee80211.h48
-rw-r--r--init/main.c7
-rw-r--r--kernel/kexec.c10
-rw-r--r--kernel/sched.c9
86 files changed, 2585 insertions, 3274 deletions
diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
index 6df1dfd18b65..375ae760dc1e 100644
--- a/Documentation/DocBook/libata.tmpl
+++ b/Documentation/DocBook/libata.tmpl
@@ -84,6 +84,14 @@ 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.
+ </para>
+ <para>
+ Called from ata_bus_probe() on a failed probe.
+ Called from ata_bus_reset() on a failed bus reset.
+ Called from ata_scsi_release().
</para>
</sect2>
@@ -98,6 +106,13 @@ 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.
</para>
+ <para>
+ Called by ata_device_add() after ata_dev_identify() determines
+ a device is present.
+ </para>
+ <para>
+ This entry may be specified as NULL in ata_port_operations.
+ </para>
</sect2>
@@ -135,6 +150,8 @@ 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.
</para>
</sect2>
@@ -147,6 +164,8 @@ void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
<para>
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.
</para>
</sect2>
@@ -161,6 +180,10 @@ 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.
</para>
+ <para>
+ This hook may be specified as NULL, in which case libata will
+ assume that atapi dma can be supported.
+ </para>
</sect2>
@@ -175,6 +198,14 @@ 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.
+ </para>
+ <para>
+ 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.
</para>
</sect2>
@@ -188,7 +219,13 @@ 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.
+ meaning on FIS-based devices.
+ </para>
+ <para>
+ 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().
</para>
</sect2>
@@ -204,6 +241,8 @@ 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.
</para>
</sect2>
@@ -227,6 +266,25 @@ PCI IDE DMA Status register.
These hooks are typically either no-ops, or simply not implemented, in
FIS-based drivers.
</para>
+ <para>
+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.
+ </para>
+ <para>
+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.
+ </para>
+ <para>
+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.
+ </para>
+ <para>
+Many legacy IDE drivers use ata_bmdma_status() as the bmdma_status() hook.
+ </para>
</sect2>
@@ -250,6 +308,10 @@ 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.
</para>
+ <para>
+ ata_qc_issue_prot() calls ->tf_load(), ->bmdma_setup(), and
+ ->bmdma_start() as necessary to initiate a transfer.
+ </para>
</sect2>
@@ -279,6 +341,21 @@ void (*irq_clear) (struct ata_port *);
before the interrupt handler is registered, to be sure hardware
is quiet.
</para>
+ <para>
+ The second argument, dev_instance, should be cast to a pointer
+ to struct ata_host_set.
+ </para>
+ <para>
+ 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).
+ </para>
+ <para>
+ 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.
+ </para>
</sect2>
@@ -292,6 +369,7 @@ void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
<para>
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.
</para>
</sect2>
@@ -307,17 +385,29 @@ 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.
+ tasks. Some drivers also use this entry point as a chance to
+ allocate driver-private memory for ap->private_data.
+ </para>
+ <para>
+ 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.
</para>
<para>
->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.
+ actively being used. Many drivers also free driver-private
+ data from port at this time.
+ </para>
+ <para>
+ Many drivers use ata_port_stop() as this hook, which frees the
+ PRD table.
</para>
<para>
->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.
</para>
</sect2>
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 89cd417651e0..0f71251f12b9 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1030,6 +1030,10 @@ 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/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index 9f63ae0f404b..b7808a89d945 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -159,9 +159,15 @@ char *__acpi_map_table(unsigned long phys, unsigned long size)
#endif
#ifdef CONFIG_PCI_MMCONFIG
-static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
+/* 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)
{
struct acpi_table_mcfg *mcfg;
+ unsigned long i;
+ int config_size;
if (!phys_addr || !size)
return -EINVAL;
@@ -172,18 +178,38 @@ static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
return -ENODEV;
}
- if (mcfg->base_reserved) {
- printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n");
+ /* 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");
return -ENODEV;
}
- pci_mmcfg_base_addr = mcfg->base_address;
+ 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;
+ }
+ }
return 0;
}
-#else
-#define acpi_parse_mcfg NULL
-#endif /* !CONFIG_PCI_MMCONFIG */
+#endif /* CONFIG_PCI_MMCONFIG */
#ifdef CONFIG_X86_LOCAL_APIC
static int __init
@@ -507,6 +533,22 @@ 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,
@@ -1123,7 +1165,6 @@ 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/arch/i386/pci/common.c b/arch/i386/pci/common.c
index 720975e1af50..87325263cd4f 100644
--- a/arch/i386/pci/common.c
+++ b/arch/i386/pci/common.c
@@ -25,7 +25,8 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
int pci_routeirq;
int pcibios_last_bus = -1;
-struct pci_bus *pci_root_bus = NULL;
+unsigned long pirq_table_addr;
+struct pci_bus *pci_root_bus;
struct pci_raw_ops *raw_pci_ops;
static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
@@ -133,7 +134,7 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
printk("PCI: Probing PCI hardware (bus %02x)\n", busnum);
- return pci_scan_bus(busnum, &pci_root_ops, NULL);
+ return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, NULL);
}
extern u8 pci_cache_line_size;
@@ -188,6 +189,9 @@ 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/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
index 83458f81e661..78ca1ecbb907 100644
--- a/arch/i386/pci/irq.c
+++ b/arch/i386/pci/irq.c
@@ -58,6 +58,35 @@ 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.
*/
@@ -65,23 +94,17 @@ 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 = (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; i<rt->size; i++)
- sum += addr[i];
- if (!sum) {
- DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
+ rt = pirq_check_routing_table(addr);
+ if (rt)
return rt;
- }
}
return NULL;
}
diff --git a/arch/i386/pci/legacy.c b/arch/i386/pci/legacy.c
index 1492e3753869..149a9588c256 100644
--- a/arch/i386/pci/legacy.c
+++ b/arch/i386/pci/legacy.c
@@ -45,6 +45,8 @@ 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/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
index 021a50aa51f4..60f0e7a1162a 100644
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -11,11 +11,9 @@
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/acpi.h>
#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 */
@@ -24,10 +22,31 @@ 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(int bus, int devfn)
+static inline void pci_exp_set_dev_base(unsigned int seg, int bus, int devfn)
{
- u32 dev_base = pci_mmcfg_base_addr | (bus << 20) | (devfn << 12);
+ u32 dev_base = get_base_addr(seg, bus) | (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);
@@ -44,7 +63,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
spin_lock_irqsave(&pci_config_lock, flags);
- pci_exp_set_dev_base(bus, devfn);
+ pci_exp_set_dev_base(seg, bus, devfn);
switch (len) {
case 1:
@@ -73,7 +92,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
spin_lock_irqsave(&pci_config_lock, flags);
- pci_exp_set_dev_base(bus, devfn);
+ pci_exp_set_dev_base(seg, bus, devfn);
switch (len) {
case 1:
@@ -101,7 +120,11 @@ static int __init pci_mmcfg_init(void)
{
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
goto out;
- if (!pci_mmcfg_base_addr)
+
+ 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))
goto out;
/* Kludge for now. Don't use mmconfig on AMD systems because
diff --git a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c
index 9e3695461899..adbe17a38f6f 100644
--- a/arch/i386/pci/numa.c
+++ b/arch/i386/pci/numa.c
@@ -115,6 +115,8 @@ 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/arch/i386/pci/pci.h b/arch/i386/pci/pci.h
index a8fc80ca69f3..a80f0f55ff51 100644
--- a/arch/i386/pci/pci.h
+++ b/arch/i386/pci/pci.h
@@ -27,6 +27,7 @@
#define PCI_ASSIGN_ALL_BUSSES 0x4000
extern unsigned int pci_probe;
+extern unsigned long pirq_table_addr;
/* pci-i386.c */
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 72dfd9e7de0f..cda06f88c66e 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -236,9 +236,7 @@ acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end)
if (BAD_MADT_ENTRY(iosapic, end))
return -EINVAL;
- iosapic_init(iosapic->address, iosapic->global_irq_base);
-
- return 0;
+ return iosapic_init(iosapic->address, iosapic->global_irq_base);
}
@@ -772,7 +770,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
#ifdef CONFIG_ACPI_NUMA
-acpi_status __init
+acpi_status __devinit
acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
{
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -825,4 +823,28 @@ 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/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index 88b014381df5..c170be095ccd 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -129,14 +129,13 @@ 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 int num_iosapic;
-
-static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */
+static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */
static int iosapic_kmalloc_ok;
static LIST_HEAD(free_rte_list);
@@ -149,7 +148,7 @@ find_iosapic (unsigned int gsi)
{
int i;
- for (i = 0; i < num_iosapic; i++) {
+ for (i = 0; i < NR_IOSAPICS; i++) {
if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
return i;
}
@@ -598,6 +597,7 @@ 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;
+ int irq, vector, index;
irq_desc_t *idesc;
u32 low32;
unsigned long trigger, polarity;
@@ -819,6 +819,9 @@ 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;
@@ -952,30 +955,86 @@ iosapic_system_init (int system_pcat_compat)
}
}
-void __init
+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
iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
{
- int num_rte;
+ int num_rte, err, index;
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);
- 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;
+ }
- /*
- * 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;
- iosapic_lists[num_iosapic].addr = addr;
- iosapic_lists[num_iosapic].gsi_base = gsi_base;
- iosapic_lists[num_iosapic].num_rte = num_rte;
+ index = iosapic_alloc();
+ iosapic_lists[index].addr = addr;
+ iosapic_lists[index].gsi_base = gsi_base;
+ iosapic_lists[index].num_rte = num_rte;
#ifdef CONFIG_NUMA
- iosapic_lists[num_iosapic].node = MAX_NUMNODES;
+ iosapic_lists[index].node = MAX_NUMNODES;
#endif
- num_iosapic++;
+ }
+ spin_unlock_irqrestore(&iosapic_lock, flags);
if ((gsi_base == 0) && pcat_compat) {
/*
@@ -986,10 +1045,43 @@ 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 __init
+void __devinit
map_iosapic_to_node(unsigned int gsi_base, int node)
{
int index;
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index e3fc4edea113..720a861f88be 100644
--- a/arch/ia64/pci/pci.c
+++ b/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(bus, &pci_root_ops, controller);
+ pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller);
if (pbus)
pcibios_setup_root_windows(pbus, controller);
@@ -373,6 +373,25 @@ 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; i<PCI_BUS_NUM_RESOURCES; i++) {
+ struct resource *busr = dev->bus->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;
@@ -386,7 +405,8 @@ 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], &region);
- pci_claim_resource(dev, i);
+ if ((is_valid_resource(dev, i)))
+ pci_claim_resource(dev, i);
}
}
@@ -398,6 +418,10 @@ 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);
@@ -418,18 +442,24 @@ 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; idx<6; idx++) {
+ for (idx=0; idx<PCI_NUM_RESOURCES; idx++) {
/* Only set up the desired resources. */
if (!(mask & (1 << idx)))
continue;
r = &dev->resource[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",
@@ -441,8 +471,6 @@ 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/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 6d7b92d72458..70cfb6ffd877 100644
--- a/arch/ppc/kernel/pci.c
+++ b/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 = (unsigned long)hose->io_base_virt;
+ io_offset = hose->io_base_virt - ___IO_BASE;
*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_BASE;
+ *offset += hose->io_base_phys - io_offset;
return rp;
}
@@ -1739,6 +1739,23 @@ 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/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
index 580676f87d23..ae6f579d3fa0 100644
--- a/arch/ppc64/kernel/pci.c
+++ b/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;
+ io_offset = (unsigned long)hose->io_base_virt - pci_io_base;
*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,4 +944,22 @@ 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/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index b693c232fd07..657e88aa0902 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -7,25 +7,50 @@
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/acpi.h>
#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 */
-char *pci_mmcfg_virt;
+struct mmcfg_virt {
+ struct acpi_table_mcfg_config *cfg;
+ char *virt;
+};
+static struct mmcfg_virt *pci_mmcfg_virt;
-static inline char *pci_dev_base(unsigned int bus, unsigned int devfn)
+static char *get_virt(unsigned int seg, int bus)
{
- return pci_mmcfg_virt + ((bus << 20) | (devfn << 12));
+ 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));
}
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(bus, devfn);
+ char *addr = pci_dev_base(seg, bus, devfn);
if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
return -EINVAL;
@@ -48,7 +73,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(bus,devfn);
+ char *addr = pci_dev_base(seg, bus, devfn);
if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
return -EINVAL;
@@ -75,9 +100,15 @@ 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;
- if (!pci_mmcfg_base_addr)
+
+ 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))
return 0;
/* Kludge for now. Don't use mmconfig on AMD systems because
@@ -88,13 +119,22 @@ static int __init pci_mmcfg_init(void)
return 0;
/* RED-PEN i386 doesn't do _nocache right now */
- pci_mmcfg_virt = ioremap_nocache(pci_mmcfg_base_addr, MMCONFIG_APER_SIZE);
- if (!pci_mmcfg_virt) {
- printk("PCI: Cannot map mmconfig aperture\n");
+ 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");
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/drivers/acpi/container.c b/drivers/acpi/container.c
index 5a0adbf8bc04..97013ddfa202 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -153,7 +153,7 @@ container_device_add(struct acpi_device **device, acpi_handle handle)
return_VALUE(-ENODEV);
}
- result = acpi_bus_scan(*device);
+ result = acpi_bus_start(*device);
return_VALUE(result);
}
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
index 5d19b39e9e2b..5148f3c10b5c 100644
--- a/drivers/acpi/pci_bind.c
+++ b/drivers/acpi/pci_bind.c
@@ -61,15 +61,14 @@ acpi_pci_data_handler (
/**
- * acpi_os_get_pci_id
+ * acpi_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_os_get_pci_id (
+acpi_get_pci_id (
acpi_handle handle,
struct acpi_pci_id *id)
{
@@ -78,7 +77,7 @@ acpi_os_get_pci_id (
struct acpi_device *device = NULL;
struct acpi_pci_data *data = NULL;
- ACPI_FUNCTION_TRACE("acpi_os_get_pci_id");
+ ACPI_FUNCTION_TRACE("acpi_get_pci_id");
if (!id)
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -92,7 +91,7 @@ acpi_os_get_pci_id (
}
status = acpi_get_data(handle, acpi_pci_data_handler, (void**) &data);
- if (ACPI_FAILURE(status) || !data || !data->dev) {
+ if (ACPI_FAILURE(status) || !data) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Invalid ACPI-PCI context for device %s\n",
acpi_device_bid(device)));
@@ -115,7 +114,7 @@ acpi_os_get_pci_id (
return_ACPI_STATUS(AE_OK);
}
-#endif /* ACPI_FUTURE_USAGE */
+EXPORT_SYMBOL(acpi_get_pci_id);
int
@@ -129,6 +128,8 @@ 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");
@@ -193,8 +194,20 @@ 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.
*/
- data->dev = pci_find_slot(data->id.bus, PCI_DEVFN(data->id.device, data->id.function));
+ 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;
+ }
+ }
+ }
if (!data->dev) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device %02x:%02x:%02x.%02x not present in PCI namespace\n",
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 7e6b8e3b2ed4..5d2f77fcd50c 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -46,6 +46,7 @@ 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,
@@ -54,6 +55,7 @@ static struct acpi_driver acpi_pci_root_driver = {
.ops = {
.add = acpi_pci_root_add,
.remove = acpi_pci_root_remove,
+ .start = acpi_pci_root_start,
},
};
@@ -169,6 +171,7 @@ 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);
@@ -298,12 +301,31 @@ acpi_pci_root_add (
root->id.bus);
end:
- if (result)
+ if (result) {
+ if (!list_empty(&root->node))
+ list_del(&root->node);
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/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index f4778747e889..76156ac91bd3 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -723,7 +723,7 @@ int acpi_processor_device_add(
return_VALUE(-ENODEV);
}
- acpi_bus_scan(*device);
+ acpi_bus_start(*device);
pr = acpi_driver_data(*device);
if (!pr)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index e85885593280..337d49b5564b 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -553,20 +553,29 @@ 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);
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n"));
-
- if (driver->ops.scan) {
- driver->ops.scan(device);
- }
-
- return_VALUE(0);
+ return_VALUE(result);
}
static int acpi_driver_attach(struct acpi_driver * drv)
@@ -586,6 +595,7 @@ 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",
@@ -1009,8 +1019,8 @@ acpi_bus_remove (
}
-int
-acpi_bus_add (
+static int
+acpi_add_single_object (
struct acpi_device **child,
struct acpi_device *parent,
acpi_handle handle,
@@ -1019,7 +1029,7 @@ acpi_bus_add (
int result = 0;
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_bus_add");
+ ACPI_FUNCTION_TRACE("acpi_add_single_object");
if (!child)
return_VALUE(-EINVAL);
@@ -1140,7 +1150,7 @@ acpi_bus_add (
*
* TBD: Assumes LDM provides driver hot-plug capability.
*/
- acpi_bus_find_driver(device);
+ result = acpi_bus_find_driver(device);
end:
if (!result)
@@ -1153,10 +1163,10 @@ end:
return_VALUE(result);
}
-EXPORT_SYMBOL(acpi_bus_add);
-int acpi_bus_scan (struct acpi_device *start)
+static int acpi_bus_scan (struct acpi_device *start,
+ struct acpi_bus_ops *ops)
{
acpi_status status = AE_OK;
struct acpi_device *parent = NULL;
@@ -1229,9 +1239,20 @@ int acpi_bus_scan (struct acpi_device *start)
continue;
}
- status = acpi_bus_add(&child, parent, chandle, type);
- if (ACPI_FAILURE(status))
- 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;
+ }
/*
* If the device is present, enabled, and functioning then
@@ -1257,8 +1278,50 @@ 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,
@@ -1331,13 +1394,19 @@ acpi_bus_scan_fixed (
/*
* Enumerate all fixed-feature devices.
*/
- if (acpi_fadt.pwr_button == 0)
- result = acpi_bus_add(&device, acpi_root,
+ if (acpi_fadt.pwr_button == 0) {
+ result = acpi_add_single_object(&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_bus_add(&device, acpi_root,
+ if (acpi_fadt.sleep_button == 0) {
+ result = acpi_add_single_object(&device, acpi_root,
NULL, ACPI_BUS_TYPE_SLEEP_BUTTON);
+ if (!result)
+ result = acpi_start_single_object(device);
+ }
return_VALUE(result);
}
@@ -1346,6 +1415,7 @@ acpi_bus_scan_fixed (
static int __init acpi_scan_init(void)
{
int result;
+ struct acpi_bus_ops ops;
ACPI_FUNCTION_TRACE("acpi_scan_init");
@@ -1357,17 +1427,23 @@ static int __init acpi_scan_init(void)
/*
* Create the root device in the bus's device tree
*/
- result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT,
+ result = acpi_add_single_object(&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)
- result = acpi_bus_scan(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)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 653512b77570..3e9fb6e4a52a 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -786,7 +786,6 @@ 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/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 234fdcfbdf01..6c98cf042714 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -1912,6 +1912,15 @@ 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/drivers/char/moxa.c b/drivers/char/moxa.c
index 7c24fbe831f8..95f7046ff059 100644
--- a/drivers/char/moxa.c
+++ b/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_find_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL)
+ while ((p = pci_get_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL)
{
if (pci_enable_device(p))
continue;
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 7db3370f4972..d7d484024e2b 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/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_find_device (PCI_VENDOR_ID_SPECIALIX,
+ while ((pdev = pci_get_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_find_device (PCI_VENDOR_ID_SPECIALIX,
+ while ((pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX,
PCI_DEVICE_ID_SPECIALIX_RIO,
pdev))) {
if (pci_enable_device(pdev)) continue;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 3802f7a17f16..4a0c57db2b67 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -338,6 +338,7 @@ 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/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index d8d65397e06e..353deb25e397 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -364,9 +364,7 @@ static struct pci_driver mptfc_driver = {
.id_table = mptfc_pci_table,
.probe = mptfc_probe,
.remove = __devexit_p(mptscsih_remove),
- .driver = {
- .shutdown = mptscsih_shutdown,
- },
+ .shutdown = mptscsih_shutdown,
#ifdef CONFIG_PM
.suspend = mptscsih_suspend,
.resume = mptscsih_resume,
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index a0078ae5b9b8..4f973a49be4c 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/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 device *);
+void mptscsih_shutdown(struct pci_dev *);
#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->dev);
+ mptscsih_shutdown(pdev);
sz1=0;
@@ -1026,9 +1026,9 @@ mptscsih_remove(struct pci_dev *pdev)
*
*/
void
-mptscsih_shutdown(struct device * dev)
+mptscsih_shutdown(struct pci_dev *pdev)
{
- MPT_ADAPTER *ioc = pci_get_drvdata(to_pci_dev(dev));
+ MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
struct Scsi_Host *host = ioc->sh;
MPT_SCSI_HOST *hd;
@@ -1054,7 +1054,7 @@ mptscsih_shutdown(struct device * dev)
int
mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
{
- mptscsih_shutdown(&pdev->dev);
+ mptscsih_shutdown(pdev);
return mpt_suspend(pdev,state);
}
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index d73aec33e16a..5ea89bf0df19 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -82,7 +82,7 @@
#endif
extern void mptscsih_remove(struct pci_dev *);
-extern void mptscsih_shutdown(struct device *);
+extern void mptscsih_shutdown(struct pci_dev *);
#ifdef CONFIG_PM
extern int mptscsih_suspend(struct pci_dev *pdev, u32 state);
extern int mptscsih_resume(struct pci_dev *pdev);
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 5f9a61b85b3b..e0c0ee5bc966 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -419,9 +419,7 @@ static struct pci_driver mptspi_driver = {
.id_table = mptspi_pci_table,
.probe = mptspi_probe,
.remove = __devexit_p(mptscsih_remove),
- .driver = {
- .shutdown = mptscsih_shutdown,
- },
+ .shutdown = mptscsih_shutdown,
#ifdef CONFIG_PM
.suspend = mptscsih_suspend,
.resume = mptscsih_resume,
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index b7dd7260cafb..8618012df06a 100755
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -87,6 +87,7 @@ Revision History:
#include <linux/if_vlan.h>
#include <linux/ctype.h>
#include <linux/crc32.h>
+#include <linux/dma-mapping.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -2006,12 +2007,11 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
}
/* Initialize DMA */
- if(!pci_dma_supported(pdev, 0xffffffff)){
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) < 0) {
printk(KERN_ERR "amd8111e: DMA not supported,"
"exiting.\n");
- goto err_free_reg;
- } else
- pdev->dma_mask = 0xffffffff;
+ goto err_free_reg;
+ }
reg_addr = pci_resource_start(pdev, 0);
reg_len = pci_resource_len(pdev, 0);
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index b8ab2b6355eb..e613cc289749 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -34,10 +34,6 @@
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 <linux/config.h>
#include <linux/errno.h>
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 1e56c8eea35f..d0fa2448761d 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -2447,9 +2447,8 @@ static int e100_resume(struct pci_dev *pdev)
#endif
-static void e100_shutdown(struct device *dev)
+static void e100_shutdown(struct pci_dev *pdev)
{
- 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);
@@ -2470,11 +2469,7 @@ static struct pci_driver e100_driver = {
.suspend = e100_suspend,
.resume = e100_resume,
#endif
-
- .driver = {
- .shutdown = e100_shutdown,
- }
-
+ .shutdown = e100_shutdown,
};
static int __init e100_init_module(void)
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 30e8d589d167..3dbb1cb09ed8 100644
--- a/drivers/net/skge.c
+++ b/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, Stephen Hemminger <shemminger@osdl.org>
+ * Copyright (C) 2004, 2005 Stephen Hemminger <shemminger@osdl.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -42,19 +42,20 @@
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "0.6"
+#define DRV_VERSION "0.7"
#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 <shemminger@osdl.org>");
@@ -70,28 +71,17 @@ 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_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 },
+ { 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) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, skge_id_table);
@@ -99,19 +89,22 @@ 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 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 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 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.
@@ -154,7 +147,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 && chip_rev(hw) == 0)));
+ (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)));
}
static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -170,7 +163,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))
@@ -190,6 +183,36 @@ 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)
@@ -198,38 +221,13 @@ 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 {
- ecmd->supported = SUPPORTED_1000baseT_Full
- | SUPPORTED_FIBRE
- | SUPPORTED_Autoneg;
-
+ } else
ecmd->port = PORT_FIBRE;
- }
ecmd->advertising = skge->advertising;
ecmd->autoneg = skge->autoneg;
@@ -238,65 +236,57 @@ 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) {
- if (ecmd->advertising & skge_modes(hw))
- return -EINVAL;
+ ecmd->advertising = supported;
+ skge->duplex = -1;
+ skge->speed = -1;
} else {
+ u32 setting;
+
switch(ecmd->speed) {
case SPEED_1000:
- if (hw->chip_id == CHIP_ID_YUKON_FE)
+ if (ecmd->duplex == DUPLEX_FULL)
+ setting = SUPPORTED_1000baseT_Full;
+ else if (ecmd->duplex == DUPLEX_HALF)
+ setting = SUPPORTED_1000baseT_Half;
+ else
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 (iscopper(hw) || hw->chip_id == CHIP_ID_GENESIS)
+ if (ecmd->duplex == DUPLEX_FULL)
+ setting = SUPPORTED_10baseT_Full;
+ else if (ecmd->duplex == DUPLEX_HALF)
+ setting = SUPPORTED_10baseT_Half;
+ else
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)) {
@@ -393,7 +383,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,
@@ -511,14 +501,6 @@ 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)
{
@@ -540,9 +522,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;
@@ -559,8 +541,6 @@ 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 */
}
@@ -643,30 +623,18 @@ 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, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_ON);
+ skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON);
skge_write8(hw, B0_LED, LED_STAT_ON);
- 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);
+ 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);
- 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);
- }
+ /* For Broadcom Phy only */
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
} else {
- skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
- skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
+ 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) |
@@ -678,28 +646,17 @@ 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, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_OFF);
+ skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
skge_write8(hw, B0_LED, LED_STAT_OFF);
- skge_write32(hw, SKGEMAC_REG(port, RX_LED_VAL), 0);
- skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_T_OFF);
+ skge_write32(hw, SK_REG(port, RX_LED_VAL), 0);
+ skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_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);
- }
+ /* Broadcom only */
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
} else {
- skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
- skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
+ 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) |
@@ -730,7 +687,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 */
@@ -763,8 +720,6 @@ 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,
@@ -793,6 +748,7 @@ 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;
@@ -806,24 +762,23 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base)
return 0;
}
-/* Setup buffer for receiving */
-static inline int skge_rx_alloc(struct skge_port *skge,
- struct skge_element *e)
+static struct sk_buff *skge_rx_alloc(struct net_device *dev, unsigned int size)
{
- unsigned long bufsize = skge->netdev->mtu + ETH_HLEN; /* VLAN? */
- struct skge_rx_desc *rd = e->desc;
- struct sk_buff *skb;
- u64 map;
+ struct sk_buff *skb = dev_alloc_skb(size);
- 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;
+ if (likely(skb)) {
+ skb->dev = dev;
+ skb_reserve(skb, NET_IP_ALIGN);
}
+ return skb;
+}
- skb->dev = skge->netdev;
- skb_reserve(skb, NET_IP_ALIGN);
+/* 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;
map = pci_map_single(skge->hw->pdev, skb->data, bufsize,
PCI_DMA_FROMDEVICE);
@@ -841,55 +796,69 @@ static inline int skge_rx_alloc(struct skge_port *skge,
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;
}
-/* Free all unused buffers in receive ring, assumes receiver stopped */
+/* 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 */
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;
- for (e = ring->to_clean; e != ring->to_use; e = e->next) {
+ e = ring->start;
+ do {
struct skge_rx_desc *rd = e->desc;
rd->control = 0;
-
- 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;
+ 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);
}
+
/* Allocate buffers for receive ring
- * 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
+ * For receive: to_clean is next received frame.
*/
static int skge_rx_fill(struct skge_port *skge)
{
struct skge_ring *ring = &skge->rx_ring;
struct skge_element *e;
- int ret = 0;
+ unsigned int bufsize = skge->rx_buf_size;
- for (e = ring->to_use; e->next != ring->to_clean; e = e->next) {
- if (skge_rx_alloc(skge, e)) {
- ret = 1;
- break;
- }
+ e = ring->start;
+ do {
+ struct sk_buff *skb = skge_rx_alloc(skge->netdev, bufsize);
- }
- ring->to_use = e;
+ if (!skb)
+ return -ENOMEM;
+
+ skge_rx_setup(skge, e, skb, bufsize);
+ } while ( (e = e->next) != ring->start);
- return ret;
+ ring->to_clean = ring->start;
+ return 0;
}
static void skge_link_up(struct skge_port *skge)
@@ -919,50 +888,50 @@ static void skge_link_down(struct skge_port *skge)
printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name);
}
-static u16 skge_xm_phy_read(struct skge_hw *hw, int port, u16 reg)
+static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg)
{
int i;
u16 v;
- 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;
- }
+ xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
+ v = 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 = skge_xm_read16(hw, port, XM_PHY_DATA);
+ /* 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 = xm_read16(hw, port, XM_PHY_DATA);
+
return v;
}
-static void skge_xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
{
int i;
- skge_xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
+ xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
for (i = 0; i < PHY_RETRIES; i++) {
- if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
+ if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
goto ready;
- cpu_relax();
+ udelay(1);
}
printk(KERN_WARNING PFX "%s: phy write failed to come ready\n",
hw->dev[port]->name);
ready:
- skge_xm_write16(hw, port, XM_PHY_DATA, val);
+ xm_write16(hw, port, XM_PHY_DATA, val);
for (i = 0; i < PHY_RETRIES; i++) {
udelay(1);
- if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
+ if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
return;
}
printk(KERN_WARNING PFX "%s: phy write timed out\n",
@@ -999,34 +968,112 @@ static void genesis_init(struct skge_hw *hw)
static void genesis_reset(struct skge_hw *hw, int port)
{
- int i;
- u64 zero = 0;
+ const u8 zero[8] = { 0 };
/* reset the statistics module */
- 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 */
+ 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 */
- /* disable all PHY IRQs */
- if (hw->phy_type == SK_PHY_BCOM)
- skge_xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
+ /* disable Broadcom PHY IRQ */
+ xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
- 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);
+ xm_outhash(hw, port, XM_HSM, zero);
}
-static void genesis_mac_init(struct skge_hw *hw, int port)
+/* 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 skge_port *skge = netdev_priv(hw->dev[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)
+{
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
int i;
- u32 r;
- u16 id1;
- u16 ctrl1, ctrl2, ctrl3, ctrl4, ctrl5;
+ u16 id1, r, ext, ctl;
/* magic workaround patterns for Broadcom */
static const struct {
@@ -1042,16 +1089,120 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
{ 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, 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, LNK_LED_REG), LINKLED_ON);
+ skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON);
- skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_START);
- skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_START);
+ skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
+ skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START);
/* Unreset the XMAC. */
- skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+ skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
/*
* Perform additional initialization for external PHYs,
@@ -1059,67 +1210,56 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
* GMII mode.
*/
spin_lock_bh(&hw->phy_lock);
- 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);
- }
+ /* 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;
- /*
- * Workaround BCOM Errata (#10523) for all BCom PHYs.
- * Disable Power Management after reset.
- */
- 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);
- }
+ skge_write32(hw, B2_GP_IO, r);
+ skge_read32(hw, B2_GP_IO);
+ spin_unlock_bh(&hw->phy_lock);
- /* Dummy read */
- skge_xm_read16(hw, port, XM_ISRC);
+ /* 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);
- r = skge_xm_read32(hw, port, XM_MODE);
- skge_xm_write32(hw, port, XM_MODE, r|XM_MD_CSA);
+ /* 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 = skge_xm_read16(hw, port, XM_RX_CMD);
- skge_xm_write16(hw, port, XM_RX_CMD, r | XM_RX_STRIP_FCS);
+ r = XM_RX_LENERR_OK | XM_RX_STRIP_FCS;
+ if (jumbo)
+ r |= XM_RX_BIG_PK_OK;
+
+ 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
+ */
+ r |= XM_RX_DIS_CEXT;
+ }
+ xm_write16(hw, port, XM_RX_CMD, r);
+
/* 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);
+ xm_write16(hw, port, XM_TX_CMD, XM_TX_AUTO_PAD);
+
+ /*
+ * 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);
/*
* Enable the reception of all error frames. This is is
@@ -1135,19 +1275,22 @@ 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.
*/
- 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);
+ xm_write32(hw, port, XM_MODE, XM_DEF_MODE);
- 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);
/*
- * Bump up the transmit threshold. This helps hold off transmit
- * underruns when we're blasting traffic from both ports at once.
+ * 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'.
*/
- skge_xm_write16(hw, port, XM_TX_THR, 512);
+ 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'.
+ */
+ xm_write32(hw, port, XM_TX_EV_MSK, XMT_DEF_MSK);
/* Configure MAC arbiter */
skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR);
@@ -1164,137 +1307,30 @@ 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, 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);
+ 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);
/* Configure Tx MAC FIFO */
- 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);
+ 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);
- if (hw->dev[port]->mtu > ETH_DATA_LEN) {
+ if (jumbo) {
/* Enable frame flushing if jumbo frames used */
- skge_write16(hw, SKGEMAC_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH);
+ skge_write16(hw, SK_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,
@@ -1304,33 +1340,30 @@ 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 !
*/
- skge_xm_write32(hw, port, XM_MODE,
- skge_xm_read32(hw, port, XM_MODE)|XM_MD_FTF);
+ xm_write32(hw, port, XM_MODE,
+ xm_read32(hw, port, XM_MODE)|XM_MD_FTF);
/* Reset the MAC */
- skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+ skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
/* For external PHYs there must be special handling */
- 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);
+ 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_xm_write16(hw, port, XM_MMU_CMD,
- skge_xm_read16(hw, port, XM_MMU_CMD)
+ xm_write16(hw, port, XM_MMU_CMD,
+ xm_read16(hw, port, XM_MMU_CMD)
& ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
- skge_xm_read16(hw, port, XM_MMU_CMD);
+ xm_read16(hw, port, XM_MMU_CMD);
}
@@ -1341,11 +1374,11 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data)
int i;
unsigned long timeout = jiffies + HZ;
- skge_xm_write16(hw, port,
+ xm_write16(hw, port,
XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC);
/* wait for update to complete */
- while (skge_xm_read16(hw, port, XM_STAT_CMD)
+ while (xm_read16(hw, port, XM_STAT_CMD)
& (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) {
if (time_after(jiffies, timeout))
break;
@@ -1353,68 +1386,60 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data)
}
/* special case for 64 bit octet counter */
- 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);
+ 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);
for (i = 2; i < ARRAY_SIZE(skge_stats); i++)
- data[i] = skge_xm_read32(hw, port, skge_stats[i].xmac_offset);
+ data[i] = 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 = 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);
- }
+ 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);
if (status & XM_IS_TXF_UR) {
- skge_xm_write32(hw, port, XM_MODE, XM_MD_FTF);
+ xm_write32(hw, port, XM_MODE, XM_MD_FTF);
++skge->net_stats.tx_fifo_errors;
}
if (status & XM_IS_RXF_OV) {
- skge_xm_write32(hw, port, XM_MODE, XM_MD_FRF);
+ xm_write32(hw, port, XM_MODE, XM_MD_FRF);
++skge->net_stats.rx_fifo_errors;
}
}
-static void skge_gm_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)
{
int i;
- skge_gma_write16(hw, port, GM_SMI_DATA, val);
- skge_gma_write16(hw, port, GM_SMI_CTRL,
+ gma_write16(hw, port, GM_SMI_DATA, val);
+ 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 (!(skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
+ if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
break;
}
}
-static u16 skge_gm_phy_read(struct skge_hw *hw, int port, u16 reg)
+static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg)
{
int i;
- skge_gma_write16(hw, port, GM_SMI_CTRL,
+ 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 (skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
+ if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
goto ready;
}
@@ -1422,24 +1447,7 @@ static u16 skge_gm_phy_read(struct skge_hw *hw, int port, u16 reg)
hw->dev[port]->name);
return 0;
ready:
- 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);
+ return gma_read16(hw, port, GM_SMI_DATA);
}
static void genesis_link_up(struct skge_port *skge)
@@ -1450,7 +1458,7 @@ static void genesis_link_up(struct skge_port *skge)
u32 mode, msk;
pr_debug("genesis_link_up\n");
- cmd = skge_xm_read16(hw, port, XM_MMU_CMD);
+ cmd = xm_read16(hw, port, XM_MMU_CMD);
/*
* enabling pause frame reception is required for 1000BT
@@ -1458,14 +1466,15 @@ 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;
- skge_xm_write16(hw, port, XM_MMU_CMD, cmd);
+ xm_write16(hw, port, XM_MMU_CMD, cmd);
- mode = skge_xm_read32(hw, port, XM_MODE);
+ mode = xm_read32(hw, port, XM_MODE);
if (skge->flow_control == FLOW_MODE_SYMMETRIC ||
skge->flow_control == FLOW_MODE_LOC_SEND) {
/*
@@ -1479,10 +1488,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 (!) */
- skge_xm_write16(hw, port, XM_MAC_PTIME, 0xffff);
+ xm_write16(hw, port, XM_MAC_PTIME, 0xffff);
mode |= XM_PAUSE_MODE;
- skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
+ skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
} else {
/*
* disable pause frame generation is required for 1000BT
@@ -1491,125 +1500,68 @@ static void genesis_link_up(struct skge_port *skge)
/* Disable Pause Mode in Mode Register */
mode &= ~XM_PAUSE_MODE;
- skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
+ skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
}
- skge_xm_write32(hw, port, XM_MODE, mode);
+ xm_write32(hw, port, XM_MODE, mode);
msk = XM_DEF_MSK;
- if (hw->phy_type != SK_PHY_XMAC)
- msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */
+ /* disable GP0 interrupt bit for external Phy */
+ msk |= XM_IS_INP_ASS;
- skge_xm_write16(hw, port, XM_IMSK, msk);
- skge_xm_read16(hw, port, XM_ISRC);
+ xm_write16(hw, port, XM_IMSK, msk);
+ xm_read16(hw, port, XM_ISRC);
/* get MMU Command Reg. */
- cmd = skge_xm_read16(hw, port, XM_MMU_CMD);
- if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL)
+ cmd = xm_read16(hw, port, XM_MMU_CMD);
+ if (skge->duplex == DUPLEX_FULL)
cmd |= XM_MMU_GMII_FD;
- 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);
- }
+ /*
+ * 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);
/* enable Rx/Tx */
- skge_xm_write16(hw, port, XM_MMU_CMD,
+ xm_write16(hw, port, XM_MMU_CMD,
cmd | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
skge_link_up(skge);
}
-static void genesis_bcom_intr(struct skge_port *skge)
+static inline void bcom_phy_intr(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
int port = skge->port;
- u16 stat = skge_xm_phy_read(hw, port, PHY_BCOM_INT_STAT);
+ 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);
- pr_debug("genesis_bcom intr stat=%x\n", stat);
+ if (isrc & PHY_B_IS_PSE)
+ printk(KERN_ERR PFX "%s: uncorrectable pair swap error\n",
+ hw->dev[port]->name);
/* Workaround BCom Errata:
* enable and disable loopback mode if "NO HCD" occurs.
*/
- 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,
+ 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,
ctrl | PHY_CT_LOOP);
- skge_xm_phy_write(hw, port, PHY_BCOM_CTRL,
+ xm_phy_write(hw, port, PHY_BCOM_CTRL,
ctrl & ~PHY_CT_LOOP);
}
- 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);
- }
-}
+ if (isrc & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+ bcom_check_link(hw, port);
-/* 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 */
@@ -1621,31 +1573,27 @@ static void yukon_init(struct skge_hw *hw, int port)
pr_debug("yukon_init\n");
if (skge->autoneg == AUTONEG_ENABLE) {
- u16 ectrl = skge_gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
+ u16 ectrl = 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);
- /* 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);
+ ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
- skge_gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl);
+ gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl);
}
- ctrl = skge_gm_phy_read(hw, port, PHY_MARV_CTRL);
+ ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
if (skge->autoneg == AUTONEG_DISABLE)
ctrl &= ~PHY_CT_ANE;
ctrl |= PHY_CT_RESET;
- skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+ gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
ctrl = 0;
ct1000 = 0;
- adv = PHY_SEL_TYPE;
+ adv = PHY_AN_CSMA;
if (skge->autoneg == AUTONEG_ENABLE) {
if (iscopper(hw)) {
@@ -1661,41 +1609,12 @@ 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;
-
- /* 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) */
+ } 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;
- }
- }
+ /* Set Flow-control capabilities */
+ adv |= phy_pause_map[skge->flow_control];
+
/* Restart Auto-negotiation */
ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
} else {
@@ -1717,36 +1636,23 @@ static void yukon_init(struct skge_hw *hw, int port)
ctrl |= PHY_CT_RESET;
}
- 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_1000T_CTRL, ct1000);
- skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
- skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+ gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
+ gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
/* Setup Phy LED's */
ledctrl = PHY_M_LED_PULS_DUR(PULS_170MS);
ledover = 0;
- 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;
+ 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;
- skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
+ 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) */
@@ -1754,25 +1660,25 @@ static void yukon_init(struct skge_hw *hw, int port)
}
if (ledover)
- skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
+ gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
/* Enable phy interrupt on autonegotiation complete (or link up) */
if (skge->autoneg == AUTONEG_ENABLE)
- skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
else
- skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
}
static void yukon_reset(struct skge_hw *hw, int port)
{
- 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);
+ 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_gma_write16(hw, port, GM_RX_CTRL,
- skge_gma_read16(hw, port, GM_RX_CTRL)
+ gma_write16(hw, port, GM_RX_CTRL,
+ gma_read16(hw, port, GM_RX_CTRL)
| GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
}
@@ -1785,17 +1691,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 &&
- chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+ hw->chip_rev == 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, SKGEMAC_REG(port, GPHY_CTRL), GPC_RST_SET);
- skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_RST_SET);
+ skge_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
+ skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET);
/* WA code for COMA mode -- clear PHY reset */
if (hw->chip_id == CHIP_ID_YUKON_LITE &&
- chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+ hw->chip_rev == CHIP_REV_YU_LITE_A3)
skge_write32(hw, B2_GP_IO,
(skge_read32(hw, B2_GP_IO) | GP_DIR_9)
& ~GP_IO_9);
@@ -1806,13 +1712,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, 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);
+ 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);
if (skge->autoneg == AUTONEG_DISABLE) {
reg = GM_GPCR_AU_ALL_DIS;
- skge_gma_write16(hw, port, GM_GP_CTRL,
- skge_gma_read16(hw, port, GM_GP_CTRL) | reg);
+ gma_write16(hw, port, GM_GP_CTRL,
+ gma_read16(hw, port, GM_GP_CTRL) | reg);
switch (skge->speed) {
case SPEED_1000:
@@ -1828,7 +1734,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, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+ skge_write32(hw, SK_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:
@@ -1836,7 +1742,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
}
- skge_gma_write16(hw, port, GM_GP_CTRL, reg);
+ gma_write16(hw, port, GM_GP_CTRL, reg);
skge_read16(hw, GMAC_IRQ_SRC);
spin_lock_bh(&hw->phy_lock);
@@ -1844,25 +1750,25 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
spin_unlock_bh(&hw->phy_lock);
/* MIB clear */
- reg = skge_gma_read16(hw, port, GM_PHY_ADDR);
- skge_gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR);
+ reg = gma_read16(hw, port, GM_PHY_ADDR);
+ gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR);
for (i = 0; i < GM_MIB_CNT_SIZE; i++)
- skge_gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i);
- skge_gma_write16(hw, port, GM_PHY_ADDR, reg);
+ gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i);
+ gma_write16(hw, port, GM_PHY_ADDR, reg);
/* transmit control */
- skge_gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF));
+ gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF));
/* receive control reg: unicast + multicast + no FCS */
- skge_gma_write16(hw, port, GM_RX_CTRL,
+ gma_write16(hw, port, GM_RX_CTRL,
GM_RXCR_UCF_ENA | GM_RXCR_CRC_DIS | GM_RXCR_MCF_ENA);
/* transmit flow control */
- skge_gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff);
+ gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff);
/* transmit parameter */
- skge_gma_write16(hw, port, GM_TX_PARAM,
+ 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));
@@ -1872,33 +1778,33 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
if (hw->dev[port]->mtu > 1500)
reg |= GM_SMOD_JUMBO_ENA;
- skge_gma_write16(hw, port, GM_SERIAL_MODE, reg);
+ gma_write16(hw, port, GM_SERIAL_MODE, reg);
/* physical address: used for pause frames */
- skge_gm_set_addr(hw, port, GM_SRC_ADDR_1L, addr);
+ gma_set_addr(hw, port, GM_SRC_ADDR_1L, addr);
/* virtual address for data */
- skge_gm_set_addr(hw, port, GM_SRC_ADDR_2L, addr);
+ gma_set_addr(hw, port, GM_SRC_ADDR_2L, addr);
/* enable interrupt mask for counter overflows */
- 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);
+ 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);
/* Initialize Mac Fifo */
/* Configure Rx MAC FIFO */
- skge_write16(hw, SKGEMAC_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK);
+ skge_write16(hw, SK_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 &&
- chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+ hw->chip_rev == CHIP_REV_YU_LITE_A3)
reg &= ~GMF_RX_F_FL_ON;
- 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);
+ 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);
/* Configure Tx MAC FIFO */
- 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);
+ 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);
}
static void yukon_stop(struct skge_port *skge)
@@ -1907,19 +1813,19 @@ static void yukon_stop(struct skge_port *skge)
int port = skge->port;
if (hw->chip_id == CHIP_ID_YUKON_LITE &&
- chip_rev(hw) == CHIP_REV_YU_LITE_A3) {
+ hw->chip_rev == CHIP_REV_YU_LITE_A3) {
skge_write32(hw, B2_GP_IO,
skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9);
}
- skge_gma_write16(hw, port, GM_GP_CTRL,
- skge_gma_read16(hw, port, GM_GP_CTRL)
+ gma_write16(hw, port, GM_GP_CTRL,
+ gma_read16(hw, port, GM_GP_CTRL)
& ~(GM_GPCR_RX_ENA|GM_GPCR_RX_ENA));
- skge_gma_read16(hw, port, GM_GP_CTRL);
+ gma_read16(hw, port, GM_GP_CTRL);
/* set GPHY Control reset */
- skge_gma_write32(hw, port, GPHY_CTRL, GPC_RST_SET);
- skge_gma_write32(hw, port, GMAC_CTRL, GMC_RST_SET);
+ gma_write32(hw, port, GPHY_CTRL, GPC_RST_SET);
+ gma_write32(hw, port, GMAC_CTRL, GMC_RST_SET);
}
static void yukon_get_stats(struct skge_port *skge, u64 *data)
@@ -1928,39 +1834,40 @@ static void yukon_get_stats(struct skge_port *skge, u64 *data)
int port = skge->port;
int i;
- 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);
+ 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);
for (i = 2; i < ARRAY_SIZE(skge_stats); i++)
- data[i] = skge_gma_read32(hw, port,
+ data[i] = gma_read32(hw, port,
skge_stats[i].gma_offset);
}
static void yukon_mac_intr(struct skge_hw *hw, int port)
{
- struct skge_port *skge = netdev_priv(hw->dev[port]);
- u8 status = skge_read8(hw, SKGEMAC_REG(port, GMAC_IRQ_SRC));
+ 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);
- pr_debug("yukon_intr status %x\n", status);
if (status & GM_IS_RX_FF_OR) {
++skge->net_stats.rx_fifo_errors;
- skge_gma_write8(hw, port, RX_GMF_CTRL_T, GMF_CLI_RX_FO);
+ 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;
- skge_gma_write8(hw, port, TX_GMF_CTRL_T, GMF_CLI_TX_FU);
+ gma_write8(hw, port, TX_GMF_CTRL_T, GMF_CLI_TX_FU);
}
}
static u16 yukon_speed(const struct skge_hw *hw, u16 aux)
{
- 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) {
+ switch (aux & PHY_M_PS_SPEED_MSK) {
case PHY_M_PS_SPEED_1000:
return SPEED_1000;
case PHY_M_PS_SPEED_100:
@@ -1981,15 +1888,15 @@ static void yukon_link_up(struct skge_port *skge)
/* Enable Transmit FIFO Underrun */
skge_write8(hw, GMAC_IRQ_MSK, GMAC_DEF_MSK);
- reg = skge_gma_read16(hw, port, GM_GP_CTRL);
+ reg = 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;
- skge_gma_write16(hw, port, GM_GP_CTRL, reg);
+ gma_write16(hw, port, GM_GP_CTRL, reg);
- skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
skge_link_up(skge);
}
@@ -1999,16 +1906,15 @@ static void yukon_link_down(struct skge_port *skge)
int port = skge->port;
pr_debug("yukon_link_down\n");
- 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_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)
& ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA));
- if (hw->chip_id != CHIP_ID_YUKON_FE &&
- skge->flow_control == FLOW_MODE_REM_SEND) {
+ if (skge->flow_control == FLOW_MODE_REM_SEND) {
/* restore Asymmetric Pause bit */
- skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
- skge_gm_phy_read(hw, port,
+ gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
+ gm_phy_read(hw, port,
PHY_MARV_AUNE_ADV)
| PHY_M_AN_ASP);
@@ -2027,20 +1933,21 @@ static void yukon_phy_intr(struct skge_port *skge)
const char *reason = NULL;
u16 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);
+ 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);
if (istatus & PHY_M_IS_AN_COMPL) {
- if (skge_gm_phy_read(hw, port, PHY_MARV_AUNE_LP)
+ if (gm_phy_read(hw, port, PHY_MARV_AUNE_LP)
& PHY_M_AN_RF) {
reason = "remote fault";
goto failed;
}
- 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)) {
+ if (gm_phy_read(hw, port, PHY_MARV_1000T_STAT) & PHY_B_1000S_MSF) {
reason = "master/slave fault";
goto failed;
}
@@ -2054,10 +1961,6 @@ 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:
@@ -2075,9 +1978,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, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+ skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
else
- skge_write8(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
+ skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
yukon_link_up(skge);
return;
}
@@ -2161,6 +2064,12 @@ 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;
@@ -2173,7 +2082,8 @@ static int skge_up(struct net_device *dev)
if ((err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma)))
goto free_pci_mem;
- if (skge_rx_fill(skge))
+ err = skge_rx_fill(skge);
+ if (err)
goto free_rx_ring;
if ((err = skge_ring_alloc(&skge->tx_ring, skge->mem + rx_size,
@@ -2182,6 +2092,10 @@ 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);
@@ -2189,7 +2103,7 @@ static int skge_up(struct net_device *dev)
yukon_mac_init(hw, port);
/* Configure RAMbuffers */
- chunk = hw->ram_size / (isdualport(hw) ? 4 : 2);
+ chunk = hw->ram_size / ((hw->ports + 1)*2);
ram_addr = hw->ram_offset + 2 * chunk * port;
skge_ramset(hw, rxqaddr[port], ram_addr, chunk);
@@ -2227,7 +2141,6 @@ 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);
@@ -2240,12 +2153,12 @@ static int skge_down(struct net_device *dev)
yukon_stop(skge);
/* Disable Force Sync bit and Enable Alloc bit */
- skge_write8(hw, SKGEMAC_REG(port, TXA_CTRL),
+ skge_write8(hw, SK_REG(port, TXA_CTRL),
TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
/* Stop Interval Timer and Limit Counter of Tx Arbiter */
- skge_write32(hw, SKGEMAC_REG(port, TXA_ITI_INI), 0L);
- skge_write32(hw, SKGEMAC_REG(port, TXA_LIM_INI), 0L);
+ skge_write32(hw, SK_REG(port, TXA_ITI_INI), 0L);
+ skge_write32(hw, SK_REG(port, TXA_LIM_INI), 0L);
/* Reset PCI FIFO */
skge_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_SET_RESET);
@@ -2260,13 +2173,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, 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);
+ 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);
} else {
- 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);
+ 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);
}
/* turn off led's */
@@ -2299,10 +2212,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);
@@ -2333,7 +2246,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
- && chip_rev(hw) == 0 && hw->chip_id == CHIP_ID_YUKON)
+ && hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON)
control = BMU_TCP_CHECK;
else
control = BMU_UDP_CHECK;
@@ -2394,6 +2307,7 @@ 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),
@@ -2438,16 +2352,17 @@ 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 (netif_running(dev)) {
+ if (running)
skge_down(dev);
+ dev->mtu = new_mtu;
+ if (running)
skge_up(dev);
- }
return err;
}
@@ -2462,7 +2377,9 @@ static void genesis_set_multicast(struct net_device *dev)
u32 mode;
u8 filter[8];
- mode = skge_xm_read32(hw, port, XM_MODE);
+ pr_debug("genesis_set_multicast flags=%x count=%d\n", dev->flags, dev->mc_count);
+
+ mode = xm_read32(hw, port, XM_MODE);
mode |= XM_MD_ENA_HASH;
if (dev->flags & IFF_PROMISC)
mode |= XM_MD_ENA_PROM;
@@ -2473,17 +2390,16 @@ 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 = crc32_le(~0, list->dmi_addr, ETH_ALEN);
- u8 bit = 63 - (crc & 63);
-
+ 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;
filter[bit/8] |= 1 << (bit%8);
}
}
- skge_xm_outhash(hw, port, XM_HSM, filter);
-
- skge_xm_write32(hw, port, XM_MODE, mode);
+ xm_write32(hw, port, XM_MODE, mode);
+ xm_outhash(hw, port, XM_HSM, filter);
}
static void yukon_set_multicast(struct net_device *dev)
@@ -2497,7 +2413,7 @@ static void yukon_set_multicast(struct net_device *dev)
memset(filter, 0, sizeof(filter));
- reg = skge_gma_read16(hw, port, GM_RX_CTRL);
+ reg = gma_read16(hw, port, GM_RX_CTRL);
reg |= GM_RXCR_UCF_ENA;
if (dev->flags & IFF_PROMISC) /* promiscious */
@@ -2510,23 +2426,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);
}
}
- skge_gma_write16(hw, port, GM_MC_ADDR_H1,
+ gma_write16(hw, port, GM_MC_ADDR_H1,
(u16)filter[0] | ((u16)filter[1] << 8));
- skge_gma_write16(hw, port, GM_MC_ADDR_H2,
+ gma_write16(hw, port, GM_MC_ADDR_H2,
(u16)filter[2] | ((u16)filter[3] << 8));
- skge_gma_write16(hw, port, GM_MC_ADDR_H3,
+ gma_write16(hw, port, GM_MC_ADDR_H3,
(u16)filter[4] | ((u16)filter[5] << 8));
- skge_gma_write16(hw, port, GM_MC_ADDR_H4,
+ gma_write16(hw, port, GM_MC_ADDR_H4,
(u16)filter[6] | ((u16)filter[7] << 8));
- skge_gma_write16(hw, port, GM_RX_CTRL, reg);
+ gma_write16(hw, port, GM_RX_CTRL, reg);
}
static inline int bad_phy_status(const struct skge_hw *hw, u32 status)
@@ -2545,28 +2461,76 @@ 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)
- || (control & BMU_BBC) > skge->netdev->mtu + VLAN_ETH_HLEN)
+ if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF))
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++;
+ 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;
+ }
+
+ 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);
@@ -2575,13 +2539,12 @@ 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 };
- for (e = ring->to_clean; e != ring->to_use && work_done < to_do;
- e = e->next) {
+ pr_debug("skge_poll\n");
+
+ for (e = ring->to_clean; work_done < to_do; e = e->next) {
struct skge_rx_desc *rd = e->desc;
- struct sk_buff *skb = e->skb;
+ struct sk_buff *skb;
u32 control, len, status;
rmb();
@@ -2590,19 +2553,12 @@ static int skge_poll(struct net_device *dev, int *budget)
break;
len = control & BMU_BBC;
- e->skb = NULL;
-
- pci_unmap_single(hw->pdev,
- pci_unmap_addr(e, mapaddr),
- pci_unmap_len(e, maplen),
- PCI_DMA_FROMDEVICE);
-
status = rd->status;
- if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
- || len > dev->mtu + VLAN_ETH_HLEN
- || bad_phy_status(hw, status)) {
+
+ if (unlikely((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
+ || bad_phy_status(hw, status))) {
skge_rx_error(skge, e - ring->start, control, status);
- dev_kfree_skb(skb);
+ skge_rx_reuse(e, skge->rx_buf_size);
continue;
}
@@ -2610,43 +2566,37 @@ 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_put(skb, len);
- skb->protocol = eth_type_trans(skb, dev);
-
- if (skge->rx_csum) {
- skb->csum = le16_to_cpu(rd->csum2);
- skb->ip_summed = CHECKSUM_HW;
- }
+ skb = skge_rx_get(skge, e, len);
+ if (likely(skb)) {
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, dev);
- dev->last_rx = jiffies;
- netif_receive_skb(skb);
+ dev->last_rx = jiffies;
+ netif_receive_skb(skb);
- ++work_done;
+ ++work_done;
+ } else
+ skge_rx_reuse(e, skge->rx_buf_size);
}
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);
- 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();
- }
+ *budget -= work_done;
+ dev->quota -= work_done;
- return !done;
+ if (work_done >= to_do)
+ return 1; /* not done */
+
+ 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;
}
static inline void skge_tx_intr(struct net_device *dev)
@@ -2657,7 +2607,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;
@@ -2690,12 +2640,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, SKGEMAC_REG(port, TX_MFF_CTRL1),
+ skge_write16(hw, SK_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, SKGEMAC_REG(port, TX_GMF_CTRL_T),
- (hw->chip_id == CHIP_ID_YUKON && chip_rev(hw) == 0)
+ skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T),
+ (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)
? GMF_CLI_TX_FC : GMF_CLI_TX_PE);
}
@@ -2703,16 +2653,16 @@ static void skge_pci_clear(struct skge_hw *hw)
{
u16 status;
- status = skge_read16(hw, SKGEPCI_REG(PCI_STATUS));
+ pci_read_config_word(hw->pdev, PCI_STATUS, &status);
skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- skge_write16(hw, SKGEPCI_REG(PCI_STATUS),
- status | PCI_STATUS_ERROR_BITS);
+ pci_write_config_word(hw->pdev, 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);
@@ -2726,9 +2676,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, SKGEMAC_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT);
+ skge_write16(hw, SK_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT);
if (hwstatus & (IS_NO_STAT_M2|IS_NO_TIST_M2))
- skge_write16(hw, SKGEMAC_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT);
+ skge_write16(hw, SK_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT);
} else {
/* Timestamp (unused) overflow */
if (hwstatus & IS_IRQ_TIST_OV)
@@ -2803,8 +2753,8 @@ static void skge_extirq(unsigned long data)
if (hw->chip_id != CHIP_ID_GENESIS)
yukon_phy_intr(skge);
- else if (hw->phy_type == SK_PHY_BCOM)
- genesis_bcom_intr(skge);
+ else
+ bcom_phy_intr(skge);
}
}
spin_unlock(&hw->phy_lock);
@@ -2824,19 +2774,14 @@ 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) && netif_rx_schedule_prep(hw->dev[0])) {
- status &= ~IS_R1_F;
+ if (status & IS_R1_F) {
hw->intr_mask &= ~IS_R1_F;
- skge_write32(hw, B0_IMSK, hw->intr_mask);
- __netif_rx_schedule(hw->dev[0]);
+ netif_rx_schedule(hw->dev[0]);
}
- if ((status & IS_R2_F) && netif_rx_schedule_prep(hw->dev[1])) {
- status &= ~IS_R2_F;
+ if (status & IS_R2_F) {
hw->intr_mask &= ~IS_R2_F;
- skge_write32(hw, B0_IMSK, hw->intr_mask);
- __netif_rx_schedule(hw->dev[1]);
+ netif_rx_schedule(hw->dev[1]);
}
if (status & IS_XA1_F)
@@ -2845,9 +2790,27 @@ 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);
@@ -2859,8 +2822,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
tasklet_schedule(&hw->ext_tasklet);
}
- if (status)
- skge_write32(hw, B0_IMSK, hw->intr_mask);
+ skge_write32(hw, B0_IMSK, hw->intr_mask);
return IRQ_HANDLED;
}
@@ -2904,9 +2866,6 @@ 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)
@@ -2930,8 +2889,8 @@ static const char *skge_board_name(const struct skge_hw *hw)
static int skge_reset(struct skge_hw *hw)
{
u16 ctst;
- u8 t8;
- int i, ports;
+ u8 t8, mac_cfg;
+ int i;
ctst = skge_read16(hw, B0_CTST);
@@ -2952,12 +2911,9 @@ 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;
@@ -2986,8 +2942,9 @@ static int skge_reset(struct skge_hw *hw)
return -EOPNOTSUPP;
}
- hw->mac_cfg = skge_read8(hw, B2_MAC_CFG);
- ports = isdualport(hw) ? 2 : 1;
+ 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;
/* read the adapters RAM size */
t8 = skge_read8(hw, B2_E_0);
@@ -3010,9 +2967,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 < 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);
+ 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);
}
}
@@ -3022,8 +2979,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 < ports; i++)
- skge_write8(hw, SKGEMAC_REG(i, TXA_CTRL), TXA_ENA_ARB);
+ for (i = 0; i < hw->ports; i++)
+ skge_write8(hw, SK_REG(i, TXA_CTRL), TXA_ENA_ARB);
/* Initialize ram interface */
skge_write16(hw, B3_RI_CTRL, RI_RST_CLR);
@@ -3050,16 +3007,14 @@ 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 | IS_PORT_1;
- if (isdualport(hw))
- hw->intr_mask |= IS_PORT_2;
+ hw->intr_mask = IS_HW_ERR | IS_EXT_REG;
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 < ports; i++) {
+ for (i = 0; i < hw->ports; i++) {
if (hw->chip_id == CHIP_ID_GENESIS)
genesis_reset(hw, i);
else
@@ -3071,7 +3026,8 @@ static int skge_reset(struct skge_hw *hw)
}
/* Initialize network device */
-static struct net_device *skge_devinit(struct skge_hw *hw, int port)
+static struct net_device *skge_devinit(struct skge_hw *hw, int port,
+ int highmem)
{
struct skge_port *skge;
struct net_device *dev = alloc_etherdev(sizeof(*skge));
@@ -3104,6 +3060,8 @@ 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;
@@ -3117,7 +3075,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_modes(hw);
+ skge->advertising = skge_supported_modes(hw);
hw->dev[port] = dev;
@@ -3125,10 +3083,6 @@ 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;
@@ -3232,14 +3186,11 @@ 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), chip_rev(hw));
+ skge_board_name(hw), hw->chip_rev);
- if ((dev = skge_devinit(hw, 0)) == NULL)
+ if ((dev = skge_devinit(hw, 0, using_dac)) == 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));
@@ -3248,10 +3199,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
skge_show_addr(dev);
- if (isdualport(hw) && (dev1 = skge_devinit(hw, 1))) {
- if (using_dac)
- dev1->features |= NETIF_F_HIGHDMA;
-
+ if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) {
if (register_netdev(dev1) == 0)
skge_show_addr(dev1);
else {
@@ -3288,7 +3236,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]))
@@ -3316,7 +3264,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) {
@@ -3349,11 +3297,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/drivers/net/skge.h b/drivers/net/skge.h
index 36c62b68fab4..14d0cc01fb9a 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -7,31 +7,6 @@
/* 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 | \
@@ -39,7 +14,6 @@ enum {
PCI_STATUS_REC_TARGET_ABORT | \
PCI_STATUS_PARITY)
-
enum csr_regs {
B0_RAP = 0x0000,
B0_CTST = 0x0004,
@@ -229,8 +203,11 @@ enum {
IS_XA2_F = 1<<1, /* Q_XA2 End of Frame */
IS_XA2_C = 1<<0, /* Q_XA2 Encoding Error */
- IS_PORT_1 = IS_XA1_F| IS_R1_F| IS_MAC1,
- IS_PORT_2 = IS_XA2_F| IS_R2_F| IS_MAC2,
+ 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,
};
@@ -288,14 +265,6 @@ 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 {
@@ -313,16 +282,6 @@ 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 */
@@ -348,30 +307,6 @@ 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 */
@@ -428,14 +363,6 @@ 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 {
@@ -452,19 +379,6 @@ 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 {
@@ -488,7 +402,7 @@ enum {
PA_ENA_TO_TX1 | PA_ENA_TO_TX2)
-/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() 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 */
@@ -511,7 +425,7 @@ enum {
/*
* Bank 4 - 5
*/
-/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() 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 */
@@ -537,7 +451,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 */
@@ -618,8 +532,7 @@ 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,
};
@@ -986,7 +899,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 */
@@ -1151,54 +1064,6 @@ 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 */
@@ -1253,8 +1118,29 @@ 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 */
@@ -1263,82 +1149,6 @@ 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 */
@@ -1418,6 +1228,16 @@ 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 */
@@ -1478,7 +1298,9 @@ 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_AN_PR | PHY_B_IS_LST_CHANGE))
+#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))
/* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */
enum {
@@ -1495,166 +1317,6 @@ 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 */
@@ -1718,7 +1380,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 */
@@ -2105,7 +1767,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 */
@@ -2127,7 +1789,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 */
@@ -2138,7 +1800,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 */
@@ -2146,7 +1808,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 */
@@ -2171,7 +1833,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
@@ -2186,7 +1848,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)
@@ -2195,7 +1857,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 */
@@ -2217,12 +1879,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,
};
@@ -2540,10 +2202,6 @@ 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 */
@@ -2662,8 +2320,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 | XM_MD_CAA)
+#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_STAT_CMD 16 bit r/w Statistics Command Register */
enum {
@@ -2793,28 +2451,20 @@ 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)
{
@@ -2827,7 +2477,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;
@@ -2853,8 +2503,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;
};
@@ -2863,7 +2513,6 @@ 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)
@@ -2892,114 +2541,87 @@ static inline void skge_write8(const struct skge_hw *hw, int reg, u8 val)
}
/* MAC Related Registers inside the device. */
-#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) \
+#define SK_REG(port,reg) (((port)<<7)+(reg))
+#define SK_XMAC_REG(port, reg) \
((BASE_XMAC_1 + (port) * (BASE_XMAC_2 - BASE_XMAC_1)) | (reg) << 1)
-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)
+static inline u32 xm_read32(const struct skge_hw *hw, int port, int reg)
{
- return skge_read16(hw, SKGEXM_REG(port,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;
}
-static inline u8 skge_xm_read8(const struct skge_hw *hw, int port, int reg)
+static inline u16 xm_read16(const struct skge_hw *hw, int port, int reg)
{
- return skge_read8(hw, SKGEXM_REG(port,reg));
+ return skge_read16(hw, SK_XMAC_REG(port,reg));
}
-static inline void skge_xm_write32(const struct skge_hw *hw, int port, int r, u32 v)
+static inline void xm_write32(const struct skge_hw *hw, int port, int r, u32 v)
{
- skge_write32(hw, SKGEXM_REG(port,r), v);
+ skge_write16(hw, SK_XMAC_REG(port,r), v & 0xffff);
+ skge_write16(hw, SK_XMAC_REG(port,r+2), v >> 16);
}
-static inline void skge_xm_write16(const struct skge_hw *hw, int port, int r, u16 v)
+static inline void xm_write16(const struct skge_hw *hw, int port, int r, u16 v)
{
- skge_write16(hw, SKGEXM_REG(port,r), v);
+ skge_write16(hw, SK_XMAC_REG(port,r), v);
}
-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,
+static inline void xm_outhash(const struct skge_hw *hw, int port, int reg,
const u8 *hash)
{
- 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));
+ 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));
}
-static inline void skge_xm_outaddr(const struct skge_hw *hw, int port, int reg,
+static inline void xm_outaddr(const struct skge_hw *hw, int port, int reg,
const u8 *addr)
{
- 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));
+ 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));
}
+#define SK_GMAC_REG(port,reg) \
+ (BASE_GMAC_1 + (port) * (BASE_GMAC_2-BASE_GMAC_1) + (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)
+static inline u16 gma_read16(const struct skge_hw *hw, int port, int reg)
{
- return skge_read16(hw, SKGEGMA_REG(port,reg));
+ return skge_read16(hw, SK_GMAC_REG(port,reg));
}
-static inline u32 skge_gma_read32(const struct skge_hw *hw, int port, int reg)
+static inline u32 gma_read32(const struct skge_hw *hw, int port, int reg)
{
- return (u32) skge_read16(hw, SKGEGMA_REG(port,reg))
- | ((u32)skge_read16(hw, SKGEGMA_REG(port,reg+4)) << 16);
+ return (u32) skge_read16(hw, SK_GMAC_REG(port,reg))
+ | ((u32)skge_read16(hw, SK_GMAC_REG(port,reg+4)) << 16);
}
-static inline u8 skge_gma_read8(const struct skge_hw *hw, int port, int reg)
+static inline void gma_write16(const struct skge_hw *hw, int port, int r, u16 v)
{
- return skge_read8(hw, SKGEGMA_REG(port,reg));
+ skge_write16(hw, SK_GMAC_REG(port,r), v);
}
-static inline void skge_gma_write16(const struct skge_hw *hw, int port, int r, u16 v)
+static inline void gma_write32(const struct skge_hw *hw, int port, int r, u32 v)
{
- skge_write16(hw, SKGEGMA_REG(port,r), v);
+ skge_write16(hw, SK_GMAC_REG(port, r), (u16) v);
+ skge_write32(hw, SK_GMAC_REG(port, r+4), (u16)(v >> 16));
}
-static inline void skge_gma_write32(const struct skge_hw *hw, int port, int r, u32 v)
+static inline void gma_write8(const struct skge_hw *hw, int port, int r, u8 v)
{
- skge_write16(hw, SKGEGMA_REG(port, r), (u16) v);
- skge_write32(hw, SKGEGMA_REG(port, r+4), (u16)(v >> 16));
+ skge_write8(hw, SK_GMAC_REG(port,r), v);
}
-static inline void skge_gma_write8(const struct skge_hw *hw, int port, int r, u8 v)
-{
- skge_write8(hw, SKGEGMA_REG(port,r), v);
-}
-
-static inline void skge_gm_set_addr(struct skge_hw *hw, int port, int reg,
+static inline void gma_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));
+ 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));
}
-
+
#endif
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index cfb9d3cdb04a..1438fdd20826 100644
--- a/drivers/net/smc91x.c
+++ b/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, IRQT_RISING);
+ set_irq_type(dev->irq, SMC_IRQ_TRIGGER_TYPE);
#ifdef SMC_USE_PXA_DMA
{
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index 946528e6b742..7089d86e857a 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -182,6 +182,16 @@ 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 <asm/mach-types.h>
+#include <asm/arch/cpu.h>
+
+#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
@@ -300,6 +310,9 @@ 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/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index be1c1047b9ba..eb0e7bd4dcf8 100644
--- a/drivers/net/via-rhine.c
+++ b/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 device *gdev);
+static void rhine_shutdown (struct pci_dev *pdev);
#define RHINE_WAIT_FOR(condition) do { \
int i=1024; \
@@ -1895,9 +1895,8 @@ static void __devexit rhine_remove_one(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
}
-static void rhine_shutdown (struct device *gendev)
+static void rhine_shutdown (struct pci_dev *pdev)
{
- 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;
@@ -1956,7 +1955,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->dev);
+ rhine_shutdown(pdev);
spin_unlock_irqrestore(&rp->lock, flags);
free_irq(dev->irq, dev);
@@ -2010,9 +2009,7 @@ static struct pci_driver rhine_driver = {
.suspend = rhine_suspend,
.resume = rhine_resume,
#endif /* CONFIG_PM */
- .driver = {
- .shutdown = rhine_shutdown,
- }
+ .shutdown = rhine_shutdown,
};
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index b0d2a73d1d47..2f2dbef2c3b7 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -993,6 +993,7 @@ 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/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index dc838804c0dd..7fdd80b7eb47 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1570,6 +1570,8 @@ 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/drivers/pci/bus.c b/drivers/pci/bus.c
index dbd33605cc10..fedae89d8f7d 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -121,10 +121,13 @@ 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 && 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) {
+ 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);
+ }
pci_bus_add_devices(dev->subordinate);
sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge");
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
index 93c120ddbd39..3e632ff8c717 100644
--- a/drivers/pci/hotplug/Makefile
+++ b/drivers/pci/hotplug/Makefile
@@ -36,9 +36,7 @@ ibmphp-objs := ibmphp_core.o \
ibmphp_hpc.o
acpiphp-objs := acpiphp_core.o \
- acpiphp_glue.o \
- acpiphp_pci.o \
- acpiphp_res.o
+ acpiphp_glue.o
rpaphp-objs := rpaphp_core.o \
rpaphp_pci.o \
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index d9499874c8a9..293603e1b7c3 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -7,6 +7,8 @@
* 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.
*
@@ -52,7 +54,6 @@
struct acpiphp_bridge;
struct acpiphp_slot;
-struct pci_resource;
/*
* struct slot - slot information for each *physical* slot
@@ -65,15 +66,6 @@ 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
@@ -101,10 +93,6 @@ 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) */
@@ -117,12 +105,6 @@ 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;
};
@@ -163,12 +145,6 @@ 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;
};
/**
@@ -243,25 +219,6 @@ 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/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index 4539e61a3dc1..60c4c38047a3 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -7,6 +7,8 @@
* 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.
*
@@ -53,8 +55,8 @@ int acpiphp_debug;
static int num_slots;
static struct acpiphp_attention_info *attention_info;
-#define DRIVER_VERSION "0.4"
-#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>"
+#define DRIVER_VERSION "0.5"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>, Matthew Wilcox <willy@hp.com>"
#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver"
MODULE_AUTHOR(DRIVER_AUTHOR);
@@ -281,8 +283,7 @@ 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
- * @busdev: pointer to struct pci_busdev (seg, bus, dev)
- *
+ * @value: pointer to struct pci_busdev (seg, bus, dev)
*/
static int get_address(struct hotplug_slot *hotplug_slot, u32 *value)
{
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index e7f41294f811..424e7de181ae 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -4,6 +4,10 @@
* 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.
*
@@ -26,6 +30,16 @@
*
*/
+/*
+ * 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 <linux/init.h>
#include <linux/module.h>
@@ -178,21 +192,18 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
bridge->nr_slots++;
- dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n",
- slot->bridge->bus, slot->device, slot->sun);
+ 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);
}
newfunc->slot = slot;
list_add_tail(&newfunc->sibling, &slot->funcs);
/* associate corresponding pci_dev */
- newfunc->pci_dev = pci_find_slot(bridge->bus,
+ newfunc->pci_dev = pci_get_slot(bridge->pci_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);
}
@@ -227,62 +238,6 @@ 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)
{
@@ -346,34 +301,29 @@ 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 */
- status = acpi_install_notify_handler(bridge->handle,
+ if (bridge->type != BRIDGE_TYPE_HOST) {
+ 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, int seg, int bus)
+static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus)
{
- acpi_status status;
struct acpiphp_bridge *bridge;
bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
@@ -384,52 +334,19 @@ static void add_host_bridge(acpi_handle *handle, int seg, int bus)
bridge->type = BRIDGE_TYPE_HOST;
bridge->handle = handle;
- bridge->seg = seg;
- bridge->bus = bus;
- bridge->pci_bus = pci_find_bus(seg, bus);
+ bridge->pci_bus = pci_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, int seg, int bus, int dev, int fn)
+static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev)
{
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) {
@@ -441,133 +358,22 @@ static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int f
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_bus = bridge->pci_dev->subordinate;
+ bridge->pci_dev = pci_dev_get(pci_dev);
+ bridge->pci_bus = pci_dev->subordinate;
if (!bridge->pci_bus) {
err("This is not a PCI-to-PCI bridge!\n");
- kfree(bridge);
- return;
+ goto err;
}
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;
}
@@ -577,14 +383,10 @@ 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 seg, bus, device, function;
+ int device, function;
struct pci_dev *dev;
-
- /* get PCI address */
- seg = (*segbus >> 8) & 0xff;
- bus = *segbus & 0xff;
+ struct pci_bus *pci_bus = context;
status = acpi_get_handle(handle, "_ADR", &dummy_handle);
if (ACPI_FAILURE(status))
@@ -599,20 +401,19 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
device = (tmp >> 16) & 0xffff;
function = tmp & 0xffff;
- dev = pci_find_slot(bus, PCI_DEVFN(device, function));
+ dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function));
- if (!dev)
- return AE_OK;
-
- if (!dev->subordinate)
- return AE_OK;
+ if (!dev || !dev->subordinate)
+ goto out;
/* 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, seg, bus, device, function);
+ add_p2p_bridge(handle, dev);
}
+ out:
+ pci_dev_put(dev);
return AE_OK;
}
@@ -624,6 +425,7 @@ 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);
@@ -653,18 +455,22 @@ 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, seg, bus);
+ add_host_bridge(handle, pci_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, &tmp, NULL);
+ find_p2p_bridge, pci_bus, NULL);
if (ACPI_FAILURE(status))
warn("find_p2p_bridge faied (error code = 0x%x)\n",status);
@@ -672,12 +478,205 @@ 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)
{
- /* No-op for now .. */
+ 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;
}
+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)
{
@@ -719,8 +718,6 @@ 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;
@@ -731,7 +728,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->pci_dev && (func->flags & FUNC_HAS_PS3)) {
+ if (func->flags & FUNC_HAS_PS3) {
status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
if (ACPI_FAILURE(status)) {
warn("%s: _PS3 failed\n", __FUNCTION__);
@@ -742,27 +739,6 @@ 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);
@@ -782,70 +758,56 @@ 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 *child;
+ struct pci_bus *bus = slot->bridge->pci_bus;
struct list_head *l;
struct acpiphp_func *func;
int retval = 0;
- int num;
+ int num, max, pass;
if (slot->flags & SLOT_ENABLED)
goto err_exit;
/* sanity check: dev should be NULL when hot-plugged in */
- dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
+ dev = pci_get_slot(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;
}
- /* 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) {
+ num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
+ if (num == 0) {
err("No new device found\n");
retval = -1;
goto err_exit;
}
- 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);
+ 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);
+ }
}
+ 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_find_slot(slot->bridge->bus,
- PCI_DEVFN(slot->device,
+ func->pci_dev = pci_get_slot(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;
}
@@ -866,9 +828,12 @@ 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;
- if (func->pci_dev)
- acpiphp_unconfigure_function(func);
+ pci_remove_bus_device(func->pci_dev);
+ pci_dev_put(func->pci_dev);
+ func->pci_dev = NULL;
}
slot->flags &= (~SLOT_ENABLED);
@@ -920,6 +885,39 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot)
}
/**
+ * 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
*
* Iterate over all slots under this bridge and make sure that if a
@@ -942,6 +940,8 @@ 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,6 +962,144 @@ 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; i<PCI_BRIDGE_RESOURCES; i++) {
+ struct resource *res = &dev->resource[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
*/
@@ -982,8 +1120,19 @@ 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;
- bridge = (struct acpiphp_bridge *)context;
+ 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;
+ }
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
@@ -1031,7 +1180,6 @@ 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)
*
@@ -1074,7 +1222,8 @@ 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);
- acpiphp_disable_slot(func->slot);
+ if (!(acpiphp_disable_slot(func->slot)))
+ acpiphp_eject_slot(func->slot);
break;
default:
@@ -1083,6 +1232,47 @@ 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,
@@ -1095,15 +1285,15 @@ static struct acpi_pci_driver acpi_pci_hp_driver = {
*/
int __init acpiphp_glue_init(void)
{
- int num;
-
- if (list_empty(&pci_root_buses))
- return -1;
+ int num = 0;
- num = acpi_pci_register_driver(&acpi_pci_hp_driver);
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, find_root_bridges, &num, NULL);
if (num <= 0)
return -1;
+ else
+ acpi_pci_register_driver(&acpi_pci_hp_driver);
return 0;
}
@@ -1116,46 +1306,6 @@ 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);
}
@@ -1173,11 +1323,14 @@ int __init acpiphp_get_num_slots(void)
list_for_each (node, &bridge_list) {
bridge = (struct acpiphp_bridge *)node;
- dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots);
+ 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");
num_slots += bridge->nr_slots;
}
- dbg("Total %dslots\n", num_slots);
+ dbg("Total %d slots\n", num_slots);
return num_slots;
}
@@ -1254,7 +1407,6 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot)
return retval;
}
-
/**
* acpiphp_disable_slot - power off slot
*/
@@ -1274,13 +1426,6 @@ 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;
@@ -1293,11 +1438,7 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot)
*/
u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
{
- unsigned int sta;
-
- sta = get_slot_status(slot);
-
- return (sta & ACPI_STA_ENABLED) ? 1 : 0;
+ return (slot->flags & SLOT_POWEREDON);
}
@@ -1335,9 +1476,10 @@ 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 = ((slot->bridge->seg) << 16) |
- ((slot->bridge->bus) << 8) |
+ address = (pci_domain_nr(pci_bus) << 16) |
+ (pci_bus->number << 8) |
slot->device;
return address;
diff --git a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c
deleted file mode 100644
index 54d97c9d1dff..000000000000
--- a/drivers/pci/hotplug/acpiphp_pci.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * 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 <t-kochi@bq.jp.nec.com>
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/acpi.h>
-#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/drivers/pci/hotplug/acpiphp_res.c b/drivers/pci/hotplug/acpiphp_res.c
deleted file mode 100644
index f54b1fa7b75a..000000000000
--- a/drivers/pci/hotplug/acpiphp_res.c
+++ /dev/null
@@ -1,700 +0,0 @@
-/*
- * 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 <gregkh@us.ibm.com>, <t-kochi@bq.jp.nec.com>
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/sysctl.h>
-#include <linux/pci.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-
-#include <linux/ioctl.h>
-#include <linux/fcntl.h>
-
-#include <linux/list.h>
-
-#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/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index afbccfa5217d..8c6d3987d461 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -60,6 +60,7 @@ 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 <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>"
@@ -1271,7 +1272,6 @@ static int one_time_init(void)
{
int loop;
int retval = 0;
- static int initialized = 0;
if (initialized)
return 0;
@@ -1441,7 +1441,8 @@ static void __exit unload_cpqphpd(void)
}
// Stop the notification mechanism
- cpqhp_event_stop_thread();
+ if (initialized)
+ cpqhp_event_stop_thread();
//unmap the rom address
if (cpqhp_rom_start)
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 30206ac43c44..b5ab9aa6ff7c 100644
--- a/drivers/pci/msi.c
+++ b/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 = 0;
-static int nr_released_vectors = 0;
+static int last_alloc_vector;
+static int nr_released_vectors;
static int nr_reserved_vectors = NR_HP_RESERVED_VECTORS;
-static int nr_msix_devices = 0;
+static int nr_msix_devices;
#ifndef CONFIG_X86_IO_APIC
int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
@@ -170,44 +170,30 @@ static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector)
return 0; /* never anything pending */
}
-static void release_msi(unsigned int vector);
-static void shutdown_msi_irq(unsigned int vector)
-{
- release_msi(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)
+static unsigned int startup_msi_irq_w_maskbit(unsigned int vector)
{
- move_msi(vector);
- ack_APIC_irq();
+ startup_msi_irq_wo_maskbit(vector);
+ unmask_MSI_irq(vector);
+ return 0; /* never anything pending */
}
-static unsigned int startup_msi_irq_w_maskbit(unsigned int vector)
+static void shutdown_msi_irq(unsigned int vector)
{
struct msi_desc *entry;
unsigned long flags;
spin_lock_irqsave(&msi_lock, flags);
entry = msi_desc[vector];
- if (!entry || !entry->dev) {
- spin_unlock_irqrestore(&msi_lock, flags);
- return 0;
- }
- entry->msi_attrib.state = 1; /* Mark it active */
+ if (entry && entry->dev)
+ entry->msi_attrib.state = 0; /* Mark it not active */
spin_unlock_irqrestore(&msi_lock, flags);
-
- 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_wo_maskbit(unsigned int vector)
+{
+ move_msi(vector);
+ ack_APIC_irq();
+}
static void end_msi_irq_w_maskbit(unsigned int vector)
{
@@ -216,6 +202,10 @@ 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.
@@ -223,10 +213,10 @@ static void end_msi_irq_w_maskbit(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_w_maskbit,
- .enable = enable_msi_irq_w_maskbit,
- .disable = disable_msi_irq_w_maskbit,
- .ack = ack_msi_irq_w_maskbit,
+ .shutdown = shutdown_msi_irq,
+ .enable = unmask_MSI_irq,
+ .disable = mask_MSI_irq,
+ .ack = mask_MSI_irq,
.end = end_msi_irq_w_maskbit,
.set_affinity = set_msi_irq_affinity
};
@@ -239,10 +229,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_w_maskbit,
- .enable = enable_msi_irq_w_maskbit,
- .disable = disable_msi_irq_w_maskbit,
- .ack = ack_msi_irq_w_maskbit,
+ .shutdown = shutdown_msi_irq,
+ .enable = unmask_MSI_irq,
+ .disable = mask_MSI_irq,
+ .ack = mask_MSI_irq,
.end = end_msi_irq_w_maskbit,
.set_affinity = set_msi_irq_affinity
};
@@ -255,10 +245,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_wo_maskbit,
- .enable = enable_msi_irq_wo_maskbit,
- .disable = disable_msi_irq_wo_maskbit,
- .ack = ack_msi_irq_wo_maskbit,
+ .shutdown = shutdown_msi_irq,
+ .enable = do_nothing,
+ .disable = do_nothing,
+ .ack = do_nothing,
.end = end_msi_irq_wo_maskbit,
.set_affinity = set_msi_irq_affinity
};
@@ -407,7 +397,7 @@ static struct msi_desc* alloc_msi_entry(void)
{
struct msi_desc *entry;
- entry = (struct msi_desc*) kmem_cache_alloc(msi_cachep, SLAB_KERNEL);
+ entry = kmem_cache_alloc(msi_cachep, SLAB_KERNEL);
if (!entry)
return NULL;
@@ -796,18 +786,6 @@ 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;
@@ -924,7 +902,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
- * @data: pointer to an array of MSI-X entries
+ * @entries: 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/drivers/pci/msi.h b/drivers/pci/msi.h
index bef21ae3cbd0..390f1851c0f1 100644
--- a/drivers/pci/msi.h
+++ b/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,7 +64,6 @@ 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/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index a15f94072a6f..cc9d65388e62 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -60,15 +60,18 @@ 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++) {
- 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));
+ 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);
}
return (str - buf);
}
@@ -313,8 +316,21 @@ 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;
- vma->vm_pgoff += res->start >> PAGE_SHIFT;
+ 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;
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/drivers/pci/probe.c b/drivers/pci/probe.c
index fd48b201eb53..6a0a82f0508b 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -374,8 +374,11 @@ 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)
+ if (child) {
+ spin_lock(&pci_bus_lock);
list_add_tail(&child->node, &parent->children);
+ spin_unlock(&pci_bus_lock);
+ }
return child;
}
@@ -411,7 +414,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;
+ u32 buses, i;
u16 bctl;
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
@@ -447,7 +450,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
return max;
}
- child = pci_alloc_child_bus(bus, dev, busnr);
+ child = pci_add_new_bus(bus, dev, busnr);
if (!child)
return max;
child->primary = buses & 0xFF;
@@ -470,7 +473,11 @@ 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);
- child = pci_alloc_child_bus(bus, dev, ++max);
+ /* 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);
buses = (buses & 0xff000000)
| ((unsigned int)(child->primary) << 0)
| ((unsigned int)(child->secondary) << 8)
@@ -501,7 +508,11 @@ 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.
*/
- max += CARDBUS_RESERVE_BUSNR;
+ for (i=0; i<CARDBUS_RESERVE_BUSNR; i++)
+ if (pci_find_bus(pci_domain_nr(bus),
+ max+i+1))
+ break;
+ max += i;
}
/*
* Set the subordinate bus number to its real value.
@@ -757,7 +768,9 @@ pci_scan_single_device(struct pci_bus *bus, int devfn)
* and the bus list for fixup functions, etc.
*/
INIT_LIST_HEAD(&dev->global_list);
+ spin_lock(&pci_bus_lock);
list_add_tail(&dev->bus_list, &bus->devices);
+ spin_unlock(&pci_bus_lock);
return dev;
}
@@ -878,7 +891,9 @@ 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;
@@ -911,8 +926,6 @@ 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:
@@ -922,7 +935,9 @@ class_dev_create_file_err:
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/drivers/pci/proc.c b/drivers/pci/proc.c
index e68bbfb1e7c3..7988fc8df3fd 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -355,14 +355,20 @@ 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++)
+ for (i=0; i<7; i++) {
+ u64 start, end;
+ pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
seq_printf(m, LONG_FORMAT,
- dev->resource[i].start |
+ ((unsigned long)start) |
(dev->resource[i].flags & PCI_REGION_FLAG_MASK));
- for(i=0; i<7; i++)
+ }
+ for (i=0; i<7; i++) {
+ u64 start, end;
+ pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
seq_printf(m, LONG_FORMAT,
dev->resource[i].start < dev->resource[i].end ?
- dev->resource[i].end - dev->resource[i].start + 1 : 0);
+ (unsigned long)(end - start) + 1 : 0);
+ }
seq_putc(m, '\t');
if (drv)
seq_printf(m, "%s", drv->name);
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 96f077f9a659..27a294b6965d 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -18,17 +18,21 @@ static void pci_free_resources(struct pci_dev *dev)
static void pci_destroy_dev(struct pci_dev *dev)
{
- pci_proc_detach_device(dev);
- pci_remove_sysfs_dev_files(dev);
- device_unregister(&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);
+ }
/* 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/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 1ba84be0b4c0..6b628de948af 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -72,7 +72,10 @@ pbus_assign_resources_sorted(struct pci_bus *bus)
for (list = head.next; list;) {
res = list->res;
idx = res - &list->dev->resource[0];
- pci_assign_resource(list->dev, idx);
+ if (pci_assign_resource(list->dev, idx)) {
+ res->start = 0;
+ res->flags = 0;
+ }
tmp = list;
list = list->next;
kfree(tmp);
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 34dbc37a79d4..bc6e4627c7a1 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/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 device *dev)
+static void twa_shutdown(struct pci_dev *pdev)
{
- struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
__twa_shutdown(tw_dev);
@@ -2140,9 +2140,7 @@ static struct pci_driver twa_driver = {
.id_table = twa_pci_tbl,
.probe = twa_probe,
.remove = twa_remove,
- .driver = {
- .shutdown = twa_shutdown
- }
+ .shutdown = twa_shutdown
};
/* This function is called on driver initialization */
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index b6dc576da430..973c51fb0fe2 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/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 device *dev)
+static void tw_shutdown(struct pci_dev *pdev)
{
- struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
__tw_shutdown(tw_dev);
@@ -2451,9 +2451,7 @@ static struct pci_driver tw_driver = {
.id_table = tw_pci_tbl,
.probe = tw_probe,
.remove = tw_remove,
- .driver = {
- .shutdown = tw_shutdown
- }
+ .shutdown = tw_shutdown,
};
/* This function is called on driver initialization */
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 9a547ca9c864..c5623694d10f 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -304,26 +304,19 @@ 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) {
- rc = -ENOMEM;
- goto err_out;
- }
+ if (!pp)
+ return -ENOMEM;
memset(pp, 0, sizeof(*pp));
mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
if (!mem) {
- rc = -ENOMEM;
- goto err_out_kfree;
+ kfree(pp);
+ return -ENOMEM;
}
memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
@@ -373,12 +366,6 @@ 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;
}
@@ -404,7 +391,6 @@ 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/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 80d022625c82..babd48363402 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -6012,7 +6012,7 @@ static int __devinit ipr_probe(struct pci_dev *pdev,
/**
* ipr_shutdown - Shutdown handler.
- * @dev: device struct
+ * @pdev: pci 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 device *dev)
+static void ipr_shutdown(struct pci_dev *pdev)
{
- struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(to_pci_dev(dev));
+ struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
unsigned long lock_flags = 0;
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -6068,9 +6068,7 @@ static struct pci_driver ipr_driver = {
.id_table = ipr_pci_table,
.probe = ipr_probe,
.remove = ipr_remove,
- .driver = {
- .shutdown = ipr_shutdown,
- },
+ .shutdown = ipr_shutdown,
};
/**
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 36b401fee1f1..cb535fa185b9 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1408,7 +1408,9 @@ 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);
- udelay(400); /* FIXME: a guess */
+ /* Couldn't find anything in SATA I/II specs, but
+ * AHCI-1.1 10.4.2 says at least 1 ms. */
+ mdelay(1);
}
scr_write_flush(ap, SCR_CONTROL, 0x300); /* phy wake/clear reset */
@@ -1920,6 +1922,7 @@ 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",
@@ -1927,7 +1930,6 @@ 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/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index ec81532eb845..a70cdf31311c 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -5036,9 +5036,9 @@ megaraid_remove_one(struct pci_dev *pdev)
}
static void
-megaraid_shutdown(struct device *dev)
+megaraid_shutdown(struct pci_dev *pdev)
{
- struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
adapter_t *adapter = (adapter_t *)host->hostdata;
__megaraid_shutdown(adapter);
@@ -5070,9 +5070,7 @@ static struct pci_driver megaraid_pci_driver = {
.id_table = megaraid_pci_tbl,
.probe = megaraid_probe_one,
.remove = __devexit_p(megaraid_remove_one),
- .driver = {
- .shutdown = megaraid_shutdown,
- },
+ .shutdown = megaraid_shutdown,
};
static int __init megaraid_init(void)
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index c627bc408a6b..9ad142476f33 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -108,6 +108,21 @@ 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;
@@ -327,9 +342,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/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index c62e92ec43b2..4ec722d73381 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -68,6 +68,7 @@ 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/include/asm-alpha/pci.h b/include/asm-alpha/pci.h
index 0c7b57bc043a..b7806aa3785c 100644
--- a/include/asm-alpha/pci.h
+++ b/include/asm-alpha/pci.h
@@ -223,6 +223,25 @@ 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/include/asm-arm/pci.h b/include/asm-arm/pci.h
index 40ffaefbeb1a..e300646fe650 100644
--- a/include/asm-arm/pci.h
+++ b/include/asm-arm/pci.h
@@ -42,6 +42,16 @@ 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/include/asm-frv/pci.h b/include/asm-frv/pci.h
index a6a469231f62..b4efe5e3591a 100644
--- a/include/asm-frv/pci.h
+++ b/include/asm-frv/pci.h
@@ -57,6 +57,16 @@ 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/include/asm-i386/pci.h b/include/asm-i386/pci.h
index fb749b85a739..3561899eb826 100644
--- a/include/asm-i386/pci.h
+++ b/include/asm-i386/pci.h
@@ -99,6 +99,16 @@ 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/include/asm-ia64/iosapic.h b/include/asm-ia64/iosapic.h
index 38a7a72791cc..1093f35b3b90 100644
--- a/include/asm-ia64/iosapic.h
+++ b/include/asm-ia64/iosapic.h
@@ -71,8 +71,11 @@ static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
}
extern void __init iosapic_system_init (int pcat_compat);
-extern void __init iosapic_init (unsigned long address,
+extern int __devinit 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);
@@ -94,11 +97,14 @@ extern unsigned int iosapic_version (char __iomem *addr);
extern void iosapic_pci_fixup (int);
#ifdef CONFIG_NUMA
-extern void __init map_iosapic_to_node (unsigned int, int);
+extern void __devinit map_iosapic_to_node (unsigned int, int);
#endif
#else
#define iosapic_system_init(pcat_compat) do { } while (0)
-#define iosapic_init(address,gsi_base) do { } while (0)
+#define iosapic_init(address,gsi_base) (-EINVAL)
+#ifdef CONFIG_HOTPLUG
+#define iosapic_remove(gsi_base) (-ENODEV)
+#endif /* CONFIG_HOTPLUG */
#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/include/asm-ia64/pci.h b/include/asm-ia64/pci.h
index a8314ee4e7d2..0c4c5d801d3f 100644
--- a/include/asm-ia64/pci.h
+++ b/include/asm-ia64/pci.h
@@ -82,6 +82,25 @@ 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/include/asm-mips/pci.h b/include/asm-mips/pci.h
index c9c576b48556..2d323b6e147d 100644
--- a/include/asm-mips/pci.h
+++ b/include/asm-mips/pci.h
@@ -130,6 +130,16 @@ 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/include/asm-parisc/pci.h b/include/asm-parisc/pci.h
index 0763c2982fb0..ee741c150176 100644
--- a/include/asm-parisc/pci.h
+++ b/include/asm-parisc/pci.h
@@ -230,6 +230,25 @@ extern inline void pcibios_register_hba(struct pci_hba_data *x)
/* export the pci_ DMA API in terms of the dma_ one */
#include <asm-generic/pci-dma-compat.h>
+#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/include/asm-ppc/pci.h b/include/asm-ppc/pci.h
index ce5ae6d048f5..db0a2a0ec74d 100644
--- a/include/asm-ppc/pci.h
+++ b/include/asm-ppc/pci.h
@@ -69,6 +69,16 @@ 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.
@@ -103,6 +113,12 @@ 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/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h
index 6cd593f660a0..d12dfce21e20 100644
--- a/include/asm-ppc64/pci.h
+++ b/include/asm-ppc64/pci.h
@@ -78,6 +78,25 @@ 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 */
@@ -136,6 +155,13 @@ 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/include/asm-sh/pci.h b/include/asm-sh/pci.h
index 9c3b63d0105e..26044889c770 100644
--- a/include/asm-sh/pci.h
+++ b/include/asm-sh/pci.h
@@ -96,6 +96,16 @@ 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/include/asm-sh64/pci.h b/include/asm-sh64/pci.h
index 8cc14e139750..c68870e02d91 100644
--- a/include/asm-sh64/pci.h
+++ b/include/asm-sh64/pci.h
@@ -86,6 +86,16 @@ 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/include/asm-sparc/pci.h b/include/asm-sparc/pci.h
index d200a25a7373..44bb38758c96 100644
--- a/include/asm-sparc/pci.h
+++ b/include/asm-sparc/pci.h
@@ -144,6 +144,16 @@ 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/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h
index 2a0c85cd1c11..84e41c1ef3f8 100644
--- a/include/asm-sparc64/pci.h
+++ b/include/asm-sparc64/pci.h
@@ -220,6 +220,25 @@ 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/include/asm-v850/pci.h b/include/asm-v850/pci.h
index e41941447b49..8e79be0fe99d 100644
--- a/include/asm-v850/pci.h
+++ b/include/asm-v850/pci.h
@@ -81,6 +81,16 @@ 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/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h
index 8712520ca47f..c1961db88fac 100644
--- a/include/asm-x86_64/pci.h
+++ b/include/asm-x86_64/pci.h
@@ -123,6 +123,16 @@ 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/include/linux/acpi.h b/include/linux/acpi.h
index b123cc08773d..ef8483673aa3 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -342,11 +342,19 @@ 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];
- u32 base_address;
- u32 base_reserved;
+ struct acpi_table_mcfg_config config[0];
} __attribute__ ((packed));
/* Table Handlers */
@@ -391,6 +399,7 @@ 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);
@@ -407,9 +416,13 @@ 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 u32 pci_mmcfg_base_addr;
+extern struct acpi_table_mcfg_config *pci_mmcfg_config;
+extern int pci_mmcfg_config_num;
extern int sbf_port ;
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index a1478258d002..8a2df4dfbc59 100644
--- a/include/linux/etherdevice.h
+++ b/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] & 0x01;
+ return ((addr[0] != 0xff) && (0x01 & addr[0]));
}
/**
diff --git a/include/linux/pci.h b/include/linux/pci.h
index b5238bd18830..66798b46f308 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -734,16 +734,20 @@ 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)
{
- return pci_scan_bus_parented(NULL, bus, ops, 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;
}
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);
@@ -870,6 +874,15 @@ 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
@@ -972,6 +985,8 @@ 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
@@ -1016,6 +1031,20 @@ 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/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 1e0bc6a8d653..c3ee1ae4545a 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -62,6 +62,8 @@
#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/include/net/ieee80211.h b/include/net/ieee80211.h
index 7fe57f957a51..151c4f203559 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -94,6 +94,8 @@ 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
@@ -300,23 +302,6 @@ 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)
@@ -441,6 +426,8 @@ 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)
@@ -488,15 +475,6 @@ 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 */
@@ -541,7 +519,7 @@ struct ieee80211_info_element {
*/
struct ieee80211_authentication {
- struct ieee80211_header_data header;
+ struct ieee80211_hdr_3addr header;
u16 algorithm;
u16 transaction;
u16 status;
@@ -550,7 +528,7 @@ struct ieee80211_authentication {
struct ieee80211_probe_response {
- struct ieee80211_header_data header;
+ struct ieee80211_hdr_3addr header;
u32 time_stamp[2];
u16 beacon_interval;
u16 capability;
@@ -648,12 +626,6 @@ 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)
@@ -787,21 +759,21 @@ extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mod
extern inline int ieee80211_get_hdrlen(u16 fc)
{
- int hdrlen = 24;
+ int hdrlen = IEEE80211_3ADDR_LEN;
switch (WLAN_FC_GET_TYPE(fc)) {
case IEEE80211_FTYPE_DATA:
if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
- hdrlen = 30; /* Addr4 */
+ hdrlen = IEEE80211_4ADDR_LEN;
break;
case IEEE80211_FTYPE_CTL:
switch (WLAN_FC_GET_STYPE(fc)) {
case IEEE80211_STYPE_CTS:
case IEEE80211_STYPE_ACK:
- hdrlen = 10;
+ hdrlen = IEEE80211_1ADDR_LEN;
break;
default:
- hdrlen = 16;
+ hdrlen = IEEE80211_2ADDR_LEN;
break;
}
break;
diff --git a/init/main.c b/init/main.c
index d324801729ba..b5e421e39ede 100644
--- a/init/main.c
+++ b/init/main.c
@@ -383,6 +383,13 @@ 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/kernel/kexec.c b/kernel/kexec.c
index 7843548cf2d9..cdd4dcd8fb63 100644
--- a/kernel/kexec.c
+++ b/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 *segments)
+ struct kexec_segment __user *segments)
{
int result;
struct kimage *image;
@@ -650,7 +650,7 @@ static kimage_entry_t *kimage_dst_used(struct kimage *image,
}
}
- return 0;
+ return NULL;
}
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 0;
+ return NULL;
/* 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 *buf;
+ unsigned char __user *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 *buf;
+ unsigned char __user *buf;
result = 0;
buf = segment->buf;
diff --git a/kernel/sched.c b/kernel/sched.c
index e2b0d3e4dd06..5f2182d42241 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -4166,6 +4166,14 @@ 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);
@@ -4183,7 +4191,6 @@ 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! */