Merge branch 'master'
This commit is contained in:
commit
71ec63c5d6
@ -2057,9 +2057,10 @@ L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
NI5010 NETWORK DRIVER
|
||||
P: Jan-Pascal van Best and Andreas Mohr
|
||||
M: Jan-Pascal van Best <jvbest@qv3pluto.leidenuniv.nl>
|
||||
M: Andreas Mohr <100.30936@germany.net>
|
||||
P: Jan-Pascal van Best
|
||||
M: janpascal@vanbest.org
|
||||
P: Andreas Mohr
|
||||
M: andi@lisas.de
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
|
6
Makefile
6
Makefile
@ -1,7 +1,7 @@
|
||||
VERSION = 2
|
||||
PATCHLEVEL = 6
|
||||
SUBLEVEL = 17
|
||||
EXTRAVERSION =
|
||||
SUBLEVEL = 18
|
||||
EXTRAVERSION = -rc1
|
||||
NAME=Crazed Snow-Weasel
|
||||
|
||||
# *DOCUMENTATION*
|
||||
@ -528,7 +528,7 @@ export MODLIB
|
||||
|
||||
ifdef INSTALL_MOD_STRIP
|
||||
ifeq ($(INSTALL_MOD_STRIP),1)
|
||||
mod_strip_cmd = $STRIP) --strip-debug
|
||||
mod_strip_cmd = $(STRIP) --strip-debug
|
||||
else
|
||||
mod_strip_cmd = $(STRIP) $(INSTALL_MOD_STRIP)
|
||||
endif # INSTALL_MOD_STRIP=1
|
||||
|
@ -107,3 +107,48 @@ void __init at91rm9200_map_io(void)
|
||||
iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
|
||||
}
|
||||
|
||||
/*
|
||||
* The default interrupt priority levels (0 = lowest, 7 = highest).
|
||||
*/
|
||||
static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
|
||||
7, /* Advanced Interrupt Controller (FIQ) */
|
||||
7, /* System Peripherals */
|
||||
0, /* Parallel IO Controller A */
|
||||
0, /* Parallel IO Controller B */
|
||||
0, /* Parallel IO Controller C */
|
||||
0, /* Parallel IO Controller D */
|
||||
6, /* USART 0 */
|
||||
6, /* USART 1 */
|
||||
6, /* USART 2 */
|
||||
6, /* USART 3 */
|
||||
0, /* Multimedia Card Interface */
|
||||
4, /* USB Device Port */
|
||||
0, /* Two-Wire Interface */
|
||||
6, /* Serial Peripheral Interface */
|
||||
5, /* Serial Synchronous Controller 0 */
|
||||
5, /* Serial Synchronous Controller 1 */
|
||||
5, /* Serial Synchronous Controller 2 */
|
||||
0, /* Timer Counter 0 */
|
||||
0, /* Timer Counter 1 */
|
||||
0, /* Timer Counter 2 */
|
||||
0, /* Timer Counter 3 */
|
||||
0, /* Timer Counter 4 */
|
||||
0, /* Timer Counter 5 */
|
||||
3, /* USB Host port */
|
||||
3, /* Ethernet MAC */
|
||||
0, /* Advanced Interrupt Controller (IRQ0) */
|
||||
0, /* Advanced Interrupt Controller (IRQ1) */
|
||||
0, /* Advanced Interrupt Controller (IRQ2) */
|
||||
0, /* Advanced Interrupt Controller (IRQ3) */
|
||||
0, /* Advanced Interrupt Controller (IRQ4) */
|
||||
0, /* Advanced Interrupt Controller (IRQ5) */
|
||||
0 /* Advanced Interrupt Controller (IRQ6) */
|
||||
};
|
||||
|
||||
void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
|
||||
{
|
||||
if (!priority)
|
||||
priority = at91rm9200_default_irq_priority;
|
||||
|
||||
at91_aic_init(priority);
|
||||
}
|
||||
|
@ -8,13 +8,19 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
void at91_gpio_irq_setup(unsigned banks);
|
||||
/* Interrupts */
|
||||
extern void __init at91rm9200_init_irq(unsigned int priority[]);
|
||||
extern void __init at91_aic_init(unsigned int priority[]);
|
||||
extern void __init at91_gpio_irq_setup(unsigned banks);
|
||||
|
||||
/* Timer */
|
||||
struct sys_timer;
|
||||
extern struct sys_timer at91rm9200_timer;
|
||||
|
||||
/* Memory Map */
|
||||
extern void __init at91rm9200_map_io(void);
|
||||
|
||||
/* Clocks */
|
||||
extern int __init at91_clock_init(unsigned long main_clock);
|
||||
struct device;
|
||||
extern void __init at91_clock_associate(const char *id, struct device *dev, const char *func);
|
||||
|
@ -36,58 +36,20 @@
|
||||
|
||||
#include "generic.h"
|
||||
|
||||
/*
|
||||
* The default interrupt priority levels (0 = lowest, 7 = highest).
|
||||
*/
|
||||
static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
|
||||
7, /* Advanced Interrupt Controller */
|
||||
7, /* System Peripheral */
|
||||
0, /* Parallel IO Controller A */
|
||||
0, /* Parallel IO Controller B */
|
||||
0, /* Parallel IO Controller C */
|
||||
0, /* Parallel IO Controller D */
|
||||
6, /* USART 0 */
|
||||
6, /* USART 1 */
|
||||
6, /* USART 2 */
|
||||
6, /* USART 3 */
|
||||
0, /* Multimedia Card Interface */
|
||||
4, /* USB Device Port */
|
||||
0, /* Two-Wire Interface */
|
||||
6, /* Serial Peripheral Interface */
|
||||
5, /* Serial Synchronous Controller */
|
||||
5, /* Serial Synchronous Controller */
|
||||
5, /* Serial Synchronous Controller */
|
||||
0, /* Timer Counter 0 */
|
||||
0, /* Timer Counter 1 */
|
||||
0, /* Timer Counter 2 */
|
||||
0, /* Timer Counter 3 */
|
||||
0, /* Timer Counter 4 */
|
||||
0, /* Timer Counter 5 */
|
||||
3, /* USB Host port */
|
||||
3, /* Ethernet MAC */
|
||||
0, /* Advanced Interrupt Controller */
|
||||
0, /* Advanced Interrupt Controller */
|
||||
0, /* Advanced Interrupt Controller */
|
||||
0, /* Advanced Interrupt Controller */
|
||||
0, /* Advanced Interrupt Controller */
|
||||
0, /* Advanced Interrupt Controller */
|
||||
0 /* Advanced Interrupt Controller */
|
||||
};
|
||||
|
||||
|
||||
static void at91rm9200_mask_irq(unsigned int irq)
|
||||
static void at91_aic_mask_irq(unsigned int irq)
|
||||
{
|
||||
/* Disable interrupt on AIC */
|
||||
at91_sys_write(AT91_AIC_IDCR, 1 << irq);
|
||||
}
|
||||
|
||||
static void at91rm9200_unmask_irq(unsigned int irq)
|
||||
static void at91_aic_unmask_irq(unsigned int irq)
|
||||
{
|
||||
/* Enable interrupt on AIC */
|
||||
at91_sys_write(AT91_AIC_IECR, 1 << irq);
|
||||
}
|
||||
|
||||
static int at91rm9200_irq_type(unsigned irq, unsigned type)
|
||||
static int at91_aic_set_type(unsigned irq, unsigned type)
|
||||
{
|
||||
unsigned int smr, srctype;
|
||||
|
||||
@ -122,7 +84,7 @@ static int at91rm9200_irq_type(unsigned irq, unsigned type)
|
||||
static u32 wakeups;
|
||||
static u32 backups;
|
||||
|
||||
static int at91rm9200_irq_set_wake(unsigned irq, unsigned value)
|
||||
static int at91_aic_set_wake(unsigned irq, unsigned value)
|
||||
{
|
||||
if (unlikely(irq >= 32))
|
||||
return -EINVAL;
|
||||
@ -149,28 +111,24 @@ void at91_irq_resume(void)
|
||||
}
|
||||
|
||||
#else
|
||||
#define at91rm9200_irq_set_wake NULL
|
||||
#define at91_aic_set_wake NULL
|
||||
#endif
|
||||
|
||||
static struct irqchip at91rm9200_irq_chip = {
|
||||
.ack = at91rm9200_mask_irq,
|
||||
.mask = at91rm9200_mask_irq,
|
||||
.unmask = at91rm9200_unmask_irq,
|
||||
.set_type = at91rm9200_irq_type,
|
||||
.set_wake = at91rm9200_irq_set_wake,
|
||||
static struct irqchip at91_aic_chip = {
|
||||
.ack = at91_aic_mask_irq,
|
||||
.mask = at91_aic_mask_irq,
|
||||
.unmask = at91_aic_unmask_irq,
|
||||
.set_type = at91_aic_set_type,
|
||||
.set_wake = at91_aic_set_wake,
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the AIC interrupt controller.
|
||||
*/
|
||||
void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
|
||||
void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* No priority list specified for this board -> use defaults */
|
||||
if (priority == NULL)
|
||||
priority = at91rm9200_default_irq_priority;
|
||||
|
||||
/*
|
||||
* The IVR is used by macro get_irqnr_and_base to read and verify.
|
||||
* The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
|
||||
@ -178,10 +136,10 @@ void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
|
||||
for (i = 0; i < NR_AIC_IRQS; i++) {
|
||||
/* Put irq number in Source Vector Register: */
|
||||
at91_sys_write(AT91_AIC_SVR(i), i);
|
||||
/* Store the Source Mode Register as defined in table above */
|
||||
/* Active Low interrupt, with the specified priority */
|
||||
at91_sys_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
|
||||
|
||||
set_irq_chip(i, &at91rm9200_irq_chip);
|
||||
set_irq_chip(i, &at91_aic_chip);
|
||||
set_irq_handler(i, do_level_IRQ);
|
||||
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
|
||||
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/mach-types.h>
|
||||
@ -36,7 +35,6 @@
|
||||
#include <asm/system.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/irq.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include <asm/mach/time.h>
|
||||
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/dma-mapping.h>
|
||||
|
@ -22,8 +22,8 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/irq.h>
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/mach-types.h>
|
||||
@ -96,26 +96,24 @@ void __init pnx4008_init_irq(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* configure and enable IRQ 0,1,30,31 (cascade interrupts) mask all others */
|
||||
/* configure IRQ's */
|
||||
for (i = 0; i < NR_IRQS; i++) {
|
||||
set_irq_flags(i, IRQF_VALID);
|
||||
set_irq_chip(i, &pnx4008_irq_chip);
|
||||
pnx4008_set_irq_type(i, pnx4008_irq_type[i]);
|
||||
}
|
||||
|
||||
/* configure and enable IRQ 0,1,30,31 (cascade interrupts) */
|
||||
pnx4008_set_irq_type(SUB1_IRQ_N, pnx4008_irq_type[SUB1_IRQ_N]);
|
||||
pnx4008_set_irq_type(SUB2_IRQ_N, pnx4008_irq_type[SUB2_IRQ_N]);
|
||||
pnx4008_set_irq_type(SUB1_FIQ_N, pnx4008_irq_type[SUB1_FIQ_N]);
|
||||
pnx4008_set_irq_type(SUB2_FIQ_N, pnx4008_irq_type[SUB2_FIQ_N]);
|
||||
|
||||
/* mask all others */
|
||||
__raw_writel((1 << SUB2_FIQ_N) | (1 << SUB1_FIQ_N) |
|
||||
(1 << SUB2_IRQ_N) | (1 << SUB1_IRQ_N),
|
||||
INTC_ER(MAIN_BASE_INT));
|
||||
__raw_writel(0, INTC_ER(SIC1_BASE_INT));
|
||||
__raw_writel(0, INTC_ER(SIC2_BASE_INT));
|
||||
|
||||
/* configure all other IRQ's */
|
||||
for (i = 0; i < NR_IRQS; i++) {
|
||||
if (i == SUB2_FIQ_N || i == SUB1_FIQ_N ||
|
||||
i == SUB2_IRQ_N || i == SUB1_IRQ_N)
|
||||
continue;
|
||||
set_irq_flags(i, IRQF_VALID);
|
||||
set_irq_chip(i, &pnx4008_irq_chip);
|
||||
pnx4008_set_irq_type(i, pnx4008_irq_type[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,17 +20,15 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/leds.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/mach/irq.h>
|
||||
#include <asm/mach/time.h>
|
||||
|
||||
#include <linux/time.h>
|
||||
#include <linux/timex.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
/*! Note: all timers are UPCOUNTING */
|
||||
|
@ -405,20 +405,22 @@ static void mpic_unmask_irq(unsigned int irq)
|
||||
unsigned int loops = 100000;
|
||||
struct mpic *mpic = mpic_from_irq(irq);
|
||||
unsigned int src = mpic_irq_to_hw(irq);
|
||||
unsigned long flags;
|
||||
|
||||
DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src);
|
||||
|
||||
spin_lock_irqsave(&mpic_lock, flags);
|
||||
mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
|
||||
mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) &
|
||||
~MPIC_VECPRI_MASK);
|
||||
|
||||
/* make sure mask gets to controller before we return to user */
|
||||
do {
|
||||
if (!loops--) {
|
||||
printk(KERN_ERR "mpic_enable_irq timeout\n");
|
||||
break;
|
||||
}
|
||||
} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
|
||||
} while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK);
|
||||
spin_unlock_irqrestore(&mpic_lock, flags);
|
||||
}
|
||||
|
||||
static void mpic_mask_irq(unsigned int irq)
|
||||
@ -426,9 +428,11 @@ static void mpic_mask_irq(unsigned int irq)
|
||||
unsigned int loops = 100000;
|
||||
struct mpic *mpic = mpic_from_irq(irq);
|
||||
unsigned int src = mpic_irq_to_hw(irq);
|
||||
unsigned long flags;
|
||||
|
||||
DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src);
|
||||
|
||||
spin_lock_irqsave(&mpic_lock, flags);
|
||||
mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI,
|
||||
mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
|
||||
MPIC_VECPRI_MASK);
|
||||
@ -440,6 +444,7 @@ static void mpic_mask_irq(unsigned int irq)
|
||||
break;
|
||||
}
|
||||
} while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK));
|
||||
spin_unlock_irqrestore(&mpic_lock, flags);
|
||||
}
|
||||
|
||||
static void mpic_end_irq(unsigned int irq)
|
||||
@ -624,9 +629,10 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
|
||||
struct irq_desc *desc = get_irq_desc(virq);
|
||||
struct irq_chip *chip;
|
||||
struct mpic *mpic = h->host_data;
|
||||
unsigned int vecpri = MPIC_VECPRI_SENSE_LEVEL |
|
||||
u32 v, vecpri = MPIC_VECPRI_SENSE_LEVEL |
|
||||
MPIC_VECPRI_POLARITY_NEGATIVE;
|
||||
int level;
|
||||
unsigned long iflags;
|
||||
|
||||
pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n",
|
||||
virq, hw, flags);
|
||||
@ -668,11 +674,21 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Reconfigure irq */
|
||||
vecpri |= MPIC_VECPRI_MASK | hw | (8 << MPIC_VECPRI_PRIORITY_SHIFT);
|
||||
mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri);
|
||||
/* Reconfigure irq. We must preserve the mask bit as we can be called
|
||||
* while the interrupt is still active (This may change in the future
|
||||
* but for now, it is the case).
|
||||
*/
|
||||
spin_lock_irqsave(&mpic_lock, iflags);
|
||||
v = mpic_irq_read(hw, MPIC_IRQ_VECTOR_PRI);
|
||||
vecpri = (v &
|
||||
~(MPIC_VECPRI_POLARITY_MASK | MPIC_VECPRI_SENSE_MASK)) |
|
||||
vecpri;
|
||||
if (vecpri != v)
|
||||
mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri);
|
||||
spin_unlock_irqrestore(&mpic_lock, iflags);
|
||||
|
||||
pr_debug("mpic: mapping as IRQ\n");
|
||||
pr_debug("mpic: mapping as IRQ, vecpri = 0x%08x (was 0x%08x)\n",
|
||||
vecpri, v);
|
||||
|
||||
set_irq_chip_data(virq, mpic);
|
||||
set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq);
|
||||
@ -904,8 +920,8 @@ void __init mpic_init(struct mpic *mpic)
|
||||
|
||||
/* do senses munging */
|
||||
if (mpic->senses && i < mpic->senses_count)
|
||||
vecpri = mpic_flags_to_vecpri(mpic->senses[i],
|
||||
&level);
|
||||
vecpri |= mpic_flags_to_vecpri(mpic->senses[i],
|
||||
&level);
|
||||
else
|
||||
vecpri |= MPIC_VECPRI_SENSE_LEVEL;
|
||||
|
||||
@ -955,14 +971,17 @@ void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)
|
||||
|
||||
void __init mpic_set_serial_int(struct mpic *mpic, int enable)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 v;
|
||||
|
||||
spin_lock_irqsave(&mpic_lock, flags);
|
||||
v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1);
|
||||
if (enable)
|
||||
v |= MPIC_GREG_GLOBAL_CONF_1_SIE;
|
||||
else
|
||||
v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE;
|
||||
mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v);
|
||||
spin_unlock_irqrestore(&mpic_lock, flags);
|
||||
}
|
||||
|
||||
void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
|
||||
|
@ -1032,7 +1032,9 @@ static void sun4v_vdev_irq_trans_init(struct device_node *dp)
|
||||
static void irq_trans_init(struct device_node *dp)
|
||||
{
|
||||
const char *model;
|
||||
#ifdef CONFIG_PCI
|
||||
int i;
|
||||
#endif
|
||||
|
||||
model = of_get_property(dp, "model", NULL);
|
||||
if (!model)
|
||||
|
@ -124,11 +124,6 @@ EXPORT_SYMBOL(__write_lock);
|
||||
EXPORT_SYMBOL(__write_unlock);
|
||||
EXPORT_SYMBOL(__write_trylock);
|
||||
|
||||
#if defined(CONFIG_MCOUNT)
|
||||
extern void _mcount(void);
|
||||
EXPORT_SYMBOL(_mcount);
|
||||
#endif
|
||||
|
||||
/* CPU online map and active count. */
|
||||
EXPORT_SYMBOL(cpu_online_map);
|
||||
EXPORT_SYMBOL(phys_cpu_present_map);
|
||||
@ -136,6 +131,11 @@ EXPORT_SYMBOL(phys_cpu_present_map);
|
||||
EXPORT_SYMBOL(smp_call_function);
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
#if defined(CONFIG_MCOUNT)
|
||||
extern void _mcount(void);
|
||||
EXPORT_SYMBOL(_mcount);
|
||||
#endif
|
||||
|
||||
EXPORT_SYMBOL(sparc64_get_clock_tick);
|
||||
|
||||
/* semaphores */
|
||||
|
@ -788,12 +788,15 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id
|
||||
if (!regs)
|
||||
return -ENOMEM;
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
if (!strcmp(model, "ds1287") ||
|
||||
!strcmp(model, "m5819") ||
|
||||
!strcmp(model, "m5819p") ||
|
||||
!strcmp(model, "m5823")) {
|
||||
ds1287_regs = (unsigned long) regs;
|
||||
} else if (model[5] == '0' && model[6] == '2') {
|
||||
} else
|
||||
#endif
|
||||
if (model[5] == '0' && model[6] == '2') {
|
||||
mstk48t02_regs = regs;
|
||||
} else if(model[5] == '0' && model[6] == '8') {
|
||||
mstk48t08_regs = regs;
|
||||
|
@ -1836,9 +1836,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
|
||||
pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev < 0x20) {
|
||||
printk(KERN_ERR PFX "pci dev %s (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
|
||||
pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
|
||||
printk(KERN_ERR PFX "Try the \"8139too\" driver instead.\n");
|
||||
dev_err(&pdev->dev,
|
||||
"This (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
|
||||
pdev->vendor, pdev->device, pci_rev);
|
||||
dev_err(&pdev->dev, "Try the \"8139too\" driver instead.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -1876,14 +1877,13 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
pciaddr = pci_resource_start(pdev, 1);
|
||||
if (!pciaddr) {
|
||||
rc = -EIO;
|
||||
printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n",
|
||||
pci_name(pdev));
|
||||
dev_err(&pdev->dev, "no MMIO resource\n");
|
||||
goto err_out_res;
|
||||
}
|
||||
if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) {
|
||||
rc = -EIO;
|
||||
printk(KERN_ERR PFX "MMIO resource (%llx) too small on pci dev %s\n",
|
||||
(unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev));
|
||||
dev_err(&pdev->dev, "MMIO resource (%llx) too small\n",
|
||||
(unsigned long long)pci_resource_len(pdev, 1));
|
||||
goto err_out_res;
|
||||
}
|
||||
|
||||
@ -1897,14 +1897,15 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
|
||||
if (rc) {
|
||||
printk(KERN_ERR PFX "No usable DMA configuration, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev,
|
||||
"No usable DMA configuration, aborting.\n");
|
||||
goto err_out_res;
|
||||
}
|
||||
rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
|
||||
if (rc) {
|
||||
printk(KERN_ERR PFX "No usable consistent DMA configuration, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev,
|
||||
"No usable consistent DMA configuration, "
|
||||
"aborting.\n");
|
||||
goto err_out_res;
|
||||
}
|
||||
}
|
||||
@ -1915,9 +1916,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
regs = ioremap(pciaddr, CP_REGS_SIZE);
|
||||
if (!regs) {
|
||||
rc = -EIO;
|
||||
printk(KERN_ERR PFX "Cannot map PCI MMIO (%llx@%llx) on pci dev %s\n",
|
||||
(unsigned long long)pci_resource_len(pdev, 1),
|
||||
(unsigned long long)pciaddr, pci_name(pdev));
|
||||
dev_err(&pdev->dev, "Cannot map PCI MMIO (%lx@%lx)\n",
|
||||
(unsigned long long)pci_resource_len(pdev, 1),
|
||||
(unsigned long long)pciaddr);
|
||||
goto err_out_res;
|
||||
}
|
||||
dev->base_addr = (unsigned long) regs;
|
||||
@ -1986,7 +1987,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
/* enable busmastering and memory-write-invalidate */
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (cp->wol_enabled) cp_set_d3_state (cp);
|
||||
if (cp->wol_enabled)
|
||||
cp_set_d3_state (cp);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -2011,7 +2013,8 @@ static void cp_remove_one (struct pci_dev *pdev)
|
||||
BUG_ON(!dev);
|
||||
unregister_netdev(dev);
|
||||
iounmap(cp->regs);
|
||||
if (cp->wol_enabled) pci_set_power_state (pdev, PCI_D0);
|
||||
if (cp->wol_enabled)
|
||||
pci_set_power_state (pdev, PCI_D0);
|
||||
pci_release_regions(pdev);
|
||||
pci_clear_mwi(pdev);
|
||||
pci_disable_device(pdev);
|
||||
|
@ -768,7 +768,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
|
||||
/* dev and priv zeroed in alloc_etherdev */
|
||||
dev = alloc_etherdev (sizeof (*tp));
|
||||
if (dev == NULL) {
|
||||
printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pci_name(pdev));
|
||||
dev_err(&pdev->dev, "Unable to alloc new net device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
SET_MODULE_OWNER(dev);
|
||||
@ -800,31 +800,31 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
|
||||
#ifdef USE_IO_OPS
|
||||
/* make sure PCI base addr 0 is PIO */
|
||||
if (!(pio_flags & IORESOURCE_IO)) {
|
||||
printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pci_name(pdev));
|
||||
dev_err(&pdev->dev, "region #0 not a PIO resource, aborting\n");
|
||||
rc = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
/* check for weird/broken PCI region reporting */
|
||||
if (pio_len < RTL_MIN_IO_SIZE) {
|
||||
printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pci_name(pdev));
|
||||
dev_err(&pdev->dev, "Invalid PCI I/O region size(s), aborting\n");
|
||||
rc = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
#else
|
||||
/* make sure PCI base addr 1 is MMIO */
|
||||
if (!(mmio_flags & IORESOURCE_MEM)) {
|
||||
printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pci_name(pdev));
|
||||
dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
|
||||
rc = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
if (mmio_len < RTL_MIN_IO_SIZE) {
|
||||
printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pci_name(pdev));
|
||||
dev_err(&pdev->dev, "Invalid PCI mem region size(s), aborting\n");
|
||||
rc = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = pci_request_regions (pdev, "8139too");
|
||||
rc = pci_request_regions (pdev, DRV_NAME);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
disable_dev_on_err = 1;
|
||||
@ -835,7 +835,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
|
||||
#ifdef USE_IO_OPS
|
||||
ioaddr = ioport_map(pio_start, pio_len);
|
||||
if (!ioaddr) {
|
||||
printk (KERN_ERR PFX "%s: cannot map PIO, aborting\n", pci_name(pdev));
|
||||
dev_err(&pdev->dev, "cannot map PIO, aborting\n");
|
||||
rc = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
@ -846,7 +846,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
|
||||
/* ioremap MMIO region */
|
||||
ioaddr = pci_iomap(pdev, 1, 0);
|
||||
if (ioaddr == NULL) {
|
||||
printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev));
|
||||
dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
|
||||
rc = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
@ -860,8 +860,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
|
||||
|
||||
/* check for missing/broken hardware */
|
||||
if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
|
||||
printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n",
|
||||
pci_name(pdev));
|
||||
dev_err(&pdev->dev, "Chip not responding, ignoring board\n");
|
||||
rc = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
@ -875,9 +874,10 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
|
||||
}
|
||||
|
||||
/* if unknown chip, assume array element #0, original RTL-8139 in this case */
|
||||
printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n",
|
||||
pci_name(pdev));
|
||||
printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pci_name(pdev), RTL_R32 (TxConfig));
|
||||
dev_printk (KERN_DEBUG, &pdev->dev,
|
||||
"unknown chip version, assuming RTL-8139\n");
|
||||
dev_printk (KERN_DEBUG, &pdev->dev,
|
||||
"TxConfig = 0x%lx\n", RTL_R32 (TxConfig));
|
||||
tp->chipset = 0;
|
||||
|
||||
match:
|
||||
@ -954,9 +954,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
|
||||
pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
|
||||
printk(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
|
||||
pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
|
||||
printk(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n");
|
||||
dev_info(&pdev->dev,
|
||||
"This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
|
||||
pdev->vendor, pdev->device, pci_rev);
|
||||
dev_info(&pdev->dev,
|
||||
"Use the \"8139cp\" driver for improved performance and stability.\n");
|
||||
}
|
||||
|
||||
i = rtl8139_init_board (pdev, &dev);
|
||||
|
@ -2120,13 +2120,14 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Cannot enable PCI device, "
|
||||
dev_err(&pdev->dev, "Cannot enable PCI device, "
|
||||
"aborting.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
|
||||
printk(KERN_ERR PFX "Cannot find proper PCI device "
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot find proper PCI device "
|
||||
"base address, aborting.\n");
|
||||
err = -ENODEV;
|
||||
goto err_out_disable_pdev;
|
||||
@ -2134,8 +2135,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
|
||||
|
||||
err = pci_request_regions(pdev, DRV_MODULE_NAME);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Cannot obtain PCI resources, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot obtain PCI resources, aborting.\n");
|
||||
goto err_out_disable_pdev;
|
||||
}
|
||||
|
||||
@ -2143,15 +2144,13 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
|
||||
|
||||
err = pci_set_dma_mask(pdev, (u64) B44_DMA_MASK);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "No usable DMA configuration, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
|
||||
goto err_out_free_res;
|
||||
}
|
||||
|
||||
err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "No usable DMA configuration, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
|
||||
goto err_out_free_res;
|
||||
}
|
||||
|
||||
@ -2160,7 +2159,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
|
||||
|
||||
dev = alloc_etherdev(sizeof(*bp));
|
||||
if (!dev) {
|
||||
printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
|
||||
dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
|
||||
err = -ENOMEM;
|
||||
goto err_out_free_res;
|
||||
}
|
||||
@ -2181,8 +2180,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
|
||||
|
||||
bp->regs = ioremap(b44reg_base, b44reg_len);
|
||||
if (bp->regs == 0UL) {
|
||||
printk(KERN_ERR PFX "Cannot map device registers, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
|
||||
err = -ENOMEM;
|
||||
goto err_out_free_dev;
|
||||
}
|
||||
@ -2212,8 +2210,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
|
||||
|
||||
err = b44_get_invariants(bp);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Problem fetching invariants of chip, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev,
|
||||
"Problem fetching invariants of chip, aborting.\n");
|
||||
goto err_out_iounmap;
|
||||
}
|
||||
|
||||
@ -2233,8 +2231,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
|
||||
|
||||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Cannot register net device, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
|
||||
goto err_out_iounmap;
|
||||
}
|
||||
|
||||
|
@ -5575,20 +5575,20 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
|
||||
/* enable device (incl. PCI PM wakeup), and bus-mastering */
|
||||
rc = pci_enable_device(pdev);
|
||||
if (rc) {
|
||||
printk(KERN_ERR PFX "Cannot enable PCI device, aborting.");
|
||||
dev_err(&pdev->dev, "Cannot enable PCI device, aborting.");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
|
||||
printk(KERN_ERR PFX "Cannot find PCI device base address, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot find PCI device base address, aborting.\n");
|
||||
rc = -ENODEV;
|
||||
goto err_out_disable;
|
||||
}
|
||||
|
||||
rc = pci_request_regions(pdev, DRV_MODULE_NAME);
|
||||
if (rc) {
|
||||
printk(KERN_ERR PFX "Cannot obtain PCI resources, aborting.\n");
|
||||
dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
|
||||
goto err_out_disable;
|
||||
}
|
||||
|
||||
@ -5596,15 +5596,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
|
||||
|
||||
bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
|
||||
if (bp->pm_cap == 0) {
|
||||
printk(KERN_ERR PFX "Cannot find power management capability, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot find power management capability, aborting.\n");
|
||||
rc = -EIO;
|
||||
goto err_out_release;
|
||||
}
|
||||
|
||||
bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
|
||||
if (bp->pcix_cap == 0) {
|
||||
printk(KERN_ERR PFX "Cannot find PCIX capability, aborting.\n");
|
||||
dev_err(&pdev->dev, "Cannot find PCIX capability, aborting.\n");
|
||||
rc = -EIO;
|
||||
goto err_out_release;
|
||||
}
|
||||
@ -5612,14 +5612,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
|
||||
if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
|
||||
bp->flags |= USING_DAC_FLAG;
|
||||
if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
|
||||
printk(KERN_ERR PFX "pci_set_consistent_dma_mask "
|
||||
"failed, aborting.\n");
|
||||
dev_err(&pdev->dev,
|
||||
"pci_set_consistent_dma_mask failed, aborting.\n");
|
||||
rc = -EIO;
|
||||
goto err_out_release;
|
||||
}
|
||||
}
|
||||
else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
|
||||
printk(KERN_ERR PFX "System does not support DMA, aborting.\n");
|
||||
dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
|
||||
rc = -EIO;
|
||||
goto err_out_release;
|
||||
}
|
||||
@ -5639,7 +5639,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
|
||||
bp->regview = ioremap_nocache(dev->base_addr, mem_len);
|
||||
|
||||
if (!bp->regview) {
|
||||
printk(KERN_ERR PFX "Cannot map register space, aborting.\n");
|
||||
dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
|
||||
rc = -ENOMEM;
|
||||
goto err_out_release;
|
||||
}
|
||||
@ -5711,8 +5711,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
|
||||
else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
|
||||
!(bp->flags & PCIX_FLAG)) {
|
||||
|
||||
printk(KERN_ERR PFX "5706 A1 can only be used in a PCIX bus, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev,
|
||||
"5706 A1 can only be used in a PCIX bus, aborting.\n");
|
||||
goto err_out_unmap;
|
||||
}
|
||||
|
||||
@ -5733,7 +5733,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
|
||||
|
||||
if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
|
||||
BNX2_DEV_INFO_SIGNATURE_MAGIC) {
|
||||
printk(KERN_ERR PFX "Firmware not running, aborting.\n");
|
||||
dev_err(&pdev->dev, "Firmware not running, aborting.\n");
|
||||
rc = -ENODEV;
|
||||
goto err_out_unmap;
|
||||
}
|
||||
@ -5895,7 +5895,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
#endif
|
||||
|
||||
if ((rc = register_netdev(dev))) {
|
||||
printk(KERN_ERR PFX "Cannot register net device\n");
|
||||
dev_err(&pdev->dev, "Cannot register net device\n");
|
||||
if (bp->regview)
|
||||
iounmap(bp->regview);
|
||||
pci_release_regions(pdev);
|
||||
|
@ -4887,13 +4887,12 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Cannot enable PCI device, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
|
||||
printk(KERN_ERR PFX "Cannot find proper PCI device "
|
||||
dev_err(&pdev->dev, "Cannot find proper PCI device "
|
||||
"base address, aborting.\n");
|
||||
err = -ENODEV;
|
||||
goto err_out_disable_pdev;
|
||||
@ -4901,7 +4900,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
|
||||
|
||||
dev = alloc_etherdev(sizeof(*cp));
|
||||
if (!dev) {
|
||||
printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
|
||||
dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
|
||||
err = -ENOMEM;
|
||||
goto err_out_disable_pdev;
|
||||
}
|
||||
@ -4910,8 +4909,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
|
||||
|
||||
err = pci_request_regions(pdev, dev->name);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Cannot obtain PCI resources, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
|
||||
goto err_out_free_netdev;
|
||||
}
|
||||
pci_set_master(pdev);
|
||||
@ -4941,7 +4939,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
|
||||
if (pci_write_config_byte(pdev,
|
||||
PCI_CACHE_LINE_SIZE,
|
||||
cas_cacheline_size)) {
|
||||
printk(KERN_ERR PFX "Could not set PCI cache "
|
||||
dev_err(&pdev->dev, "Could not set PCI cache "
|
||||
"line size\n");
|
||||
goto err_write_cacheline;
|
||||
}
|
||||
@ -4955,7 +4953,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
|
||||
err = pci_set_consistent_dma_mask(pdev,
|
||||
DMA_64BIT_MASK);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR PFX "Unable to obtain 64-bit DMA "
|
||||
dev_err(&pdev->dev, "Unable to obtain 64-bit DMA "
|
||||
"for consistent allocations\n");
|
||||
goto err_out_free_res;
|
||||
}
|
||||
@ -4963,7 +4961,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
|
||||
} else {
|
||||
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "No usable DMA configuration, "
|
||||
dev_err(&pdev->dev, "No usable DMA configuration, "
|
||||
"aborting.\n");
|
||||
goto err_out_free_res;
|
||||
}
|
||||
@ -5023,8 +5021,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
|
||||
/* give us access to cassini registers */
|
||||
cp->regs = pci_iomap(pdev, 0, casreg_len);
|
||||
if (cp->regs == 0UL) {
|
||||
printk(KERN_ERR PFX "Cannot map device registers, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
|
||||
goto err_out_free_res;
|
||||
}
|
||||
cp->casreg_len = casreg_len;
|
||||
@ -5040,8 +5037,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
|
||||
pci_alloc_consistent(pdev, sizeof(struct cas_init_block),
|
||||
&cp->block_dvma);
|
||||
if (!cp->init_block) {
|
||||
printk(KERN_ERR PFX "Cannot allocate init block, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev, "Cannot allocate init block, aborting.\n");
|
||||
goto err_out_iounmap;
|
||||
}
|
||||
|
||||
@ -5085,8 +5081,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
|
||||
dev->features |= NETIF_F_HIGHDMA;
|
||||
|
||||
if (register_netdev(dev)) {
|
||||
printk(KERN_ERR PFX "Cannot register net device, "
|
||||
"aborting.\n");
|
||||
dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
|
||||
goto err_out_free_consistent;
|
||||
}
|
||||
|
||||
|
@ -703,8 +703,8 @@ static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id,
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
lance_interrupt(const int irq, void *dev_id, struct pt_regs *regs)
|
||||
static irqreturn_t lance_interrupt(const int irq, void *dev_id,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
struct net_device *dev = (struct net_device *) dev_id;
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
@ -1253,7 +1253,7 @@ static int __init dec_lance_init(const int type, const int slot)
|
||||
return 0;
|
||||
|
||||
err_out_free_dev:
|
||||
kfree(dev);
|
||||
free_netdev(dev);
|
||||
|
||||
err_out:
|
||||
return ret;
|
||||
@ -1299,6 +1299,7 @@ static void __exit dec_lance_cleanup(void)
|
||||
while (root_lance_dev) {
|
||||
struct net_device *dev = root_lance_dev;
|
||||
struct lance_private *lp = netdev_priv(dev);
|
||||
|
||||
unregister_netdev(dev);
|
||||
#ifdef CONFIG_TC
|
||||
if (lp->slot >= 0)
|
||||
|
@ -9,49 +9,10 @@
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
*/
|
||||
/*
|
||||
Rev Date Description
|
||||
==========================================================================
|
||||
0.01 2001/05/03 Created DL2000-based linux driver
|
||||
0.02 2001/05/21 Added VLAN and hardware checksum support.
|
||||
1.00 2001/06/26 Added jumbo frame support.
|
||||
1.01 2001/08/21 Added two parameters, rx_coalesce and rx_timeout.
|
||||
1.02 2001/10/08 Supported fiber media.
|
||||
Added flow control parameters.
|
||||
1.03 2001/10/12 Changed the default media to 1000mbps_fd for
|
||||
the fiber devices.
|
||||
1.04 2001/11/08 Fixed Tx stopped when tx very busy.
|
||||
1.05 2001/11/22 Fixed Tx stopped when unidirectional tx busy.
|
||||
1.06 2001/12/13 Fixed disconnect bug at 10Mbps mode.
|
||||
Fixed tx_full flag incorrect.
|
||||
Added tx_coalesce paramter.
|
||||
1.07 2002/01/03 Fixed miscount of RX frame error.
|
||||
1.08 2002/01/17 Fixed the multicast bug.
|
||||
1.09 2002/03/07 Move rx-poll-now to re-fill loop.
|
||||
Added rio_timer() to watch rx buffers.
|
||||
1.10 2002/04/16 Fixed miscount of carrier error.
|
||||
1.11 2002/05/23 Added ISR schedule scheme
|
||||
Fixed miscount of rx frame error for DGE-550SX.
|
||||
Fixed VLAN bug.
|
||||
1.12 2002/06/13 Lock tx_coalesce=1 on 10/100Mbps mode.
|
||||
1.13 2002/08/13 1. Fix disconnection (many tx:carrier/rx:frame
|
||||
errs) with some mainboards.
|
||||
2. Use definition "DRV_NAME" "DRV_VERSION"
|
||||
"DRV_RELDATE" for flexibility.
|
||||
1.14 2002/08/14 Support ethtool.
|
||||
1.15 2002/08/27 Changed the default media to Auto-Negotiation
|
||||
for the fiber devices.
|
||||
1.16 2002/09/04 More power down time for fiber devices auto-
|
||||
negotiation.
|
||||
Fix disconnect bug after ifup and ifdown.
|
||||
1.17 2002/10/03 Fix RMON statistics overflow.
|
||||
Always use I/O mapping to access eeprom,
|
||||
avoid system freezing with some chipsets.
|
||||
|
||||
*/
|
||||
#define DRV_NAME "D-Link DL2000-based linux driver"
|
||||
#define DRV_VERSION "v1.17b"
|
||||
#define DRV_RELDATE "2006/03/10"
|
||||
#define DRV_VERSION "v1.18"
|
||||
#define DRV_RELDATE "2006/06/27"
|
||||
#include "dl2k.h"
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
|
@ -555,12 +555,12 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
|
||||
|
||||
if (!request_region(pci_resource_start(pdev, 1),
|
||||
pci_resource_len(pdev, 1), "eepro100")) {
|
||||
printk (KERN_ERR "eepro100: cannot reserve I/O ports\n");
|
||||
dev_err(&pdev->dev, "eepro100: cannot reserve I/O ports\n");
|
||||
goto err_out_none;
|
||||
}
|
||||
if (!request_mem_region(pci_resource_start(pdev, 0),
|
||||
pci_resource_len(pdev, 0), "eepro100")) {
|
||||
printk (KERN_ERR "eepro100: cannot reserve MMIO region\n");
|
||||
dev_err(&pdev->dev, "eepro100: cannot reserve MMIO region\n");
|
||||
goto err_out_free_pio_region;
|
||||
}
|
||||
|
||||
@ -573,7 +573,7 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
|
||||
|
||||
ioaddr = pci_iomap(pdev, pci_bar, 0);
|
||||
if (!ioaddr) {
|
||||
printk (KERN_ERR "eepro100: cannot remap IO\n");
|
||||
dev_err(&pdev->dev, "eepro100: cannot remap IO\n");
|
||||
goto err_out_free_mmio_region;
|
||||
}
|
||||
|
||||
|
@ -19,62 +19,15 @@
|
||||
|
||||
Information and updates available at
|
||||
http://www.scyld.com/network/epic100.html
|
||||
[this link no longer provides anything useful -jgarzik]
|
||||
|
||||
---------------------------------------------------------------------
|
||||
|
||||
Linux kernel-specific changes:
|
||||
|
||||
LK1.1.2 (jgarzik):
|
||||
* Merge becker version 1.09 (4/08/2000)
|
||||
|
||||
LK1.1.3:
|
||||
* Major bugfix to 1.09 driver (Francis Romieu)
|
||||
|
||||
LK1.1.4 (jgarzik):
|
||||
* Merge becker test version 1.09 (5/29/2000)
|
||||
|
||||
LK1.1.5:
|
||||
* Fix locking (jgarzik)
|
||||
* Limit 83c175 probe to ethernet-class PCI devices (rgooch)
|
||||
|
||||
LK1.1.6:
|
||||
* Merge becker version 1.11
|
||||
* Move pci_enable_device before any PCI BAR len checks
|
||||
|
||||
LK1.1.7:
|
||||
* { fill me in }
|
||||
|
||||
LK1.1.8:
|
||||
* ethtool driver info support (jgarzik)
|
||||
|
||||
LK1.1.9:
|
||||
* ethtool media get/set support (jgarzik)
|
||||
|
||||
LK1.1.10:
|
||||
* revert MII transceiver init change (jgarzik)
|
||||
|
||||
LK1.1.11:
|
||||
* implement ETHTOOL_[GS]SET, _NWAY_RST, _[GS]MSGLVL, _GLINK (jgarzik)
|
||||
* replace some MII-related magic numbers with constants
|
||||
|
||||
LK1.1.12:
|
||||
* fix power-up sequence
|
||||
|
||||
LK1.1.13:
|
||||
* revert version 1.1.12, power-up sequence "fix"
|
||||
|
||||
LK1.1.14 (Kryzsztof Halasa):
|
||||
* fix spurious bad initializations
|
||||
* pound phy a la SMSC's app note on the subject
|
||||
|
||||
AC1.1.14ac
|
||||
* fix power up/down for ethtool that broke in 1.11
|
||||
|
||||
*/
|
||||
|
||||
#define DRV_NAME "epic100"
|
||||
#define DRV_VERSION "1.11+LK1.1.14+AC1.1.14"
|
||||
#define DRV_RELDATE "June 2, 2004"
|
||||
#define DRV_VERSION "2.0"
|
||||
#define DRV_RELDATE "June 27, 2006"
|
||||
|
||||
/* The user-configurable values.
|
||||
These may be modified when a driver module is loaded.*/
|
||||
@ -204,19 +157,15 @@ typedef enum {
|
||||
|
||||
struct epic_chip_info {
|
||||
const char *name;
|
||||
int io_size; /* Needed for I/O region check or ioremap(). */
|
||||
int drv_flags; /* Driver use, intended as capability flags. */
|
||||
};
|
||||
|
||||
|
||||
/* indexed by chip_t */
|
||||
static const struct epic_chip_info pci_id_tbl[] = {
|
||||
{ "SMSC EPIC/100 83c170",
|
||||
EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN },
|
||||
{ "SMSC EPIC/100 83c170",
|
||||
EPIC_TOTAL_SIZE, TYPE2_INTR },
|
||||
{ "SMSC EPIC/C 83c175",
|
||||
EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN },
|
||||
{ "SMSC EPIC/100 83c170", TYPE2_INTR | NO_MII | MII_PWRDWN },
|
||||
{ "SMSC EPIC/100 83c170", TYPE2_INTR },
|
||||
{ "SMSC EPIC/C 83c175", TYPE2_INTR | MII_PWRDWN },
|
||||
};
|
||||
|
||||
|
||||
@ -385,8 +334,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
|
||||
goto out;
|
||||
irq = pdev->irq;
|
||||
|
||||
if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) {
|
||||
printk (KERN_ERR "card %d: no PCI region space\n", card_idx);
|
||||
if (pci_resource_len(pdev, 0) < EPIC_TOTAL_SIZE) {
|
||||
dev_err(&pdev->dev, "no PCI region space\n");
|
||||
ret = -ENODEV;
|
||||
goto err_out_disable;
|
||||
}
|
||||
@ -401,7 +350,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
|
||||
|
||||
dev = alloc_etherdev(sizeof (*ep));
|
||||
if (!dev) {
|
||||
printk (KERN_ERR "card %d: no memory for eth device\n", card_idx);
|
||||
dev_err(&pdev->dev, "no memory for eth device\n");
|
||||
goto err_out_free_res;
|
||||
}
|
||||
SET_MODULE_OWNER(dev);
|
||||
@ -413,7 +362,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
|
||||
ioaddr = pci_resource_start (pdev, 1);
|
||||
ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
|
||||
if (!ioaddr) {
|
||||
printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx);
|
||||
dev_err(&pdev->dev, "ioremap failed\n");
|
||||
goto err_out_free_netdev;
|
||||
}
|
||||
#endif
|
||||
@ -473,8 +422,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
|
||||
((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4));
|
||||
|
||||
if (debug > 2) {
|
||||
printk(KERN_DEBUG DRV_NAME "(%s): EEPROM contents\n",
|
||||
pci_name(pdev));
|
||||
dev_printk(KERN_DEBUG, &pdev->dev, "EEPROM contents:\n");
|
||||
for (i = 0; i < 64; i++)
|
||||
printk(" %4.4x%s", read_eeprom(ioaddr, i),
|
||||
i % 16 == 15 ? "\n" : "");
|
||||
@ -496,21 +444,23 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
|
||||
int mii_status = mdio_read(dev, phy, MII_BMSR);
|
||||
if (mii_status != 0xffff && mii_status != 0x0000) {
|
||||
ep->phys[phy_idx++] = phy;
|
||||
printk(KERN_INFO DRV_NAME "(%s): MII transceiver #%d control "
|
||||
"%4.4x status %4.4x.\n",
|
||||
pci_name(pdev), phy, mdio_read(dev, phy, 0), mii_status);
|
||||
dev_info(&pdev->dev,
|
||||
"MII transceiver #%d control "
|
||||
"%4.4x status %4.4x.\n",
|
||||
phy, mdio_read(dev, phy, 0), mii_status);
|
||||
}
|
||||
}
|
||||
ep->mii_phy_cnt = phy_idx;
|
||||
if (phy_idx != 0) {
|
||||
phy = ep->phys[0];
|
||||
ep->mii.advertising = mdio_read(dev, phy, MII_ADVERTISE);
|
||||
printk(KERN_INFO DRV_NAME "(%s): Autonegotiation advertising %4.4x link "
|
||||
dev_info(&pdev->dev,
|
||||
"Autonegotiation advertising %4.4x link "
|
||||
"partner %4.4x.\n",
|
||||
pci_name(pdev), ep->mii.advertising, mdio_read(dev, phy, 5));
|
||||
ep->mii.advertising, mdio_read(dev, phy, 5));
|
||||
} else if ( ! (ep->chip_flags & NO_MII)) {
|
||||
printk(KERN_WARNING DRV_NAME "(%s): ***WARNING***: No MII transceiver found!\n",
|
||||
pci_name(pdev));
|
||||
dev_warn(&pdev->dev,
|
||||
"***WARNING***: No MII transceiver found!\n");
|
||||
/* Use the known PHY address of the EPII. */
|
||||
ep->phys[0] = 3;
|
||||
}
|
||||
@ -525,8 +475,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
|
||||
/* The lower four bits are the media type. */
|
||||
if (duplex) {
|
||||
ep->mii.force_media = ep->mii.full_duplex = 1;
|
||||
printk(KERN_INFO DRV_NAME "(%s): Forced full duplex operation requested.\n",
|
||||
pci_name(pdev));
|
||||
dev_info(&pdev->dev, "Forced full duplex requested.\n");
|
||||
}
|
||||
dev->if_port = ep->default_port = option;
|
||||
|
||||
|
@ -124,7 +124,9 @@ MODULE_PARM_DESC(multicast_filter_limit, "fealnx maximum number of filtered mult
|
||||
MODULE_PARM_DESC(options, "fealnx: Bits 0-3: media type, bit 17: full duplex");
|
||||
MODULE_PARM_DESC(full_duplex, "fealnx full duplex setting(s) (1)");
|
||||
|
||||
#define MIN_REGION_SIZE 136
|
||||
enum {
|
||||
MIN_REGION_SIZE = 136,
|
||||
};
|
||||
|
||||
/* A chip capabilities table, matching the entries in pci_tbl[] above. */
|
||||
enum chip_capability_flags {
|
||||
@ -146,14 +148,13 @@ enum phy_type_flags {
|
||||
|
||||
struct chip_info {
|
||||
char *chip_name;
|
||||
int io_size;
|
||||
int flags;
|
||||
};
|
||||
|
||||
static const struct chip_info skel_netdrv_tbl[] = {
|
||||
{"100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR},
|
||||
{"100/10M Ethernet PCI Adapter", 136, HAS_CHIP_XCVR},
|
||||
{"1000/100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR},
|
||||
static const struct chip_info skel_netdrv_tbl[] __devinitdata = {
|
||||
{ "100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
|
||||
{ "100/10M Ethernet PCI Adapter", HAS_CHIP_XCVR },
|
||||
{ "1000/100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
|
||||
};
|
||||
|
||||
/* Offsets to the Command and Status Registers. */
|
||||
@ -504,13 +505,14 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
|
||||
|
||||
len = pci_resource_len(pdev, bar);
|
||||
if (len < MIN_REGION_SIZE) {
|
||||
printk(KERN_ERR "%s: region size %ld too small, aborting\n",
|
||||
boardname, len);
|
||||
dev_err(&pdev->dev,
|
||||
"region size %ld too small, aborting\n", len);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
i = pci_request_regions(pdev, boardname);
|
||||
if (i) return i;
|
||||
if (i)
|
||||
return i;
|
||||
|
||||
irq = pdev->irq;
|
||||
|
||||
@ -576,9 +578,9 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
|
||||
|
||||
if (mii_status != 0xffff && mii_status != 0x0000) {
|
||||
np->phys[phy_idx++] = phy;
|
||||
printk(KERN_INFO
|
||||
"%s: MII PHY found at address %d, status "
|
||||
"0x%4.4x.\n", dev->name, phy, mii_status);
|
||||
dev_info(&pdev->dev,
|
||||
"MII PHY found at address %d, status "
|
||||
"0x%4.4x.\n", phy, mii_status);
|
||||
/* get phy type */
|
||||
{
|
||||
unsigned int data;
|
||||
@ -601,10 +603,10 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
|
||||
}
|
||||
|
||||
np->mii_cnt = phy_idx;
|
||||
if (phy_idx == 0) {
|
||||
printk(KERN_WARNING "%s: MII PHY not found -- this device may "
|
||||
"not operate correctly.\n", dev->name);
|
||||
}
|
||||
if (phy_idx == 0)
|
||||
dev_warn(&pdev->dev,
|
||||
"MII PHY not found -- this device may "
|
||||
"not operate correctly.\n");
|
||||
} else {
|
||||
np->phys[0] = 32;
|
||||
/* 89/6/23 add, (begin) */
|
||||
@ -630,7 +632,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
|
||||
np->mii.full_duplex = full_duplex[card_idx];
|
||||
|
||||
if (np->mii.full_duplex) {
|
||||
printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
|
||||
dev_info(&pdev->dev, "Media type forced to Full Duplex.\n");
|
||||
/* 89/6/13 add, (begin) */
|
||||
// if (np->PHYType==MarvellPHY)
|
||||
if ((np->PHYType == MarvellPHY) || (np->PHYType == LevelOnePHY)) {
|
||||
|
@ -699,7 +699,6 @@ static int __init gt96100_probe1(struct pci_dev *pci, int port_num)
|
||||
memset(gp, 0, sizeof(*gp)); // clear it
|
||||
|
||||
gp->port_num = port_num;
|
||||
gp->io_size = GT96100_ETH_IO_SIZE;
|
||||
gp->port_offset = port_num * GT96100_ETH_IO_SIZE;
|
||||
gp->phy_addr = phy_addr;
|
||||
gp->chip_rev = chip_rev;
|
||||
@ -1531,7 +1530,7 @@ static void gt96100_cleanup_module(void)
|
||||
+ sizeof(gt96100_td_t) * TX_RING_SIZE,
|
||||
gp->rx_ring);
|
||||
free_netdev(gtif->dev);
|
||||
release_region(gtif->iobase, gp->io_size);
|
||||
release_region(gtif->iobase, GT96100_ETH_IO_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -331,7 +331,6 @@ struct gt96100_private {
|
||||
mib_counters_t mib;
|
||||
struct net_device_stats stats;
|
||||
|
||||
int io_size;
|
||||
int port_num; // 0 or 1
|
||||
int chip_rev;
|
||||
u32 port_offset;
|
||||
@ -340,7 +339,6 @@ struct gt96100_private {
|
||||
u32 last_psr; // last value of the port status register
|
||||
|
||||
int options; /* User-settable misc. driver options. */
|
||||
int drv_flags;
|
||||
struct timer_list timer;
|
||||
spinlock_t lock; /* Serialise access to device */
|
||||
};
|
||||
|
@ -20,22 +20,15 @@
|
||||
|
||||
Support and updates available at
|
||||
http://www.scyld.com/network/hamachi.html
|
||||
[link no longer provides useful info -jgarzik]
|
||||
or
|
||||
http://www.parl.clemson.edu/~keithu/hamachi.html
|
||||
|
||||
|
||||
|
||||
Linux kernel changelog:
|
||||
|
||||
LK1.0.1:
|
||||
- fix lack of pci_dev<->dev association
|
||||
- ethtool support (jgarzik)
|
||||
|
||||
*/
|
||||
|
||||
#define DRV_NAME "hamachi"
|
||||
#define DRV_VERSION "1.01+LK1.0.1"
|
||||
#define DRV_RELDATE "5/18/2001"
|
||||
#define DRV_VERSION "2.0"
|
||||
#define DRV_RELDATE "June 27, 2006"
|
||||
|
||||
|
||||
/* A few user-configurable values. */
|
||||
@ -608,7 +601,8 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
|
||||
pci_set_master(pdev);
|
||||
|
||||
i = pci_request_regions(pdev, DRV_NAME);
|
||||
if (i) return i;
|
||||
if (i)
|
||||
return i;
|
||||
|
||||
irq = pdev->irq;
|
||||
ioaddr = ioremap(base, 0x400);
|
||||
|
@ -188,7 +188,6 @@ struct myri10ge_priv {
|
||||
int vendor_specific_offset;
|
||||
u32 devctl;
|
||||
u16 msi_flags;
|
||||
u32 pm_state[16];
|
||||
u32 read_dma;
|
||||
u32 write_dma;
|
||||
u32 read_write_dma;
|
||||
@ -1289,6 +1288,7 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
|
||||
"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
|
||||
"tx_heartbeat_errors", "tx_window_errors",
|
||||
/* device-specific stats */
|
||||
"tx_boundary", "WC", "irq", "MSI",
|
||||
"read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
|
||||
"serial_number", "tx_pkt_start", "tx_pkt_done",
|
||||
"tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt",
|
||||
@ -1327,6 +1327,10 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
|
||||
for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
|
||||
data[i] = ((unsigned long *)&mgp->stats)[i];
|
||||
|
||||
data[i++] = (unsigned int)mgp->tx.boundary;
|
||||
data[i++] = (unsigned int)(mgp->mtrr >= 0);
|
||||
data[i++] = (unsigned int)mgp->pdev->irq;
|
||||
data[i++] = (unsigned int)mgp->msi_enabled;
|
||||
data[i++] = (unsigned int)mgp->read_dma;
|
||||
data[i++] = (unsigned int)mgp->write_dma;
|
||||
data[i++] = (unsigned int)mgp->read_write_dma;
|
||||
@ -2197,8 +2201,6 @@ static int myri10ge_change_mtu(struct net_device *dev, int new_mtu)
|
||||
* any other device, except if forced with myri10ge_ecrc_enable > 1.
|
||||
*/
|
||||
|
||||
#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_PCIE 0x005d
|
||||
|
||||
static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
|
||||
{
|
||||
struct pci_dev *bridge = mgp->pdev->bus->self;
|
||||
@ -2737,11 +2739,10 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
dev_err(&pdev->dev, "register_netdev failed: %d\n", status);
|
||||
goto abort_with_irq;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "myri10ge: %s: %s IRQ %d, tx bndry %d, fw %s, WC %s\n",
|
||||
netdev->name, (mgp->msi_enabled ? "MSI" : "xPIC"),
|
||||
pdev->irq, mgp->tx.boundary, mgp->fw_name,
|
||||
(mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
|
||||
dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
|
||||
(mgp->msi_enabled ? "MSI" : "xPIC"),
|
||||
pdev->irq, mgp->tx.boundary, mgp->fw_name,
|
||||
(mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -20,120 +20,9 @@
|
||||
|
||||
Support information and updates available at
|
||||
http://www.scyld.com/network/netsemi.html
|
||||
[link no longer provides useful info -jgarzik]
|
||||
|
||||
|
||||
Linux kernel modifications:
|
||||
|
||||
Version 1.0.1:
|
||||
- Spinlock fixes
|
||||
- Bug fixes and better intr performance (Tjeerd)
|
||||
Version 1.0.2:
|
||||
- Now reads correct MAC address from eeprom
|
||||
Version 1.0.3:
|
||||
- Eliminate redundant priv->tx_full flag
|
||||
- Call netif_start_queue from dev->tx_timeout
|
||||
- wmb() in start_tx() to flush data
|
||||
- Update Tx locking
|
||||
- Clean up PCI enable (davej)
|
||||
Version 1.0.4:
|
||||
- Merge Donald Becker's natsemi.c version 1.07
|
||||
Version 1.0.5:
|
||||
- { fill me in }
|
||||
Version 1.0.6:
|
||||
* ethtool support (jgarzik)
|
||||
* Proper initialization of the card (which sometimes
|
||||
fails to occur and leaves the card in a non-functional
|
||||
state). (uzi)
|
||||
|
||||
* Some documented register settings to optimize some
|
||||
of the 100Mbit autodetection circuitry in rev C cards. (uzi)
|
||||
|
||||
* Polling of the PHY intr for stuff like link state
|
||||
change and auto- negotiation to finally work properly. (uzi)
|
||||
|
||||
* One-liner removal of a duplicate declaration of
|
||||
netdev_error(). (uzi)
|
||||
|
||||
Version 1.0.7: (Manfred Spraul)
|
||||
* pci dma
|
||||
* SMP locking update
|
||||
* full reset added into tx_timeout
|
||||
* correct multicast hash generation (both big and little endian)
|
||||
[copied from a natsemi driver version
|
||||
from Myrio Corporation, Greg Smith]
|
||||
* suspend/resume
|
||||
|
||||
version 1.0.8 (Tim Hockin <thockin@sun.com>)
|
||||
* ETHTOOL_* support
|
||||
* Wake on lan support (Erik Gilling)
|
||||
* MXDMA fixes for serverworks
|
||||
* EEPROM reload
|
||||
|
||||
version 1.0.9 (Manfred Spraul)
|
||||
* Main change: fix lack of synchronize
|
||||
netif_close/netif_suspend against a last interrupt
|
||||
or packet.
|
||||
* do not enable superflous interrupts (e.g. the
|
||||
drivers relies on TxDone - TxIntr not needed)
|
||||
* wait that the hardware has really stopped in close
|
||||
and suspend.
|
||||
* workaround for the (at least) gcc-2.95.1 compiler
|
||||
problem. Also simplifies the code a bit.
|
||||
* disable_irq() in tx_timeout - needed to protect
|
||||
against rx interrupts.
|
||||
* stop the nic before switching into silent rx mode
|
||||
for wol (required according to docu).
|
||||
|
||||
version 1.0.10:
|
||||
* use long for ee_addr (various)
|
||||
* print pointers properly (DaveM)
|
||||
* include asm/irq.h (?)
|
||||
|
||||
version 1.0.11:
|
||||
* check and reset if PHY errors appear (Adrian Sun)
|
||||
* WoL cleanup (Tim Hockin)
|
||||
* Magic number cleanup (Tim Hockin)
|
||||
* Don't reload EEPROM on every reset (Tim Hockin)
|
||||
* Save and restore EEPROM state across reset (Tim Hockin)
|
||||
* MDIO Cleanup (Tim Hockin)
|
||||
* Reformat register offsets/bits (jgarzik)
|
||||
|
||||
version 1.0.12:
|
||||
* ETHTOOL_* further support (Tim Hockin)
|
||||
|
||||
version 1.0.13:
|
||||
* ETHTOOL_[G]EEPROM support (Tim Hockin)
|
||||
|
||||
version 1.0.13:
|
||||
* crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
|
||||
|
||||
version 1.0.14:
|
||||
* Cleanup some messages and autoneg in ethtool (Tim Hockin)
|
||||
|
||||
version 1.0.15:
|
||||
* Get rid of cable_magic flag
|
||||
* use new (National provided) solution for cable magic issue
|
||||
|
||||
version 1.0.16:
|
||||
* call netdev_rx() for RxErrors (Manfred Spraul)
|
||||
* formatting and cleanups
|
||||
* change options and full_duplex arrays to be zero
|
||||
initialized
|
||||
* enable only the WoL and PHY interrupts in wol mode
|
||||
|
||||
version 1.0.17:
|
||||
* only do cable_magic on 83815 and early 83816 (Tim Hockin)
|
||||
* create a function for rx refill (Manfred Spraul)
|
||||
* combine drain_ring and init_ring (Manfred Spraul)
|
||||
* oom handling (Manfred Spraul)
|
||||
* hands_off instead of playing with netif_device_{de,a}ttach
|
||||
(Manfred Spraul)
|
||||
* be sure to write the MAC back to the chip (Manfred Spraul)
|
||||
* lengthen EEPROM timeout, and always warn about timeouts
|
||||
(Manfred Spraul)
|
||||
* comments update (Manfred)
|
||||
* do the right thing on a phy-reset (Manfred and Tim)
|
||||
|
||||
TODO:
|
||||
* big endian support with CFG:BEM instead of cpu_to_le32
|
||||
*/
|
||||
@ -165,8 +54,8 @@
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#define DRV_NAME "natsemi"
|
||||
#define DRV_VERSION "1.07+LK1.0.17"
|
||||
#define DRV_RELDATE "Sep 27, 2002"
|
||||
#define DRV_VERSION "2.0"
|
||||
#define DRV_RELDATE "June 27, 2006"
|
||||
|
||||
#define RX_OFFSET 2
|
||||
|
||||
|
@ -231,12 +231,12 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
|
||||
irq = pdev->irq;
|
||||
|
||||
if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {
|
||||
printk (KERN_ERR PFX "no I/O resource at PCI BAR #0\n");
|
||||
dev_err(&pdev->dev, "no I/O resource at PCI BAR #0\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) {
|
||||
printk (KERN_ERR PFX "I/O resource 0x%x @ 0x%lx busy\n",
|
||||
dev_err(&pdev->dev, "I/O resource 0x%x @ 0x%lx busy\n",
|
||||
NE_IO_EXTENT, ioaddr);
|
||||
return -EBUSY;
|
||||
}
|
||||
@ -263,7 +263,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
|
||||
/* Allocate net_device, dev->priv; fill in 8390 specific dev fields. */
|
||||
dev = alloc_ei_netdev();
|
||||
if (!dev) {
|
||||
printk (KERN_ERR PFX "cannot allocate ethernet device\n");
|
||||
dev_err(&pdev->dev, "cannot allocate ethernet device\n");
|
||||
goto err_out_free_res;
|
||||
}
|
||||
SET_MODULE_OWNER(dev);
|
||||
@ -281,7 +281,8 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
|
||||
while ((inb(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
|
||||
/* Limit wait: '2' avoids jiffy roll-over. */
|
||||
if (jiffies - reset_start_time > 2) {
|
||||
printk(KERN_ERR PFX "Card failure (no reset ack).\n");
|
||||
dev_err(&pdev->dev,
|
||||
"Card failure (no reset ack).\n");
|
||||
goto err_out_free_netdev;
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,12 @@
|
||||
/* ni5010.c: A network driver for the MiCom-Interlan NI5010 ethercard.
|
||||
*
|
||||
* Copyright 1996,1997 Jan-Pascal van Best and Andreas Mohr.
|
||||
* Copyright 1996,1997,2006 Jan-Pascal van Best and Andreas Mohr.
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
* The authors may be reached as:
|
||||
* jvbest@wi.leidenuniv.nl a.mohr@mailto.de
|
||||
* or by snail mail as
|
||||
* Jan-Pascal van Best Andreas Mohr
|
||||
* Klikspaanweg 58-4 Stauferstr. 6
|
||||
* 2324 LZ Leiden D-71272 Renningen
|
||||
* The Netherlands Germany
|
||||
* janpascal@vanbest.org andi@lisas.de
|
||||
*
|
||||
* Sources:
|
||||
* Donald Becker's "skeleton.c"
|
||||
@ -27,8 +22,9 @@
|
||||
* 970503 v0.93: Fixed auto-irq failure on warm reboot (JB)
|
||||
* 970623 v1.00: First kernel version (AM)
|
||||
* 970814 v1.01: Added detection of onboard receive buffer size (AM)
|
||||
* 060611 v1.02: slight cleanup: email addresses, driver modernization.
|
||||
* Bugs:
|
||||
* - None known...
|
||||
* - not SMP-safe (no locking of I/O accesses)
|
||||
* - Note that you have to patch ifconfig for the new /proc/net/dev
|
||||
* format. It gives incorrect stats otherwise.
|
||||
*
|
||||
@ -39,7 +35,7 @@
|
||||
* Complete merge with Andreas' driver
|
||||
* Implement ring buffers (Is this useful? You can't squeeze
|
||||
* too many packet in a 2k buffer!)
|
||||
* Implement DMA (Again, is this useful? Some docs says DMA is
|
||||
* Implement DMA (Again, is this useful? Some docs say DMA is
|
||||
* slower than programmed I/O)
|
||||
*
|
||||
* Compile with:
|
||||
@ -47,7 +43,7 @@
|
||||
* -DMODULE -c ni5010.c
|
||||
*
|
||||
* Insert with e.g.:
|
||||
* insmod ni5010.o io=0x300 irq=5
|
||||
* insmod ni5010.ko io=0x300 irq=5
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -69,15 +65,15 @@
|
||||
|
||||
#include "ni5010.h"
|
||||
|
||||
static const char *boardname = "NI5010";
|
||||
static char *version =
|
||||
"ni5010.c: v1.00 06/23/97 Jan-Pascal van Best and Andreas Mohr\n";
|
||||
static const char boardname[] = "NI5010";
|
||||
static char version[] __initdata =
|
||||
"ni5010.c: v1.02 20060611 Jan-Pascal van Best and Andreas Mohr\n";
|
||||
|
||||
/* bufsize_rcv == 0 means autoprobing */
|
||||
static unsigned int bufsize_rcv;
|
||||
|
||||
#define jumpered_interrupts /* IRQ line jumpered on board */
|
||||
#undef jumpered_dma /* No DMA used */
|
||||
#define JUMPERED_INTERRUPTS /* IRQ line jumpered on board */
|
||||
#undef JUMPERED_DMA /* No DMA used */
|
||||
#undef FULL_IODETECT /* Only detect in portlist */
|
||||
|
||||
#ifndef FULL_IODETECT
|
||||
@ -281,7 +277,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
|
||||
|
||||
PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
|
||||
|
||||
#ifdef jumpered_interrupts
|
||||
#ifdef JUMPERED_INTERRUPTS
|
||||
if (dev->irq == 0xff)
|
||||
;
|
||||
else if (dev->irq < 2) {
|
||||
@ -305,7 +301,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
|
||||
} else if (dev->irq == 2) {
|
||||
dev->irq = 9;
|
||||
}
|
||||
#endif /* jumpered_irq */
|
||||
#endif /* JUMPERED_INTERRUPTS */
|
||||
PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name));
|
||||
|
||||
/* DMA is not supported (yet?), so no use detecting it */
|
||||
@ -334,7 +330,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
|
||||
outw(0, IE_GP); /* Point GP at start of packet */
|
||||
outb(0, IE_RBUF); /* set buffer byte 0 to 0 again */
|
||||
}
|
||||
printk("// bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
|
||||
printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
|
||||
memset(dev->priv, 0, sizeof(struct ni5010_local));
|
||||
|
||||
dev->open = ni5010_open;
|
||||
@ -354,11 +350,9 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
|
||||
outb(0xff, EDLC_XCLR); /* Kill all pending xmt interrupts */
|
||||
|
||||
printk(KERN_INFO "%s: NI5010 found at 0x%x, using IRQ %d", dev->name, ioaddr, dev->irq);
|
||||
if (dev->dma) printk(" & DMA %d", dev->dma);
|
||||
if (dev->dma)
|
||||
printk(" & DMA %d", dev->dma);
|
||||
printk(".\n");
|
||||
|
||||
printk(KERN_INFO "Join the NI5010 driver development team!\n");
|
||||
printk(KERN_INFO "Mail to a.mohr@mailto.de or jvbest@wi.leidenuniv.nl\n");
|
||||
return 0;
|
||||
out:
|
||||
release_region(dev->base_addr, NI5010_IO_EXTENT);
|
||||
@ -371,7 +365,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
|
||||
*
|
||||
* This routine should set everything up anew at each open, even
|
||||
* registers that "should" only need to be set once at boot, so that
|
||||
* there is non-reboot way to recover if something goes wrong.
|
||||
* there is a non-reboot way to recover if something goes wrong.
|
||||
*/
|
||||
|
||||
static int ni5010_open(struct net_device *dev)
|
||||
@ -390,13 +384,13 @@ static int ni5010_open(struct net_device *dev)
|
||||
* Always allocate the DMA channel after the IRQ,
|
||||
* and clean up on failure.
|
||||
*/
|
||||
#ifdef jumpered_dma
|
||||
#ifdef JUMPERED_DMA
|
||||
if (request_dma(dev->dma, cardname)) {
|
||||
printk(KERN_WARNING "%s: Cannot get dma %#2x\n", dev->name, dev->dma);
|
||||
free_irq(dev->irq, NULL);
|
||||
return -EAGAIN;
|
||||
}
|
||||
#endif /* jumpered_dma */
|
||||
#endif /* JUMPERED_DMA */
|
||||
|
||||
PRINTK3((KERN_DEBUG "%s: passed open() #2\n", dev->name));
|
||||
/* Reset the hardware here. Don't forget to set the station address. */
|
||||
@ -633,7 +627,7 @@ static int ni5010_close(struct net_device *dev)
|
||||
int ioaddr = dev->base_addr;
|
||||
|
||||
PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name));
|
||||
#ifdef jumpered_interrupts
|
||||
#ifdef JUMPERED_INTERRUPTS
|
||||
free_irq(dev->irq, NULL);
|
||||
#endif
|
||||
/* Put card in held-RESET state */
|
||||
@ -771,7 +765,7 @@ module_param(irq, int, 0);
|
||||
MODULE_PARM_DESC(io, "ni5010 I/O base address");
|
||||
MODULE_PARM_DESC(irq, "ni5010 IRQ number");
|
||||
|
||||
int init_module(void)
|
||||
static int __init ni5010_init_module(void)
|
||||
{
|
||||
PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname));
|
||||
/*
|
||||
@ -792,13 +786,15 @@ int init_module(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_module(void)
|
||||
static void __exit ni5010_cleanup_module(void)
|
||||
{
|
||||
PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname));
|
||||
unregister_netdev(dev_ni5010);
|
||||
release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT);
|
||||
free_netdev(dev_ni5010);
|
||||
}
|
||||
module_init(ni5010_init_module);
|
||||
module_exit(ni5010_cleanup_module);
|
||||
#endif /* MODULE */
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
@ -803,7 +803,7 @@ static int ns83820_setup_rx(struct net_device *ndev)
|
||||
|
||||
writel(dev->IMR_cache, dev->base + IMR);
|
||||
writel(1, dev->base + IER);
|
||||
spin_unlock_irq(&dev->misc_lock);
|
||||
spin_unlock(&dev->misc_lock);
|
||||
|
||||
kick_rx(ndev);
|
||||
|
||||
@ -1012,8 +1012,6 @@ static void do_tx_done(struct net_device *ndev)
|
||||
struct ns83820 *dev = PRIV(ndev);
|
||||
u32 cmdsts, tx_done_idx, *desc;
|
||||
|
||||
spin_lock_irq(&dev->tx_lock);
|
||||
|
||||
dprintk("do_tx_done(%p)\n", ndev);
|
||||
tx_done_idx = dev->tx_done_idx;
|
||||
desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
|
||||
@ -1069,7 +1067,6 @@ static void do_tx_done(struct net_device *ndev)
|
||||
netif_start_queue(ndev);
|
||||
netif_wake_queue(ndev);
|
||||
}
|
||||
spin_unlock_irq(&dev->tx_lock);
|
||||
}
|
||||
|
||||
static void ns83820_cleanup_tx(struct ns83820 *dev)
|
||||
@ -1281,11 +1278,13 @@ static struct ethtool_ops ops = {
|
||||
.get_link = ns83820_get_link
|
||||
};
|
||||
|
||||
/* this function is called in irq context from the ISR */
|
||||
static void ns83820_mib_isr(struct ns83820 *dev)
|
||||
{
|
||||
spin_lock(&dev->misc_lock);
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&dev->misc_lock, flags);
|
||||
ns83820_update_stats(dev);
|
||||
spin_unlock(&dev->misc_lock);
|
||||
spin_unlock_irqrestore(&dev->misc_lock, flags);
|
||||
}
|
||||
|
||||
static void ns83820_do_isr(struct net_device *ndev, u32 isr);
|
||||
@ -1307,6 +1306,8 @@ static irqreturn_t ns83820_irq(int foo, void *data, struct pt_regs *regs)
|
||||
static void ns83820_do_isr(struct net_device *ndev, u32 isr)
|
||||
{
|
||||
struct ns83820 *dev = PRIV(ndev);
|
||||
unsigned long flags;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC))
|
||||
Dprintk("odd isr? 0x%08x\n", isr);
|
||||
@ -1321,10 +1322,10 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
|
||||
if ((ISR_RXDESC | ISR_RXOK) & isr) {
|
||||
prefetch(dev->rx_info.next_rx_desc);
|
||||
|
||||
spin_lock_irq(&dev->misc_lock);
|
||||
spin_lock_irqsave(&dev->misc_lock, flags);
|
||||
dev->IMR_cache &= ~(ISR_RXDESC | ISR_RXOK);
|
||||
writel(dev->IMR_cache, dev->base + IMR);
|
||||
spin_unlock_irq(&dev->misc_lock);
|
||||
spin_unlock_irqrestore(&dev->misc_lock, flags);
|
||||
|
||||
tasklet_schedule(&dev->rx_tasklet);
|
||||
//rx_irq(ndev);
|
||||
@ -1370,16 +1371,18 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
|
||||
* work has accumulated
|
||||
*/
|
||||
if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) {
|
||||
spin_lock_irqsave(&dev->tx_lock, flags);
|
||||
do_tx_done(ndev);
|
||||
spin_unlock_irqrestore(&dev->tx_lock, flags);
|
||||
|
||||
/* Disable TxOk if there are no outstanding tx packets.
|
||||
*/
|
||||
if ((dev->tx_done_idx == dev->tx_free_idx) &&
|
||||
(dev->IMR_cache & ISR_TXOK)) {
|
||||
spin_lock_irq(&dev->misc_lock);
|
||||
spin_lock_irqsave(&dev->misc_lock, flags);
|
||||
dev->IMR_cache &= ~ISR_TXOK;
|
||||
writel(dev->IMR_cache, dev->base + IMR);
|
||||
spin_unlock_irq(&dev->misc_lock);
|
||||
spin_unlock_irqrestore(&dev->misc_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1390,10 +1393,10 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
|
||||
* nature are expected, we must enable TxOk.
|
||||
*/
|
||||
if ((ISR_TXIDLE & isr) && (dev->tx_done_idx != dev->tx_free_idx)) {
|
||||
spin_lock_irq(&dev->misc_lock);
|
||||
spin_lock_irqsave(&dev->misc_lock, flags);
|
||||
dev->IMR_cache |= ISR_TXOK;
|
||||
writel(dev->IMR_cache, dev->base + IMR);
|
||||
spin_unlock_irq(&dev->misc_lock);
|
||||
spin_unlock_irqrestore(&dev->misc_lock, flags);
|
||||
}
|
||||
|
||||
/* MIB interrupt: one of the statistics counters is about to overflow */
|
||||
@ -1455,7 +1458,7 @@ static void ns83820_tx_timeout(struct net_device *ndev)
|
||||
u32 tx_done_idx, *desc;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
spin_lock_irqsave(&dev->tx_lock, flags);
|
||||
|
||||
tx_done_idx = dev->tx_done_idx;
|
||||
desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
|
||||
@ -1482,7 +1485,7 @@ static void ns83820_tx_timeout(struct net_device *ndev)
|
||||
ndev->name,
|
||||
tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));
|
||||
|
||||
local_irq_restore(flags);
|
||||
spin_unlock_irqrestore(&dev->tx_lock, flags);
|
||||
}
|
||||
|
||||
static void ns83820_tx_watch(unsigned long data)
|
||||
@ -1832,7 +1835,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
|
||||
} else if (!pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
|
||||
using_dac = 0;
|
||||
} else {
|
||||
printk(KERN_WARNING "ns83820.c: pci_set_dma_mask failed!\n");
|
||||
dev_warn(&pci_dev->dev, "pci_set_dma_mask failed!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -1855,7 +1858,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
|
||||
|
||||
err = pci_enable_device(pci_dev);
|
||||
if (err) {
|
||||
printk(KERN_INFO "ns83820: pci_enable_dev failed: %d\n", err);
|
||||
dev_info(&pci_dev->dev, "pci_enable_dev failed: %d\n", err);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
@ -1884,8 +1887,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
|
||||
err = request_irq(pci_dev->irq, ns83820_irq, IRQF_SHARED,
|
||||
DRV_NAME, ndev);
|
||||
if (err) {
|
||||
printk(KERN_INFO "ns83820: unable to register irq %d\n",
|
||||
pci_dev->irq);
|
||||
dev_info(&pci_dev->dev, "unable to register irq %d, err %d\n",
|
||||
pci_dev->irq, err);
|
||||
goto out_disable;
|
||||
}
|
||||
|
||||
@ -1899,7 +1902,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
|
||||
rtnl_lock();
|
||||
err = dev_alloc_name(ndev, ndev->name);
|
||||
if (err < 0) {
|
||||
printk(KERN_INFO "ns83820: unable to get netdev name: %d\n", err);
|
||||
dev_info(&pci_dev->dev, "unable to get netdev name: %d\n", err);
|
||||
goto out_free_irq;
|
||||
}
|
||||
|
||||
|
@ -601,7 +601,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
|
||||
/* dev zeroed in alloc_etherdev */
|
||||
dev = alloc_etherdev (sizeof (*tp));
|
||||
if (dev == NULL) {
|
||||
printk (KERN_ERR PFX "unable to alloc new ethernet\n");
|
||||
dev_err(&pdev->dev, "unable to alloc new ethernet\n");
|
||||
DPRINTK ("EXIT, returning -ENOMEM\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -631,14 +631,14 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
|
||||
|
||||
/* make sure PCI base addr 0 is PIO */
|
||||
if (!(pio_flags & IORESOURCE_IO)) {
|
||||
printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n");
|
||||
dev_err(&pdev->dev, "region #0 not a PIO resource, aborting\n");
|
||||
rc = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* make sure PCI base addr 1 is MMIO */
|
||||
if (!(mmio_flags & IORESOURCE_MEM)) {
|
||||
printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n");
|
||||
dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
|
||||
rc = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
@ -646,12 +646,12 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
|
||||
/* check for weird/broken PCI region reporting */
|
||||
if ((pio_len < NETDRV_MIN_IO_SIZE) ||
|
||||
(mmio_len < NETDRV_MIN_IO_SIZE)) {
|
||||
printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
|
||||
dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n");
|
||||
rc = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
rc = pci_request_regions (pdev, "pci-skeleton");
|
||||
rc = pci_request_regions (pdev, MODNAME);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
|
||||
@ -663,7 +663,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
|
||||
/* ioremap MMIO region */
|
||||
ioaddr = ioremap (mmio_start, mmio_len);
|
||||
if (ioaddr == NULL) {
|
||||
printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");
|
||||
dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
|
||||
rc = -EIO;
|
||||
goto err_out_free_res;
|
||||
}
|
||||
@ -699,9 +699,10 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
|
||||
}
|
||||
|
||||
/* if unknown chip, assume array element #0, original RTL-8139 in this case */
|
||||
printk (KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming RTL-8139\n",
|
||||
pci_name(pdev));
|
||||
printk (KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n", pci_name(pdev), NETDRV_R32 (TxConfig));
|
||||
dev_printk (KERN_DEBUG, &pdev->dev,
|
||||
"unknown chip version, assuming RTL-8139\n");
|
||||
dev_printk (KERN_DEBUG, &pdev->dev, "TxConfig = 0x%lx\n",
|
||||
NETDRV_R32 (TxConfig));
|
||||
tp->chipset = 0;
|
||||
|
||||
match:
|
||||
|
@ -58,18 +58,15 @@ static const char *const version =
|
||||
* PCI device identifiers for "new style" Linux PCI Device Drivers
|
||||
*/
|
||||
static struct pci_device_id pcnet32_pci_tbl[] = {
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME), },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE), },
|
||||
|
||||
/*
|
||||
* Adapters that were sold with IBM's RS/6000 or pSeries hardware have
|
||||
* the incorrect vendor id.
|
||||
*/
|
||||
{ PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, 0},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE),
|
||||
.class = (PCI_CLASS_NETWORK_ETHERNET << 8), .class_mask = 0xffff00, },
|
||||
|
||||
{ } /* terminate list */
|
||||
};
|
||||
@ -188,6 +185,23 @@ static int homepna[MAX_UNITS];
|
||||
|
||||
#define PCNET32_TOTAL_SIZE 0x20
|
||||
|
||||
#define CSR0 0
|
||||
#define CSR0_INIT 0x1
|
||||
#define CSR0_START 0x2
|
||||
#define CSR0_STOP 0x4
|
||||
#define CSR0_TXPOLL 0x8
|
||||
#define CSR0_INTEN 0x40
|
||||
#define CSR0_IDON 0x0100
|
||||
#define CSR0_NORMAL (CSR0_START | CSR0_INTEN)
|
||||
#define PCNET32_INIT_LOW 1
|
||||
#define PCNET32_INIT_HIGH 2
|
||||
#define CSR3 3
|
||||
#define CSR4 4
|
||||
#define CSR5 5
|
||||
#define CSR5_SUSPEND 0x0001
|
||||
#define CSR15 15
|
||||
#define PCNET32_MC_FILTER 8
|
||||
|
||||
/* The PCNET32 Rx and Tx ring descriptors. */
|
||||
struct pcnet32_rx_head {
|
||||
u32 base;
|
||||
@ -277,7 +291,6 @@ struct pcnet32_private {
|
||||
u32 phymask;
|
||||
};
|
||||
|
||||
static void pcnet32_probe_vlbus(void);
|
||||
static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
|
||||
static int pcnet32_probe1(unsigned long, int, struct pci_dev *);
|
||||
static int pcnet32_open(struct net_device *);
|
||||
@ -419,6 +432,238 @@ static struct pcnet32_access pcnet32_dwio = {
|
||||
.reset = pcnet32_dwio_reset
|
||||
};
|
||||
|
||||
static void pcnet32_netif_stop(struct net_device *dev)
|
||||
{
|
||||
dev->trans_start = jiffies;
|
||||
netif_poll_disable(dev);
|
||||
netif_tx_disable(dev);
|
||||
}
|
||||
|
||||
static void pcnet32_netif_start(struct net_device *dev)
|
||||
{
|
||||
netif_wake_queue(dev);
|
||||
netif_poll_enable(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate space for the new sized tx ring.
|
||||
* Free old resources
|
||||
* Save new resources.
|
||||
* Any failure keeps old resources.
|
||||
* Must be called with lp->lock held.
|
||||
*/
|
||||
static void pcnet32_realloc_tx_ring(struct net_device *dev,
|
||||
struct pcnet32_private *lp,
|
||||
unsigned int size)
|
||||
{
|
||||
dma_addr_t new_ring_dma_addr;
|
||||
dma_addr_t *new_dma_addr_list;
|
||||
struct pcnet32_tx_head *new_tx_ring;
|
||||
struct sk_buff **new_skb_list;
|
||||
|
||||
pcnet32_purge_tx_ring(dev);
|
||||
|
||||
new_tx_ring = pci_alloc_consistent(lp->pci_dev,
|
||||
sizeof(struct pcnet32_tx_head) *
|
||||
(1 << size),
|
||||
&new_ring_dma_addr);
|
||||
if (new_tx_ring == NULL) {
|
||||
if (netif_msg_drv(lp))
|
||||
printk("\n" KERN_ERR
|
||||
"%s: Consistent memory allocation failed.\n",
|
||||
dev->name);
|
||||
return;
|
||||
}
|
||||
memset(new_tx_ring, 0, sizeof(struct pcnet32_tx_head) * (1 << size));
|
||||
|
||||
new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
|
||||
GFP_ATOMIC);
|
||||
if (!new_dma_addr_list) {
|
||||
if (netif_msg_drv(lp))
|
||||
printk("\n" KERN_ERR
|
||||
"%s: Memory allocation failed.\n", dev->name);
|
||||
goto free_new_tx_ring;
|
||||
}
|
||||
|
||||
new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
|
||||
GFP_ATOMIC);
|
||||
if (!new_skb_list) {
|
||||
if (netif_msg_drv(lp))
|
||||
printk("\n" KERN_ERR
|
||||
"%s: Memory allocation failed.\n", dev->name);
|
||||
goto free_new_lists;
|
||||
}
|
||||
|
||||
kfree(lp->tx_skbuff);
|
||||
kfree(lp->tx_dma_addr);
|
||||
pci_free_consistent(lp->pci_dev,
|
||||
sizeof(struct pcnet32_tx_head) *
|
||||
lp->tx_ring_size, lp->tx_ring,
|
||||
lp->tx_ring_dma_addr);
|
||||
|
||||
lp->tx_ring_size = (1 << size);
|
||||
lp->tx_mod_mask = lp->tx_ring_size - 1;
|
||||
lp->tx_len_bits = (size << 12);
|
||||
lp->tx_ring = new_tx_ring;
|
||||
lp->tx_ring_dma_addr = new_ring_dma_addr;
|
||||
lp->tx_dma_addr = new_dma_addr_list;
|
||||
lp->tx_skbuff = new_skb_list;
|
||||
return;
|
||||
|
||||
free_new_lists:
|
||||
kfree(new_dma_addr_list);
|
||||
free_new_tx_ring:
|
||||
pci_free_consistent(lp->pci_dev,
|
||||
sizeof(struct pcnet32_tx_head) *
|
||||
(1 << size),
|
||||
new_tx_ring,
|
||||
new_ring_dma_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate space for the new sized rx ring.
|
||||
* Re-use old receive buffers.
|
||||
* alloc extra buffers
|
||||
* free unneeded buffers
|
||||
* free unneeded buffers
|
||||
* Save new resources.
|
||||
* Any failure keeps old resources.
|
||||
* Must be called with lp->lock held.
|
||||
*/
|
||||
static void pcnet32_realloc_rx_ring(struct net_device *dev,
|
||||
struct pcnet32_private *lp,
|
||||
unsigned int size)
|
||||
{
|
||||
dma_addr_t new_ring_dma_addr;
|
||||
dma_addr_t *new_dma_addr_list;
|
||||
struct pcnet32_rx_head *new_rx_ring;
|
||||
struct sk_buff **new_skb_list;
|
||||
int new, overlap;
|
||||
|
||||
new_rx_ring = pci_alloc_consistent(lp->pci_dev,
|
||||
sizeof(struct pcnet32_rx_head) *
|
||||
(1 << size),
|
||||
&new_ring_dma_addr);
|
||||
if (new_rx_ring == NULL) {
|
||||
if (netif_msg_drv(lp))
|
||||
printk("\n" KERN_ERR
|
||||
"%s: Consistent memory allocation failed.\n",
|
||||
dev->name);
|
||||
return;
|
||||
}
|
||||
memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size));
|
||||
|
||||
new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
|
||||
GFP_ATOMIC);
|
||||
if (!new_dma_addr_list) {
|
||||
if (netif_msg_drv(lp))
|
||||
printk("\n" KERN_ERR
|
||||
"%s: Memory allocation failed.\n", dev->name);
|
||||
goto free_new_rx_ring;
|
||||
}
|
||||
|
||||
new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
|
||||
GFP_ATOMIC);
|
||||
if (!new_skb_list) {
|
||||
if (netif_msg_drv(lp))
|
||||
printk("\n" KERN_ERR
|
||||
"%s: Memory allocation failed.\n", dev->name);
|
||||
goto free_new_lists;
|
||||
}
|
||||
|
||||
/* first copy the current receive buffers */
|
||||
overlap = min(size, lp->rx_ring_size);
|
||||
for (new = 0; new < overlap; new++) {
|
||||
new_rx_ring[new] = lp->rx_ring[new];
|
||||
new_dma_addr_list[new] = lp->rx_dma_addr[new];
|
||||
new_skb_list[new] = lp->rx_skbuff[new];
|
||||
}
|
||||
/* now allocate any new buffers needed */
|
||||
for (; new < size; new++ ) {
|
||||
struct sk_buff *rx_skbuff;
|
||||
new_skb_list[new] = dev_alloc_skb(PKT_BUF_SZ);
|
||||
if (!(rx_skbuff = new_skb_list[new])) {
|
||||
/* keep the original lists and buffers */
|
||||
if (netif_msg_drv(lp))
|
||||
printk(KERN_ERR
|
||||
"%s: pcnet32_realloc_rx_ring dev_alloc_skb failed.\n",
|
||||
dev->name);
|
||||
goto free_all_new;
|
||||
}
|
||||
skb_reserve(rx_skbuff, 2);
|
||||
|
||||
new_dma_addr_list[new] =
|
||||
pci_map_single(lp->pci_dev, rx_skbuff->data,
|
||||
PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
|
||||
new_rx_ring[new].base = (u32) le32_to_cpu(new_dma_addr_list[new]);
|
||||
new_rx_ring[new].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
|
||||
new_rx_ring[new].status = le16_to_cpu(0x8000);
|
||||
}
|
||||
/* and free any unneeded buffers */
|
||||
for (; new < lp->rx_ring_size; new++) {
|
||||
if (lp->rx_skbuff[new]) {
|
||||
pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[new],
|
||||
PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
|
||||
dev_kfree_skb(lp->rx_skbuff[new]);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(lp->rx_skbuff);
|
||||
kfree(lp->rx_dma_addr);
|
||||
pci_free_consistent(lp->pci_dev,
|
||||
sizeof(struct pcnet32_rx_head) *
|
||||
lp->rx_ring_size, lp->rx_ring,
|
||||
lp->rx_ring_dma_addr);
|
||||
|
||||
lp->rx_ring_size = (1 << size);
|
||||
lp->rx_mod_mask = lp->rx_ring_size - 1;
|
||||
lp->rx_len_bits = (size << 4);
|
||||
lp->rx_ring = new_rx_ring;
|
||||
lp->rx_ring_dma_addr = new_ring_dma_addr;
|
||||
lp->rx_dma_addr = new_dma_addr_list;
|
||||
lp->rx_skbuff = new_skb_list;
|
||||
return;
|
||||
|
||||
free_all_new:
|
||||
for (; --new >= lp->rx_ring_size; ) {
|
||||
if (new_skb_list[new]) {
|
||||
pci_unmap_single(lp->pci_dev, new_dma_addr_list[new],
|
||||
PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
|
||||
dev_kfree_skb(new_skb_list[new]);
|
||||
}
|
||||
}
|
||||
kfree(new_skb_list);
|
||||
free_new_lists:
|
||||
kfree(new_dma_addr_list);
|
||||
free_new_rx_ring:
|
||||
pci_free_consistent(lp->pci_dev,
|
||||
sizeof(struct pcnet32_rx_head) *
|
||||
(1 << size),
|
||||
new_rx_ring,
|
||||
new_ring_dma_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
static void pcnet32_purge_rx_ring(struct net_device *dev)
|
||||
{
|
||||
struct pcnet32_private *lp = dev->priv;
|
||||
int i;
|
||||
|
||||
/* free all allocated skbuffs */
|
||||
for (i = 0; i < lp->rx_ring_size; i++) {
|
||||
lp->rx_ring[i].status = 0; /* CPU owns buffer */
|
||||
wmb(); /* Make sure adapter sees owner change */
|
||||
if (lp->rx_skbuff[i]) {
|
||||
pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
|
||||
PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
|
||||
dev_kfree_skb_any(lp->rx_skbuff[i]);
|
||||
}
|
||||
lp->rx_skbuff[i] = NULL;
|
||||
lp->rx_dma_addr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
static void pcnet32_poll_controller(struct net_device *dev)
|
||||
{
|
||||
@ -519,10 +764,10 @@ static void pcnet32_get_ringparam(struct net_device *dev,
|
||||
{
|
||||
struct pcnet32_private *lp = dev->priv;
|
||||
|
||||
ering->tx_max_pending = TX_MAX_RING_SIZE - 1;
|
||||
ering->tx_pending = lp->tx_ring_size - 1;
|
||||
ering->rx_max_pending = RX_MAX_RING_SIZE - 1;
|
||||
ering->rx_pending = lp->rx_ring_size - 1;
|
||||
ering->tx_max_pending = TX_MAX_RING_SIZE;
|
||||
ering->tx_pending = lp->tx_ring_size;
|
||||
ering->rx_max_pending = RX_MAX_RING_SIZE;
|
||||
ering->rx_pending = lp->rx_ring_size;
|
||||
}
|
||||
|
||||
static int pcnet32_set_ringparam(struct net_device *dev,
|
||||
@ -530,56 +775,53 @@ static int pcnet32_set_ringparam(struct net_device *dev,
|
||||
{
|
||||
struct pcnet32_private *lp = dev->priv;
|
||||
unsigned long flags;
|
||||
unsigned int size;
|
||||
ulong ioaddr = dev->base_addr;
|
||||
int i;
|
||||
|
||||
if (ering->rx_mini_pending || ering->rx_jumbo_pending)
|
||||
return -EINVAL;
|
||||
|
||||
if (netif_running(dev))
|
||||
pcnet32_close(dev);
|
||||
pcnet32_netif_stop(dev);
|
||||
|
||||
spin_lock_irqsave(&lp->lock, flags);
|
||||
pcnet32_free_ring(dev);
|
||||
lp->tx_ring_size =
|
||||
min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
|
||||
lp->rx_ring_size =
|
||||
min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
|
||||
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
|
||||
|
||||
size = min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
|
||||
|
||||
/* set the minimum ring size to 4, to allow the loopback test to work
|
||||
* unchanged.
|
||||
*/
|
||||
for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) {
|
||||
if (lp->tx_ring_size <= (1 << i))
|
||||
if (size <= (1 << i))
|
||||
break;
|
||||
}
|
||||
lp->tx_ring_size = (1 << i);
|
||||
lp->tx_mod_mask = lp->tx_ring_size - 1;
|
||||
lp->tx_len_bits = (i << 12);
|
||||
|
||||
if ((1 << i) != lp->tx_ring_size)
|
||||
pcnet32_realloc_tx_ring(dev, lp, i);
|
||||
|
||||
size = min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
|
||||
for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) {
|
||||
if (lp->rx_ring_size <= (1 << i))
|
||||
if (size <= (1 << i))
|
||||
break;
|
||||
}
|
||||
lp->rx_ring_size = (1 << i);
|
||||
lp->rx_mod_mask = lp->rx_ring_size - 1;
|
||||
lp->rx_len_bits = (i << 4);
|
||||
if ((1 << i) != lp->rx_ring_size)
|
||||
pcnet32_realloc_rx_ring(dev, lp, i);
|
||||
|
||||
dev->weight = lp->rx_ring_size / 2;
|
||||
|
||||
if (pcnet32_alloc_ring(dev, dev->name)) {
|
||||
pcnet32_free_ring(dev);
|
||||
spin_unlock_irqrestore(&lp->lock, flags);
|
||||
return -ENOMEM;
|
||||
if (netif_running(dev)) {
|
||||
pcnet32_netif_start(dev);
|
||||
pcnet32_restart(dev, CSR0_NORMAL);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&lp->lock, flags);
|
||||
|
||||
if (pcnet32_debug & NETIF_MSG_DRV)
|
||||
printk(KERN_INFO PFX
|
||||
if (netif_msg_drv(lp))
|
||||
printk(KERN_INFO
|
||||
"%s: Ring Param Settings: RX: %d, TX: %d\n", dev->name,
|
||||
lp->rx_ring_size, lp->tx_ring_size);
|
||||
|
||||
if (netif_running(dev))
|
||||
pcnet32_open(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -633,29 +875,27 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
|
||||
unsigned long flags;
|
||||
unsigned long ticks;
|
||||
|
||||
*data1 = 1; /* status of test, default to fail */
|
||||
rc = 1; /* default to fail */
|
||||
|
||||
if (netif_running(dev))
|
||||
pcnet32_close(dev);
|
||||
|
||||
spin_lock_irqsave(&lp->lock, flags);
|
||||
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
|
||||
|
||||
numbuffs = min(numbuffs, (int)min(lp->rx_ring_size, lp->tx_ring_size));
|
||||
|
||||
/* Reset the PCNET32 */
|
||||
lp->a.reset(ioaddr);
|
||||
lp->a.write_csr(ioaddr, CSR4, 0x0915);
|
||||
|
||||
/* switch pcnet32 to 32bit mode */
|
||||
lp->a.write_bcr(ioaddr, 20, 2);
|
||||
|
||||
lp->init_block.mode =
|
||||
le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
|
||||
lp->init_block.filter[0] = 0;
|
||||
lp->init_block.filter[1] = 0;
|
||||
|
||||
/* purge & init rings but don't actually restart */
|
||||
pcnet32_restart(dev, 0x0000);
|
||||
|
||||
lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
|
||||
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
|
||||
|
||||
/* Initialize Transmit buffers. */
|
||||
size = data_len + 15;
|
||||
@ -697,14 +937,15 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
|
||||
}
|
||||
}
|
||||
|
||||
x = a->read_bcr(ioaddr, 32); /* set internal loopback in BSR32 */
|
||||
x = x | 0x0002;
|
||||
a->write_bcr(ioaddr, 32, x);
|
||||
x = a->read_bcr(ioaddr, 32); /* set internal loopback in BCR32 */
|
||||
a->write_bcr(ioaddr, 32, x | 0x0002);
|
||||
|
||||
lp->a.write_csr(ioaddr, 15, 0x0044); /* set int loopback in CSR15 */
|
||||
/* set int loopback in CSR15 */
|
||||
x = a->read_csr(ioaddr, CSR15) & 0xfffc;
|
||||
lp->a.write_csr(ioaddr, CSR15, x | 0x0044);
|
||||
|
||||
teststatus = le16_to_cpu(0x8000);
|
||||
lp->a.write_csr(ioaddr, 0, 0x0002); /* Set STRT bit */
|
||||
lp->a.write_csr(ioaddr, CSR0, CSR0_START); /* Set STRT bit */
|
||||
|
||||
/* Check status of descriptors */
|
||||
for (x = 0; x < numbuffs; x++) {
|
||||
@ -712,7 +953,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
|
||||
rmb();
|
||||
while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {
|
||||
spin_unlock_irqrestore(&lp->lock, flags);
|
||||
mdelay(1);
|
||||
msleep(1);
|
||||
spin_lock_irqsave(&lp->lock, flags);
|
||||
rmb();
|
||||
ticks++;
|
||||
@ -725,7 +966,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
|
||||
}
|
||||
}
|
||||
|
||||
lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
|
||||
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
|
||||
wmb();
|
||||
if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
|
||||
printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name);
|
||||
@ -758,25 +999,24 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
|
||||
}
|
||||
x++;
|
||||
}
|
||||
if (!rc) {
|
||||
*data1 = 0;
|
||||
}
|
||||
|
||||
clean_up:
|
||||
*data1 = rc;
|
||||
pcnet32_purge_tx_ring(dev);
|
||||
x = a->read_csr(ioaddr, 15) & 0xFFFF;
|
||||
a->write_csr(ioaddr, 15, (x & ~0x0044)); /* reset bits 6 and 2 */
|
||||
|
||||
x = a->read_csr(ioaddr, CSR15);
|
||||
a->write_csr(ioaddr, CSR15, (x & ~0x0044)); /* reset bits 6 and 2 */
|
||||
|
||||
x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
|
||||
x = x & ~0x0002;
|
||||
a->write_bcr(ioaddr, 32, x);
|
||||
|
||||
spin_unlock_irqrestore(&lp->lock, flags);
|
||||
a->write_bcr(ioaddr, 32, (x & ~0x0002));
|
||||
|
||||
if (netif_running(dev)) {
|
||||
spin_unlock_irqrestore(&lp->lock, flags);
|
||||
pcnet32_open(dev);
|
||||
} else {
|
||||
pcnet32_purge_rx_ring(dev);
|
||||
lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
|
||||
spin_unlock_irqrestore(&lp->lock, flags);
|
||||
}
|
||||
|
||||
return (rc);
|
||||
@ -839,6 +1079,43 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* lp->lock must be held.
|
||||
*/
|
||||
static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
|
||||
int can_sleep)
|
||||
{
|
||||
int csr5;
|
||||
struct pcnet32_private *lp = dev->priv;
|
||||
struct pcnet32_access *a = &lp->a;
|
||||
ulong ioaddr = dev->base_addr;
|
||||
int ticks;
|
||||
|
||||
/* set SUSPEND (SPND) - CSR5 bit 0 */
|
||||
csr5 = a->read_csr(ioaddr, CSR5);
|
||||
a->write_csr(ioaddr, CSR5, csr5 | CSR5_SUSPEND);
|
||||
|
||||
/* poll waiting for bit to be set */
|
||||
ticks = 0;
|
||||
while (!(a->read_csr(ioaddr, CSR5) & CSR5_SUSPEND)) {
|
||||
spin_unlock_irqrestore(&lp->lock, *flags);
|
||||
if (can_sleep)
|
||||
msleep(1);
|
||||
else
|
||||
mdelay(1);
|
||||
spin_lock_irqsave(&lp->lock, *flags);
|
||||
ticks++;
|
||||
if (ticks > 200) {
|
||||
if (netif_msg_hw(lp))
|
||||
printk(KERN_DEBUG
|
||||
"%s: Error getting into suspend!\n",
|
||||
dev->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define PCNET32_REGS_PER_PHY 32
|
||||
#define PCNET32_MAX_PHYS 32
|
||||
static int pcnet32_get_regs_len(struct net_device *dev)
|
||||
@ -857,32 +1134,13 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
|
||||
struct pcnet32_private *lp = dev->priv;
|
||||
struct pcnet32_access *a = &lp->a;
|
||||
ulong ioaddr = dev->base_addr;
|
||||
int ticks;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&lp->lock, flags);
|
||||
|
||||
csr0 = a->read_csr(ioaddr, 0);
|
||||
if (!(csr0 & 0x0004)) { /* If not stopped */
|
||||
/* set SUSPEND (SPND) - CSR5 bit 0 */
|
||||
a->write_csr(ioaddr, 5, 0x0001);
|
||||
|
||||
/* poll waiting for bit to be set */
|
||||
ticks = 0;
|
||||
while (!(a->read_csr(ioaddr, 5) & 0x0001)) {
|
||||
spin_unlock_irqrestore(&lp->lock, flags);
|
||||
mdelay(1);
|
||||
spin_lock_irqsave(&lp->lock, flags);
|
||||
ticks++;
|
||||
if (ticks > 200) {
|
||||
if (netif_msg_hw(lp))
|
||||
printk(KERN_DEBUG
|
||||
"%s: Error getting into suspend!\n",
|
||||
dev->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
csr0 = a->read_csr(ioaddr, CSR0);
|
||||
if (!(csr0 & CSR0_STOP)) /* If not stopped */
|
||||
pcnet32_suspend(dev, &flags, 1);
|
||||
|
||||
/* read address PROM */
|
||||
for (i = 0; i < 16; i += 2)
|
||||
@ -919,9 +1177,12 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(csr0 & 0x0004)) { /* If not stopped */
|
||||
if (!(csr0 & CSR0_STOP)) { /* If not stopped */
|
||||
int csr5;
|
||||
|
||||
/* clear SUSPEND (SPND) - CSR5 bit 0 */
|
||||
a->write_csr(ioaddr, 5, 0x0000);
|
||||
csr5 = a->read_csr(ioaddr, CSR5);
|
||||
a->write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&lp->lock, flags);
|
||||
@ -952,7 +1213,7 @@ static struct ethtool_ops pcnet32_ethtool_ops = {
|
||||
/* only probes for non-PCI devices, the rest are handled by
|
||||
* pci_register_driver via pcnet32_probe_pci */
|
||||
|
||||
static void __devinit pcnet32_probe_vlbus(void)
|
||||
static void __devinit pcnet32_probe_vlbus(unsigned int *pcnet32_portlist)
|
||||
{
|
||||
unsigned int *port, ioaddr;
|
||||
|
||||
@ -1436,7 +1697,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
|
||||
lp->tx_ring_size,
|
||||
&lp->tx_ring_dma_addr);
|
||||
if (lp->tx_ring == NULL) {
|
||||
if (pcnet32_debug & NETIF_MSG_DRV)
|
||||
if (netif_msg_drv(lp))
|
||||
printk("\n" KERN_ERR PFX
|
||||
"%s: Consistent memory allocation failed.\n",
|
||||
name);
|
||||
@ -1448,52 +1709,48 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
|
||||
lp->rx_ring_size,
|
||||
&lp->rx_ring_dma_addr);
|
||||
if (lp->rx_ring == NULL) {
|
||||
if (pcnet32_debug & NETIF_MSG_DRV)
|
||||
if (netif_msg_drv(lp))
|
||||
printk("\n" KERN_ERR PFX
|
||||
"%s: Consistent memory allocation failed.\n",
|
||||
name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
lp->tx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->tx_ring_size,
|
||||
lp->tx_dma_addr = kcalloc(lp->tx_ring_size, sizeof(dma_addr_t),
|
||||
GFP_ATOMIC);
|
||||
if (!lp->tx_dma_addr) {
|
||||
if (pcnet32_debug & NETIF_MSG_DRV)
|
||||
if (netif_msg_drv(lp))
|
||||
printk("\n" KERN_ERR PFX
|
||||
"%s: Memory allocation failed.\n", name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(lp->tx_dma_addr, 0, sizeof(dma_addr_t) * lp->tx_ring_size);
|
||||
|
||||
lp->rx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->rx_ring_size,
|
||||
lp->rx_dma_addr = kcalloc(lp->rx_ring_size, sizeof(dma_addr_t),
|
||||
GFP_ATOMIC);
|
||||
if (!lp->rx_dma_addr) {
|
||||
if (pcnet32_debug & NETIF_MSG_DRV)
|
||||
if (netif_msg_drv(lp))
|
||||
printk("\n" KERN_ERR PFX
|
||||
"%s: Memory allocation failed.\n", name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(lp->rx_dma_addr, 0, sizeof(dma_addr_t) * lp->rx_ring_size);
|
||||
|
||||
lp->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->tx_ring_size,
|
||||
lp->tx_skbuff = kcalloc(lp->tx_ring_size, sizeof(struct sk_buff *),
|
||||
GFP_ATOMIC);
|
||||
if (!lp->tx_skbuff) {
|
||||
if (pcnet32_debug & NETIF_MSG_DRV)
|
||||
if (netif_msg_drv(lp))
|
||||
printk("\n" KERN_ERR PFX
|
||||
"%s: Memory allocation failed.\n", name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(lp->tx_skbuff, 0, sizeof(struct sk_buff *) * lp->tx_ring_size);
|
||||
|
||||
lp->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->rx_ring_size,
|
||||
lp->rx_skbuff = kcalloc(lp->rx_ring_size, sizeof(struct sk_buff *),
|
||||
GFP_ATOMIC);
|
||||
if (!lp->rx_skbuff) {
|
||||
if (pcnet32_debug & NETIF_MSG_DRV)
|
||||
if (netif_msg_drv(lp))
|
||||
printk("\n" KERN_ERR PFX
|
||||
"%s: Memory allocation failed.\n", name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1757,16 +2014,7 @@ static int pcnet32_open(struct net_device *dev)
|
||||
|
||||
err_free_ring:
|
||||
/* free any allocated skbuffs */
|
||||
for (i = 0; i < lp->rx_ring_size; i++) {
|
||||
lp->rx_ring[i].status = 0;
|
||||
if (lp->rx_skbuff[i]) {
|
||||
pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
|
||||
PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
|
||||
dev_kfree_skb(lp->rx_skbuff[i]);
|
||||
}
|
||||
lp->rx_skbuff[i] = NULL;
|
||||
lp->rx_dma_addr[i] = 0;
|
||||
}
|
||||
pcnet32_purge_rx_ring(dev);
|
||||
|
||||
/*
|
||||
* Switch back to 16bit mode to avoid problems with dumb
|
||||
@ -2348,7 +2596,6 @@ static int pcnet32_close(struct net_device *dev)
|
||||
{
|
||||
unsigned long ioaddr = dev->base_addr;
|
||||
struct pcnet32_private *lp = dev->priv;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
del_timer_sync(&lp->watchdog_timer);
|
||||
@ -2379,31 +2626,8 @@ static int pcnet32_close(struct net_device *dev)
|
||||
|
||||
spin_lock_irqsave(&lp->lock, flags);
|
||||
|
||||
/* free all allocated skbuffs */
|
||||
for (i = 0; i < lp->rx_ring_size; i++) {
|
||||
lp->rx_ring[i].status = 0;
|
||||
wmb(); /* Make sure adapter sees owner change */
|
||||
if (lp->rx_skbuff[i]) {
|
||||
pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
|
||||
PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
|
||||
dev_kfree_skb(lp->rx_skbuff[i]);
|
||||
}
|
||||
lp->rx_skbuff[i] = NULL;
|
||||
lp->rx_dma_addr[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < lp->tx_ring_size; i++) {
|
||||
lp->tx_ring[i].status = 0; /* CPU owns buffer */
|
||||
wmb(); /* Make sure adapter sees owner change */
|
||||
if (lp->tx_skbuff[i]) {
|
||||
pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i],
|
||||
lp->tx_skbuff[i]->len,
|
||||
PCI_DMA_TODEVICE);
|
||||
dev_kfree_skb(lp->tx_skbuff[i]);
|
||||
}
|
||||
lp->tx_skbuff[i] = NULL;
|
||||
lp->tx_dma_addr[i] = 0;
|
||||
}
|
||||
pcnet32_purge_rx_ring(dev);
|
||||
pcnet32_purge_tx_ring(dev);
|
||||
|
||||
spin_unlock_irqrestore(&lp->lock, flags);
|
||||
|
||||
@ -2433,6 +2657,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
|
||||
volatile struct pcnet32_init_block *ib = &lp->init_block;
|
||||
volatile u16 *mcast_table = (u16 *) & ib->filter;
|
||||
struct dev_mc_list *dmi = dev->mc_list;
|
||||
unsigned long ioaddr = dev->base_addr;
|
||||
char *addrs;
|
||||
int i;
|
||||
u32 crc;
|
||||
@ -2441,6 +2666,10 @@ static void pcnet32_load_multicast(struct net_device *dev)
|
||||
if (dev->flags & IFF_ALLMULTI) {
|
||||
ib->filter[0] = 0xffffffff;
|
||||
ib->filter[1] = 0xffffffff;
|
||||
lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff);
|
||||
lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff);
|
||||
lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff);
|
||||
lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+3, 0xffff);
|
||||
return;
|
||||
}
|
||||
/* clear the multicast filter */
|
||||
@ -2462,6 +2691,9 @@ static void pcnet32_load_multicast(struct net_device *dev)
|
||||
le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) |
|
||||
(1 << (crc & 0xf)));
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i,
|
||||
le16_to_cpu(mcast_table[i]));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2472,8 +2704,11 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
|
||||
{
|
||||
unsigned long ioaddr = dev->base_addr, flags;
|
||||
struct pcnet32_private *lp = dev->priv;
|
||||
int csr15, suspended;
|
||||
|
||||
spin_lock_irqsave(&lp->lock, flags);
|
||||
suspended = pcnet32_suspend(dev, &flags, 0);
|
||||
csr15 = lp->a.read_csr(ioaddr, CSR15);
|
||||
if (dev->flags & IFF_PROMISC) {
|
||||
/* Log any net taps. */
|
||||
if (netif_msg_hw(lp))
|
||||
@ -2482,15 +2717,24 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
|
||||
lp->init_block.mode =
|
||||
le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
|
||||
7);
|
||||
lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
|
||||
} else {
|
||||
lp->init_block.mode =
|
||||
le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
|
||||
lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
|
||||
pcnet32_load_multicast(dev);
|
||||
}
|
||||
|
||||
lp->a.write_csr(ioaddr, 0, 0x0004); /* Temporarily stop the lance. */
|
||||
pcnet32_restart(dev, 0x0042); /* Resume normal operation */
|
||||
netif_wake_queue(dev);
|
||||
if (suspended) {
|
||||
int csr5;
|
||||
/* clear SUSPEND (SPND) - CSR5 bit 0 */
|
||||
csr5 = lp->a.read_csr(ioaddr, CSR5);
|
||||
lp->a.write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
|
||||
} else {
|
||||
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
|
||||
pcnet32_restart(dev, CSR0_NORMAL);
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&lp->lock, flags);
|
||||
}
|
||||
@ -2730,7 +2974,7 @@ static int __init pcnet32_init_module(void)
|
||||
|
||||
/* should we find any remaining VLbus devices ? */
|
||||
if (pcnet32vlb)
|
||||
pcnet32_probe_vlbus();
|
||||
pcnet32_probe_vlbus(pcnet32_portlist);
|
||||
|
||||
if (cards_found && (pcnet32_debug & NETIF_MSG_PROBE))
|
||||
printk(KERN_INFO PFX "%d cards_found.\n", cards_found);
|
||||
|
@ -103,7 +103,22 @@ static int cis820x_config_intr(struct phy_device *phydev)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Cicada 820x */
|
||||
/* Cicada 8201, a.k.a Vitesse VSC8201 */
|
||||
static struct phy_driver cis8201_driver = {
|
||||
.phy_id = 0x000fc410,
|
||||
.name = "Cicada Cis8201",
|
||||
.phy_id_mask = 0x000ffff0,
|
||||
.features = PHY_GBIT_FEATURES,
|
||||
.flags = PHY_HAS_INTERRUPT,
|
||||
.config_init = &cis820x_config_init,
|
||||
.config_aneg = &genphy_config_aneg,
|
||||
.read_status = &genphy_read_status,
|
||||
.ack_interrupt = &cis820x_ack_interrupt,
|
||||
.config_intr = &cis820x_config_intr,
|
||||
.driver = { .owner = THIS_MODULE,},
|
||||
};
|
||||
|
||||
/* Cicada 8204 */
|
||||
static struct phy_driver cis8204_driver = {
|
||||
.phy_id = 0x000fc440,
|
||||
.name = "Cicada Cis8204",
|
||||
@ -118,15 +133,30 @@ static struct phy_driver cis8204_driver = {
|
||||
.driver = { .owner = THIS_MODULE,},
|
||||
};
|
||||
|
||||
static int __init cis8204_init(void)
|
||||
static int __init cicada_init(void)
|
||||
{
|
||||
return phy_driver_register(&cis8204_driver);
|
||||
int ret;
|
||||
|
||||
ret = phy_driver_register(&cis8204_driver);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
ret = phy_driver_register(&cis8201_driver);
|
||||
if (ret)
|
||||
goto err2;
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
phy_driver_unregister(&cis8204_driver);
|
||||
err1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit cis8204_exit(void)
|
||||
static void __exit cicada_exit(void)
|
||||
{
|
||||
phy_driver_unregister(&cis8204_driver);
|
||||
phy_driver_unregister(&cis8201_driver);
|
||||
}
|
||||
|
||||
module_init(cis8204_init);
|
||||
module_exit(cis8204_exit);
|
||||
module_init(cicada_init);
|
||||
module_exit(cicada_exit);
|
||||
|
@ -1406,7 +1406,7 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
|
||||
dev = alloc_etherdev(sizeof (*tp));
|
||||
if (dev == NULL) {
|
||||
if (netif_msg_drv(&debug))
|
||||
printk(KERN_ERR PFX "unable to alloc new ethernet\n");
|
||||
dev_err(&pdev->dev, "unable to alloc new ethernet\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
@ -1418,10 +1418,8 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
|
||||
/* enable device (incl. PCI PM wakeup and hotplug setup) */
|
||||
rc = pci_enable_device(pdev);
|
||||
if (rc < 0) {
|
||||
if (netif_msg_probe(tp)) {
|
||||
printk(KERN_ERR PFX "%s: enable failure\n",
|
||||
pci_name(pdev));
|
||||
}
|
||||
if (netif_msg_probe(tp))
|
||||
dev_err(&pdev->dev, "enable failure\n");
|
||||
goto err_out_free_dev;
|
||||
}
|
||||
|
||||
@ -1437,37 +1435,32 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
|
||||
pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
|
||||
acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
|
||||
} else {
|
||||
if (netif_msg_probe(tp)) {
|
||||
printk(KERN_ERR PFX
|
||||
if (netif_msg_probe(tp))
|
||||
dev_err(&pdev->dev,
|
||||
"PowerManagement capability not found.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* make sure PCI base addr 1 is MMIO */
|
||||
if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
|
||||
if (netif_msg_probe(tp)) {
|
||||
printk(KERN_ERR PFX
|
||||
if (netif_msg_probe(tp))
|
||||
dev_err(&pdev->dev,
|
||||
"region #1 not an MMIO resource, aborting\n");
|
||||
}
|
||||
rc = -ENODEV;
|
||||
goto err_out_mwi;
|
||||
}
|
||||
/* check for weird/broken PCI region reporting */
|
||||
if (pci_resource_len(pdev, 1) < R8169_REGS_SIZE) {
|
||||
if (netif_msg_probe(tp)) {
|
||||
printk(KERN_ERR PFX
|
||||
if (netif_msg_probe(tp))
|
||||
dev_err(&pdev->dev,
|
||||
"Invalid PCI region size(s), aborting\n");
|
||||
}
|
||||
rc = -ENODEV;
|
||||
goto err_out_mwi;
|
||||
}
|
||||
|
||||
rc = pci_request_regions(pdev, MODULENAME);
|
||||
if (rc < 0) {
|
||||
if (netif_msg_probe(tp)) {
|
||||
printk(KERN_ERR PFX "%s: could not request regions.\n",
|
||||
pci_name(pdev));
|
||||
}
|
||||
if (netif_msg_probe(tp))
|
||||
dev_err(&pdev->dev, "could not request regions.\n");
|
||||
goto err_out_mwi;
|
||||
}
|
||||
|
||||
@ -1480,10 +1473,9 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
|
||||
} else {
|
||||
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
|
||||
if (rc < 0) {
|
||||
if (netif_msg_probe(tp)) {
|
||||
printk(KERN_ERR PFX
|
||||
if (netif_msg_probe(tp))
|
||||
dev_err(&pdev->dev,
|
||||
"DMA configuration failed.\n");
|
||||
}
|
||||
goto err_out_free_res;
|
||||
}
|
||||
}
|
||||
@ -1494,7 +1486,7 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
|
||||
ioaddr = ioremap(pci_resource_start(pdev, 1), R8169_REGS_SIZE);
|
||||
if (ioaddr == NULL) {
|
||||
if (netif_msg_probe(tp))
|
||||
printk(KERN_ERR PFX "cannot remap MMIO, aborting\n");
|
||||
dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
|
||||
rc = -EIO;
|
||||
goto err_out_free_res;
|
||||
}
|
||||
@ -1526,9 +1518,9 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
|
||||
if (i < 0) {
|
||||
/* Unknown chip: assume array element #0, original RTL-8169 */
|
||||
if (netif_msg_probe(tp)) {
|
||||
printk(KERN_DEBUG PFX "PCI device %s: "
|
||||
dev_printk(KERN_DEBUG, &pdev->dev,
|
||||
"unknown chip version, assuming %s\n",
|
||||
pci_name(pdev), rtl_chip_info[0].name);
|
||||
rtl_chip_info[0].name);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -22,129 +22,13 @@
|
||||
|
||||
Support and updates available at
|
||||
http://www.scyld.com/network/starfire.html
|
||||
[link no longer provides useful info -jgarzik]
|
||||
|
||||
-----------------------------------------------------------
|
||||
|
||||
Linux kernel-specific changes:
|
||||
|
||||
LK1.1.1 (jgarzik):
|
||||
- Use PCI driver interface
|
||||
- Fix MOD_xxx races
|
||||
- softnet fixups
|
||||
|
||||
LK1.1.2 (jgarzik):
|
||||
- Merge Becker version 0.15
|
||||
|
||||
LK1.1.3 (Andrew Morton)
|
||||
- Timer cleanups
|
||||
|
||||
LK1.1.4 (jgarzik):
|
||||
- Merge Becker version 1.03
|
||||
|
||||
LK1.2.1 (Ion Badulescu <ionut@cs.columbia.edu>)
|
||||
- Support hardware Rx/Tx checksumming
|
||||
- Use the GFP firmware taken from Adaptec's Netware driver
|
||||
|
||||
LK1.2.2 (Ion Badulescu)
|
||||
- Backported to 2.2.x
|
||||
|
||||
LK1.2.3 (Ion Badulescu)
|
||||
- Fix the flaky mdio interface
|
||||
- More compat clean-ups
|
||||
|
||||
LK1.2.4 (Ion Badulescu)
|
||||
- More 2.2.x initialization fixes
|
||||
|
||||
LK1.2.5 (Ion Badulescu)
|
||||
- Several fixes from Manfred Spraul
|
||||
|
||||
LK1.2.6 (Ion Badulescu)
|
||||
- Fixed ifup/ifdown/ifup problem in 2.4.x
|
||||
|
||||
LK1.2.7 (Ion Badulescu)
|
||||
- Removed unused code
|
||||
- Made more functions static and __init
|
||||
|
||||
LK1.2.8 (Ion Badulescu)
|
||||
- Quell bogus error messages, inform about the Tx threshold
|
||||
- Removed #ifdef CONFIG_PCI, this driver is PCI only
|
||||
|
||||
LK1.2.9 (Ion Badulescu)
|
||||
- Merged Jeff Garzik's changes from 2.4.4-pre5
|
||||
- Added 2.2.x compatibility stuff required by the above changes
|
||||
|
||||
LK1.2.9a (Ion Badulescu)
|
||||
- More updates from Jeff Garzik
|
||||
|
||||
LK1.3.0 (Ion Badulescu)
|
||||
- Merged zerocopy support
|
||||
|
||||
LK1.3.1 (Ion Badulescu)
|
||||
- Added ethtool support
|
||||
- Added GPIO (media change) interrupt support
|
||||
|
||||
LK1.3.2 (Ion Badulescu)
|
||||
- Fixed 2.2.x compatibility issues introduced in 1.3.1
|
||||
- Fixed ethtool ioctl returning uninitialized memory
|
||||
|
||||
LK1.3.3 (Ion Badulescu)
|
||||
- Initialize the TxMode register properly
|
||||
- Don't dereference dev->priv after freeing it
|
||||
|
||||
LK1.3.4 (Ion Badulescu)
|
||||
- Fixed initialization timing problems
|
||||
- Fixed interrupt mask definitions
|
||||
|
||||
LK1.3.5 (jgarzik)
|
||||
- ethtool NWAY_RST, GLINK, [GS]MSGLVL support
|
||||
|
||||
LK1.3.6:
|
||||
- Sparc64 support and fixes (Ion Badulescu)
|
||||
- Better stats and error handling (Ion Badulescu)
|
||||
- Use new pci_set_mwi() PCI API function (jgarzik)
|
||||
|
||||
LK1.3.7 (Ion Badulescu)
|
||||
- minimal implementation of tx_timeout()
|
||||
- correctly shutdown the Rx/Tx engines in netdev_close()
|
||||
- added calls to netif_carrier_on/off
|
||||
(patch from Stefan Rompf <srompf@isg.de>)
|
||||
- VLAN support
|
||||
|
||||
LK1.3.8 (Ion Badulescu)
|
||||
- adjust DMA burst size on sparc64
|
||||
- 64-bit support
|
||||
- reworked zerocopy support for 64-bit buffers
|
||||
- working and usable interrupt mitigation/latency
|
||||
- reduced Tx interrupt frequency for lower interrupt overhead
|
||||
|
||||
LK1.3.9 (Ion Badulescu)
|
||||
- bugfix for mcast filter
|
||||
- enable the right kind of Tx interrupts (TxDMADone, not TxDone)
|
||||
|
||||
LK1.4.0 (Ion Badulescu)
|
||||
- NAPI support
|
||||
|
||||
LK1.4.1 (Ion Badulescu)
|
||||
- flush PCI posting buffers after disabling Rx interrupts
|
||||
- put the chip to a D3 slumber on driver unload
|
||||
- added config option to enable/disable NAPI
|
||||
|
||||
LK1.4.2 (Ion Badulescu)
|
||||
- finally added firmware (GPL'ed by Adaptec)
|
||||
- removed compatibility code for 2.2.x
|
||||
|
||||
LK1.4.2.1 (Ion Badulescu)
|
||||
- fixed 32/64 bit issues on i386 + CONFIG_HIGHMEM
|
||||
- added 32-bit padding to outgoing skb's, removed previous workaround
|
||||
|
||||
TODO: - fix forced speed/duplexing code (broken a long time ago, when
|
||||
somebody converted the driver to use the generic MII code)
|
||||
- fix VLAN support
|
||||
*/
|
||||
|
||||
#define DRV_NAME "starfire"
|
||||
#define DRV_VERSION "1.03+LK1.4.2.1"
|
||||
#define DRV_RELDATE "October 3, 2005"
|
||||
#define DRV_VERSION "2.0"
|
||||
#define DRV_RELDATE "June 27, 2006"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -846,7 +730,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
|
||||
goto err_out_free_netdev;
|
||||
}
|
||||
|
||||
/* ioremap is borken in Linux-2.2.x/sparc64 */
|
||||
base = ioremap(ioaddr, io_size);
|
||||
if (!base) {
|
||||
printk(KERN_ERR DRV_NAME " %d: cannot remap %#x @ %#lx, aborting\n",
|
||||
|
@ -16,91 +16,13 @@
|
||||
|
||||
Support and updates available at
|
||||
http://www.scyld.com/network/sundance.html
|
||||
[link no longer provides useful info -jgarzik]
|
||||
|
||||
|
||||
Version LK1.01a (jgarzik):
|
||||
- Replace some MII-related magic numbers with constants
|
||||
|
||||
Version LK1.02 (D-Link):
|
||||
- Add new board to PCI ID list
|
||||
- Fix multicast bug
|
||||
|
||||
Version LK1.03 (D-Link):
|
||||
- New Rx scheme, reduce Rx congestion
|
||||
- Option to disable flow control
|
||||
|
||||
Version LK1.04 (D-Link):
|
||||
- Tx timeout recovery
|
||||
- More support for ethtool.
|
||||
|
||||
Version LK1.04a:
|
||||
- Remove unused/constant members from struct pci_id_info
|
||||
(which then allows removal of 'drv_flags' from private struct)
|
||||
(jgarzik)
|
||||
- If no phy is found, fail to load that board (jgarzik)
|
||||
- Always start phy id scan at id 1 to avoid problems (Donald Becker)
|
||||
- Autodetect where mii_preable_required is needed,
|
||||
default to not needed. (Donald Becker)
|
||||
|
||||
Version LK1.04b:
|
||||
- Remove mii_preamble_required module parameter (Donald Becker)
|
||||
- Add per-interface mii_preamble_required (setting is autodetected)
|
||||
(Donald Becker)
|
||||
- Remove unnecessary cast from void pointer (jgarzik)
|
||||
- Re-align comments in private struct (jgarzik)
|
||||
|
||||
Version LK1.04c (jgarzik):
|
||||
- Support bitmapped message levels (NETIF_MSG_xxx), and the
|
||||
two ethtool ioctls that get/set them
|
||||
- Don't hand-code MII ethtool support, use standard API/lib
|
||||
|
||||
Version LK1.04d:
|
||||
- Merge from Donald Becker's sundance.c: (Jason Lunz)
|
||||
* proper support for variably-sized MTUs
|
||||
* default to PIO, to fix chip bugs
|
||||
- Add missing unregister_netdev (Jason Lunz)
|
||||
- Add CONFIG_SUNDANCE_MMIO config option (jgarzik)
|
||||
- Better rx buf size calculation (Donald Becker)
|
||||
|
||||
Version LK1.05 (D-Link):
|
||||
- Fix DFE-580TX packet drop issue (for DL10050C)
|
||||
- Fix reset_tx logic
|
||||
|
||||
Version LK1.06 (D-Link):
|
||||
- Fix crash while unloading driver
|
||||
|
||||
Versin LK1.06b (D-Link):
|
||||
- New tx scheme, adaptive tx_coalesce
|
||||
|
||||
Version LK1.07 (D-Link):
|
||||
- Fix tx bugs in big-endian machines
|
||||
- Remove unused max_interrupt_work module parameter, the new
|
||||
NAPI-like rx scheme doesn't need it.
|
||||
- Remove redundancy get_stats() in intr_handler(), those
|
||||
I/O access could affect performance in ARM-based system
|
||||
- Add Linux software VLAN support
|
||||
|
||||
Version LK1.08 (Philippe De Muyter phdm@macqel.be):
|
||||
- Fix bug of custom mac address
|
||||
(StationAddr register only accept word write)
|
||||
|
||||
Version LK1.09 (D-Link):
|
||||
- Fix the flowctrl bug.
|
||||
- Set Pause bit in MII ANAR if flow control enabled.
|
||||
|
||||
Version LK1.09a (ICPlus):
|
||||
- Add the delay time in reading the contents of EEPROM
|
||||
|
||||
Version LK1.10 (Philippe De Muyter phdm@macqel.be):
|
||||
- Make 'unblock interface after Tx underrun' work
|
||||
|
||||
Version LK1.11 (Pedro Alejandro Lopez-Valencia palopezv at gmail.com):
|
||||
- Add support for IC Plus Corporation IP100A chipset
|
||||
*/
|
||||
|
||||
#define DRV_NAME "sundance"
|
||||
#define DRV_VERSION "1.01+LK1.11"
|
||||
#define DRV_RELDATE "14-Jun-2006"
|
||||
#define DRV_VERSION "1.1"
|
||||
#define DRV_RELDATE "27-Jun-2006"
|
||||
|
||||
|
||||
/* The user-configurable values.
|
||||
@ -282,15 +204,15 @@ IVc. Errata
|
||||
#define USE_IO_OPS 1
|
||||
#endif
|
||||
|
||||
static struct pci_device_id sundance_pci_tbl[] = {
|
||||
{0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0},
|
||||
{0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1},
|
||||
{0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2},
|
||||
{0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3},
|
||||
{0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
|
||||
{0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
|
||||
{0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
|
||||
{0,}
|
||||
static const struct pci_device_id sundance_pci_tbl[] = {
|
||||
{ 0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0 },
|
||||
{ 0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1 },
|
||||
{ 0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2 },
|
||||
{ 0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3 },
|
||||
{ 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
|
||||
{ 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
|
||||
{ 0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
|
||||
|
||||
@ -301,7 +223,7 @@ enum {
|
||||
struct pci_id_info {
|
||||
const char *name;
|
||||
};
|
||||
static const struct pci_id_info pci_id_tbl[] = {
|
||||
static const struct pci_id_info pci_id_tbl[] __devinitdata = {
|
||||
{"D-Link DFE-550TX FAST Ethernet Adapter"},
|
||||
{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
|
||||
{"D-Link DFE-580TX 4 port Server Adapter"},
|
||||
@ -309,7 +231,7 @@ static const struct pci_id_info pci_id_tbl[] = {
|
||||
{"D-Link DL10050-based FAST Ethernet Adapter"},
|
||||
{"Sundance Technology Alta"},
|
||||
{"IC Plus Corporation IP100A FAST Ethernet Adapter"},
|
||||
{NULL,}, /* 0 terminated list. */
|
||||
{ } /* terminate list. */
|
||||
};
|
||||
|
||||
/* This driver was written to use PCI memory space, however x86-oriented
|
||||
|
@ -224,24 +224,21 @@ static const struct pci_device_id w840_pci_tbl[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, w840_pci_tbl);
|
||||
|
||||
enum {
|
||||
netdev_res_size = 128, /* size of PCI BAR resource */
|
||||
};
|
||||
|
||||
struct pci_id_info {
|
||||
const char *name;
|
||||
struct match_info {
|
||||
int pci, pci_mask, subsystem, subsystem_mask;
|
||||
int revision, revision_mask; /* Only 8 bits. */
|
||||
} id;
|
||||
int io_size; /* Needed for I/O region check or ioremap(). */
|
||||
int drv_flags; /* Driver use, intended as capability flags. */
|
||||
int drv_flags; /* Driver use, intended as capability flags. */
|
||||
};
|
||||
static struct pci_id_info pci_id_tbl[] = {
|
||||
{"Winbond W89c840", /* Sometime a Level-One switch card. */
|
||||
{ 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 },
|
||||
128, CanHaveMII | HasBrokenTx | FDXOnNoMII},
|
||||
{"Winbond W89c840", { 0x08401050, 0xffffffff, },
|
||||
128, CanHaveMII | HasBrokenTx},
|
||||
{"Compex RL100-ATX", { 0x201111F6, 0xffffffff,},
|
||||
128, CanHaveMII | HasBrokenTx},
|
||||
{NULL,}, /* 0 terminated list. */
|
||||
|
||||
static const struct pci_id_info pci_id_tbl[] __devinitdata = {
|
||||
{ /* Sometime a Level-One switch card. */
|
||||
"Winbond W89c840", CanHaveMII | HasBrokenTx | FDXOnNoMII},
|
||||
{ "Winbond W89c840", CanHaveMII | HasBrokenTx},
|
||||
{ "Compex RL100-ATX", CanHaveMII | HasBrokenTx},
|
||||
{ } /* terminate list. */
|
||||
};
|
||||
|
||||
/* This driver was written to use PCI memory space, however some x86 systems
|
||||
@ -399,7 +396,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
|
||||
#ifdef USE_IO_OPS
|
||||
bar = 0;
|
||||
#endif
|
||||
ioaddr = pci_iomap(pdev, bar, pci_id_tbl[chip_idx].io_size);
|
||||
ioaddr = pci_iomap(pdev, bar, netdev_res_size);
|
||||
if (!ioaddr)
|
||||
goto err_out_free_res;
|
||||
|
||||
|
@ -10,26 +10,11 @@
|
||||
410 Severn Ave., Suite 210
|
||||
Annapolis MD 21403
|
||||
|
||||
-----------------------------------------------------------
|
||||
|
||||
Linux kernel-specific changes:
|
||||
|
||||
LK1.0 (Ion Badulescu)
|
||||
- Major cleanup
|
||||
- Use 2.4 PCI API
|
||||
- Support ethtool
|
||||
- Rewrite perfect filter/hash code
|
||||
- Use interrupts for media changes
|
||||
|
||||
LK1.1 (Ion Badulescu)
|
||||
- Disallow negotiation of unsupported full-duplex modes
|
||||
*/
|
||||
|
||||
#define DRV_NAME "xircom_tulip_cb"
|
||||
#define DRV_VERSION "0.91+LK1.1"
|
||||
#define DRV_RELDATE "October 11, 2001"
|
||||
|
||||
#define CARDBUS 1
|
||||
#define DRV_VERSION "0.92"
|
||||
#define DRV_RELDATE "June 27, 2006"
|
||||
|
||||
/* A few user-configurable values. */
|
||||
|
||||
@ -306,10 +291,10 @@ struct xircom_private {
|
||||
struct xircom_tx_desc tx_ring[TX_RING_SIZE];
|
||||
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
|
||||
struct sk_buff* tx_skbuff[TX_RING_SIZE];
|
||||
#ifdef CARDBUS
|
||||
|
||||
/* The X3201-3 requires 4-byte aligned tx bufs */
|
||||
struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE];
|
||||
#endif
|
||||
|
||||
/* The addresses of receive-in-place skbuffs. */
|
||||
struct sk_buff* rx_skbuff[RX_RING_SIZE];
|
||||
u16 setup_frame[PKT_SETUP_SZ / sizeof(u16)]; /* Pseudo-Tx frame to init address table. */
|
||||
@ -908,10 +893,8 @@ static void xircom_init_ring(struct net_device *dev)
|
||||
tp->tx_skbuff[i] = NULL;
|
||||
tp->tx_ring[i].status = 0;
|
||||
tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
|
||||
#ifdef CARDBUS
|
||||
if (tp->chip_id == X3201_3)
|
||||
tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ);
|
||||
#endif /* CARDBUS */
|
||||
}
|
||||
tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]);
|
||||
}
|
||||
@ -931,12 +914,10 @@ xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
entry = tp->cur_tx % TX_RING_SIZE;
|
||||
|
||||
tp->tx_skbuff[entry] = skb;
|
||||
#ifdef CARDBUS
|
||||
if (tp->chip_id == X3201_3) {
|
||||
memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len);
|
||||
tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data);
|
||||
} else
|
||||
#endif
|
||||
tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
|
||||
|
||||
if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
|
||||
|
@ -25,117 +25,13 @@
|
||||
version. He may or may not be interested in bug reports on this
|
||||
code. You can find his versions at:
|
||||
http://www.scyld.com/network/via-rhine.html
|
||||
|
||||
|
||||
Linux kernel version history:
|
||||
|
||||
LK1.1.0:
|
||||
- Jeff Garzik: softnet 'n stuff
|
||||
|
||||
LK1.1.1:
|
||||
- Justin Guyett: softnet and locking fixes
|
||||
- Jeff Garzik: use PCI interface
|
||||
|
||||
LK1.1.2:
|
||||
- Urban Widmark: minor cleanups, merges from Becker 1.03a/1.04 versions
|
||||
|
||||
LK1.1.3:
|
||||
- Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c
|
||||
code) update "Theory of Operation" with
|
||||
softnet/locking changes
|
||||
- Dave Miller: PCI DMA and endian fixups
|
||||
- Jeff Garzik: MOD_xxx race fixes, updated PCI resource allocation
|
||||
|
||||
LK1.1.4:
|
||||
- Urban Widmark: fix gcc 2.95.2 problem and
|
||||
remove writel's to fixed address 0x7c
|
||||
|
||||
LK1.1.5:
|
||||
- Urban Widmark: mdio locking, bounce buffer changes
|
||||
merges from Beckers 1.05 version
|
||||
added netif_running_on/off support
|
||||
|
||||
LK1.1.6:
|
||||
- Urban Widmark: merges from Beckers 1.08b version (VT6102 + mdio)
|
||||
set netif_running_on/off on startup, del_timer_sync
|
||||
|
||||
LK1.1.7:
|
||||
- Manfred Spraul: added reset into tx_timeout
|
||||
|
||||
LK1.1.9:
|
||||
- Urban Widmark: merges from Beckers 1.10 version
|
||||
(media selection + eeprom reload)
|
||||
- David Vrabel: merges from D-Link "1.11" version
|
||||
(disable WOL and PME on startup)
|
||||
|
||||
LK1.1.10:
|
||||
- Manfred Spraul: use "singlecopy" for unaligned buffers
|
||||
don't allocate bounce buffers for !ReqTxAlign cards
|
||||
|
||||
LK1.1.11:
|
||||
- David Woodhouse: Set dev->base_addr before the first time we call
|
||||
wait_for_reset(). It's a lot happier that way.
|
||||
Free np->tx_bufs only if we actually allocated it.
|
||||
|
||||
LK1.1.12:
|
||||
- Martin Eriksson: Allow Memory-Mapped IO to be enabled.
|
||||
|
||||
LK1.1.13 (jgarzik):
|
||||
- Add ethtool support
|
||||
- Replace some MII-related magic numbers with constants
|
||||
|
||||
LK1.1.14 (Ivan G.):
|
||||
- fixes comments for Rhine-III
|
||||
- removes W_MAX_TIMEOUT (unused)
|
||||
- adds HasDavicomPhy for Rhine-I (basis: linuxfet driver; my card
|
||||
is R-I and has Davicom chip, flag is referenced in kernel driver)
|
||||
- sends chip_id as a parameter to wait_for_reset since np is not
|
||||
initialized on first call
|
||||
- changes mmio "else if (chip_id==VT6102)" to "else" so it will work
|
||||
for Rhine-III's (documentation says same bit is correct)
|
||||
- transmit frame queue message is off by one - fixed
|
||||
- adds IntrNormalSummary to "Something Wicked" exclusion list
|
||||
so normal interrupts will not trigger the message (src: Donald Becker)
|
||||
(Roger Luethi)
|
||||
- show confused chip where to continue after Tx error
|
||||
- location of collision counter is chip specific
|
||||
- allow selecting backoff algorithm (module parameter)
|
||||
|
||||
LK1.1.15 (jgarzik):
|
||||
- Use new MII lib helper generic_mii_ioctl
|
||||
|
||||
LK1.1.16 (Roger Luethi)
|
||||
- Etherleak fix
|
||||
- Handle Tx buffer underrun
|
||||
- Fix bugs in full duplex handling
|
||||
- New reset code uses "force reset" cmd on Rhine-II
|
||||
- Various clean ups
|
||||
|
||||
LK1.1.17 (Roger Luethi)
|
||||
- Fix race in via_rhine_start_tx()
|
||||
- On errors, wait for Tx engine to turn off before scavenging
|
||||
- Handle Tx descriptor write-back race on Rhine-II
|
||||
- Force flushing for PCI posted writes
|
||||
- More reset code changes
|
||||
|
||||
LK1.1.18 (Roger Luethi)
|
||||
- No filtering multicast in promisc mode (Edward Peng)
|
||||
- Fix for Rhine-I Tx timeouts
|
||||
|
||||
LK1.1.19 (Roger Luethi)
|
||||
- Increase Tx threshold for unspecified errors
|
||||
|
||||
LK1.2.0-2.6 (Roger Luethi)
|
||||
- Massive clean-up
|
||||
- Rewrite PHY, media handling (remove options, full_duplex, backoff)
|
||||
- Fix Tx engine race for good
|
||||
- Craig Brind: Zero padded aligned buffers for short packets.
|
||||
[link no longer provides useful info -jgarzik]
|
||||
|
||||
*/
|
||||
|
||||
#define DRV_NAME "via-rhine"
|
||||
#define DRV_VERSION "1.2.0-2.6"
|
||||
#define DRV_RELDATE "June-10-2004"
|
||||
#define DRV_VERSION "1.4.0"
|
||||
#define DRV_RELDATE "June-27-2006"
|
||||
|
||||
|
||||
/* A few user-configurable values.
|
||||
@ -356,12 +252,11 @@ enum rhine_quirks {
|
||||
/* Beware of PCI posted writes */
|
||||
#define IOSYNC do { ioread8(ioaddr + StationAddr); } while (0)
|
||||
|
||||
static struct pci_device_id rhine_pci_tbl[] =
|
||||
{
|
||||
{0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT86C100A */
|
||||
{0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT6102 */
|
||||
{0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* 6105{,L,LOM} */
|
||||
{0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT6105M */
|
||||
static const struct pci_device_id rhine_pci_tbl[] = {
|
||||
{ 0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, }, /* VT86C100A */
|
||||
{ 0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, }, /* VT6102 */
|
||||
{ 0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, }, /* 6105{,L,LOM} */
|
||||
{ 0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, }, /* VT6105M */
|
||||
{ } /* terminate list */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, rhine_pci_tbl);
|
||||
|
@ -229,7 +229,8 @@ static int rx_copybreak = 200;
|
||||
module_param(rx_copybreak, int, 0644);
|
||||
MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
|
||||
|
||||
static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info);
|
||||
static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr,
|
||||
const struct velocity_info_tbl *info);
|
||||
static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
|
||||
static void velocity_print_info(struct velocity_info *vptr);
|
||||
static int velocity_open(struct net_device *dev);
|
||||
@ -294,9 +295,9 @@ static void velocity_unregister_notifier(void)
|
||||
* Internal board variants. At the moment we have only one
|
||||
*/
|
||||
|
||||
static struct velocity_info_tbl chip_info_table[] = {
|
||||
{CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 256, 1, 0x00FFFFFFUL},
|
||||
{0, NULL}
|
||||
static const struct velocity_info_tbl chip_info_table[] __devinitdata = {
|
||||
{CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 1, 0x00FFFFFFUL},
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
@ -304,10 +305,9 @@ static struct velocity_info_tbl chip_info_table[] = {
|
||||
* device driver. Used for hotplug autoloading.
|
||||
*/
|
||||
|
||||
static struct pci_device_id velocity_id_table[] __devinitdata = {
|
||||
{PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) chip_info_table},
|
||||
{0, }
|
||||
static const struct pci_device_id velocity_id_table[] __devinitdata = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, velocity_id_table);
|
||||
@ -341,7 +341,7 @@ static char __devinit *get_chip_name(enum chip_type chip_id)
|
||||
static void __devexit velocity_remove1(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
unsigned long flags;
|
||||
@ -686,21 +686,23 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
|
||||
static int first = 1;
|
||||
struct net_device *dev;
|
||||
int i;
|
||||
struct velocity_info_tbl *info = (struct velocity_info_tbl *) ent->driver_data;
|
||||
const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
|
||||
struct velocity_info *vptr;
|
||||
struct mac_regs __iomem * regs;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
/* FIXME: this driver, like almost all other ethernet drivers,
|
||||
* can support more than MAX_UNITS.
|
||||
*/
|
||||
if (velocity_nics >= MAX_UNITS) {
|
||||
printk(KERN_NOTICE VELOCITY_NAME ": already found %d NICs.\n",
|
||||
velocity_nics);
|
||||
dev_notice(&pdev->dev, "already found %d NICs.\n",
|
||||
velocity_nics);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev = alloc_etherdev(sizeof(struct velocity_info));
|
||||
|
||||
if (dev == NULL) {
|
||||
printk(KERN_ERR VELOCITY_NAME ": allocate net device failed.\n");
|
||||
if (!dev) {
|
||||
dev_err(&pdev->dev, "allocate net device failed.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -708,7 +710,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
|
||||
|
||||
SET_MODULE_OWNER(dev);
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
vptr = dev->priv;
|
||||
vptr = netdev_priv(dev);
|
||||
|
||||
|
||||
if (first) {
|
||||
@ -731,17 +733,17 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
|
||||
|
||||
ret = velocity_get_pci_info(vptr, pdev);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
|
||||
/* error message already printed */
|
||||
goto err_disable;
|
||||
}
|
||||
|
||||
ret = pci_request_regions(pdev, VELOCITY_NAME);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
|
||||
dev_err(&pdev->dev, "No PCI resources.\n");
|
||||
goto err_disable;
|
||||
}
|
||||
|
||||
regs = ioremap(vptr->memaddr, vptr->io_size);
|
||||
regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
|
||||
if (regs == NULL) {
|
||||
ret = -EIO;
|
||||
goto err_release_res;
|
||||
@ -859,13 +861,14 @@ static void __devinit velocity_print_info(struct velocity_info *vptr)
|
||||
* discovered.
|
||||
*/
|
||||
|
||||
static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info)
|
||||
static void __devinit velocity_init_info(struct pci_dev *pdev,
|
||||
struct velocity_info *vptr,
|
||||
const struct velocity_info_tbl *info)
|
||||
{
|
||||
memset(vptr, 0, sizeof(struct velocity_info));
|
||||
|
||||
vptr->pdev = pdev;
|
||||
vptr->chip_id = info->chip_id;
|
||||
vptr->io_size = info->io_size;
|
||||
vptr->num_txq = info->txqueue;
|
||||
vptr->multicast_limit = MCAM_SIZE;
|
||||
spin_lock_init(&vptr->lock);
|
||||
@ -883,8 +886,7 @@ static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_i
|
||||
|
||||
static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
|
||||
{
|
||||
|
||||
if(pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
|
||||
if (pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
|
||||
return -EIO;
|
||||
|
||||
pci_set_master(pdev);
|
||||
@ -892,24 +894,20 @@ static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pc
|
||||
vptr->ioaddr = pci_resource_start(pdev, 0);
|
||||
vptr->memaddr = pci_resource_start(pdev, 1);
|
||||
|
||||
if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO))
|
||||
{
|
||||
printk(KERN_ERR "%s: region #0 is not an I/O resource, aborting.\n",
|
||||
pci_name(pdev));
|
||||
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
|
||||
dev_err(&pdev->dev,
|
||||
"region #0 is not an I/O resource, aborting.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if((pci_resource_flags(pdev, 1) & IORESOURCE_IO))
|
||||
{
|
||||
printk(KERN_ERR "%s: region #1 is an I/O resource, aborting.\n",
|
||||
pci_name(pdev));
|
||||
if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
|
||||
dev_err(&pdev->dev,
|
||||
"region #1 is an I/O resource, aborting.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if(pci_resource_len(pdev, 1) < 256)
|
||||
{
|
||||
printk(KERN_ERR "%s: region #1 is too small.\n",
|
||||
pci_name(pdev));
|
||||
if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
|
||||
dev_err(&pdev->dev, "region #1 is too small.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
vptr->pdev = pdev;
|
||||
@ -1728,7 +1726,7 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_
|
||||
|
||||
static int velocity_open(struct net_device *dev)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
int ret;
|
||||
|
||||
vptr->rx_buf_sz = (dev->mtu <= 1504 ? PKT_BUF_SZ : dev->mtu + 32);
|
||||
@ -1785,7 +1783,7 @@ static int velocity_open(struct net_device *dev)
|
||||
|
||||
static int velocity_change_mtu(struct net_device *dev, int new_mtu)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
unsigned long flags;
|
||||
int oldmtu = dev->mtu;
|
||||
int ret = 0;
|
||||
@ -1861,7 +1859,7 @@ static void velocity_shutdown(struct velocity_info *vptr)
|
||||
|
||||
static int velocity_close(struct net_device *dev)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
|
||||
netif_stop_queue(dev);
|
||||
velocity_shutdown(vptr);
|
||||
@ -1894,7 +1892,7 @@ static int velocity_close(struct net_device *dev)
|
||||
|
||||
static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
int qnum = 0;
|
||||
struct tx_desc *td_ptr;
|
||||
struct velocity_td_info *tdinfo;
|
||||
@ -2049,7 +2047,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
|
||||
{
|
||||
struct net_device *dev = dev_instance;
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
u32 isr_status;
|
||||
int max_count = 0;
|
||||
|
||||
@ -2104,7 +2102,7 @@ static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
|
||||
|
||||
static void velocity_set_multi(struct net_device *dev)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
struct mac_regs __iomem * regs = vptr->mac_regs;
|
||||
u8 rx_mode;
|
||||
int i;
|
||||
@ -2153,7 +2151,7 @@ static void velocity_set_multi(struct net_device *dev)
|
||||
|
||||
static struct net_device_stats *velocity_get_stats(struct net_device *dev)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
|
||||
/* If the hardware is down, don't touch MII */
|
||||
if(!netif_running(dev))
|
||||
@ -2196,7 +2194,7 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev)
|
||||
|
||||
static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
int ret;
|
||||
|
||||
/* If we are asked for information and the device is power
|
||||
@ -2825,7 +2823,7 @@ static void enable_flow_control_ability(struct velocity_info *vptr)
|
||||
|
||||
static int velocity_ethtool_up(struct net_device *dev)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
if (!netif_running(dev))
|
||||
pci_set_power_state(vptr->pdev, PCI_D0);
|
||||
return 0;
|
||||
@ -2841,14 +2839,14 @@ static int velocity_ethtool_up(struct net_device *dev)
|
||||
|
||||
static void velocity_ethtool_down(struct net_device *dev)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
if (!netif_running(dev))
|
||||
pci_set_power_state(vptr->pdev, PCI_D3hot);
|
||||
}
|
||||
|
||||
static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
struct mac_regs __iomem * regs = vptr->mac_regs;
|
||||
u32 status;
|
||||
status = check_connection_type(vptr->mac_regs);
|
||||
@ -2873,7 +2871,7 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd
|
||||
|
||||
static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
u32 curr_status;
|
||||
u32 new_status = 0;
|
||||
int ret = 0;
|
||||
@ -2896,14 +2894,14 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
|
||||
|
||||
static u32 velocity_get_link(struct net_device *dev)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
struct mac_regs __iomem * regs = vptr->mac_regs;
|
||||
return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, ®s->PHYSR0) ? 0 : 1;
|
||||
}
|
||||
|
||||
static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
strcpy(info->driver, VELOCITY_NAME);
|
||||
strcpy(info->version, VELOCITY_VERSION);
|
||||
strcpy(info->bus_info, pci_name(vptr->pdev));
|
||||
@ -2911,7 +2909,7 @@ static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo
|
||||
|
||||
static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP;
|
||||
wol->wolopts |= WAKE_MAGIC;
|
||||
/*
|
||||
@ -2927,7 +2925,7 @@ static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_woli
|
||||
|
||||
static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
|
||||
if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP)))
|
||||
return -EFAULT;
|
||||
@ -2992,7 +2990,7 @@ static struct ethtool_ops velocity_ethtool_ops = {
|
||||
|
||||
static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
{
|
||||
struct velocity_info *vptr = dev->priv;
|
||||
struct velocity_info *vptr = netdev_priv(dev);
|
||||
struct mac_regs __iomem * regs = vptr->mac_regs;
|
||||
unsigned long flags;
|
||||
struct mii_ioctl_data *miidata = if_mii(ifr);
|
||||
|
@ -31,6 +31,8 @@
|
||||
#define VELOCITY_FULL_DRV_NAM "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"
|
||||
#define VELOCITY_VERSION "1.13"
|
||||
|
||||
#define VELOCITY_IO_SIZE 256
|
||||
|
||||
#define PKT_BUF_SZ 1540
|
||||
|
||||
#define MAX_UNITS 8
|
||||
@ -1191,7 +1193,6 @@ enum chip_type {
|
||||
struct velocity_info_tbl {
|
||||
enum chip_type chip_id;
|
||||
char *name;
|
||||
int io_size;
|
||||
int txqueue;
|
||||
u32 flags;
|
||||
};
|
||||
@ -1751,7 +1752,6 @@ struct velocity_info {
|
||||
struct mac_regs __iomem * mac_regs;
|
||||
unsigned long memaddr;
|
||||
unsigned long ioaddr;
|
||||
u32 io_size;
|
||||
|
||||
u8 rev_id;
|
||||
|
||||
|
@ -134,18 +134,6 @@ config SEALEVEL_4021
|
||||
The driver will be compiled as a module: the
|
||||
module will be called sealevel.
|
||||
|
||||
config SYNCLINK_SYNCPPP
|
||||
tristate "SyncLink HDLC/SYNCPPP support"
|
||||
depends on WAN
|
||||
help
|
||||
Enables HDLC/SYNCPPP support for the SyncLink WAN driver.
|
||||
|
||||
Normally the SyncLink WAN driver works with the main PPP driver
|
||||
<file:drivers/net/ppp_generic.c> and pppd program.
|
||||
HDLC/SYNCPPP support allows use of the Cisco HDLC/PPP driver
|
||||
<file:drivers/net/wan/syncppp.c>. The SyncLink WAN driver (in
|
||||
character devices) must also be enabled.
|
||||
|
||||
# Generic HDLC
|
||||
config HDLC
|
||||
tristate "Generic HDLC layer"
|
||||
|
@ -28,7 +28,6 @@ obj-$(CONFIG_COSA) += syncppp.o cosa.o
|
||||
obj-$(CONFIG_FARSYNC) += syncppp.o farsync.o
|
||||
obj-$(CONFIG_DSCC4) += dscc4.o
|
||||
obj-$(CONFIG_LANMEDIA) += syncppp.o
|
||||
obj-$(CONFIG_SYNCLINK_SYNCPPP) += syncppp.o
|
||||
obj-$(CONFIG_X25_ASY) += x25_asy.o
|
||||
|
||||
obj-$(CONFIG_LANMEDIA) += lmc/
|
||||
|
@ -550,6 +550,7 @@ config USB_ZD1201
|
||||
|
||||
source "drivers/net/wireless/hostap/Kconfig"
|
||||
source "drivers/net/wireless/bcm43xx/Kconfig"
|
||||
source "drivers/net/wireless/zd1211rw/Kconfig"
|
||||
|
||||
# yes, this works even when no drivers are selected
|
||||
config NET_WIRELESS
|
||||
|
@ -36,6 +36,7 @@ obj-$(CONFIG_PRISM54) += prism54/
|
||||
|
||||
obj-$(CONFIG_HOSTAP) += hostap/
|
||||
obj-$(CONFIG_BCM43XX) += bcm43xx/
|
||||
obj-$(CONFIG_ZD1211RW) += zd1211rw/
|
||||
|
||||
# 16-bit wireless PCMCIA client drivers
|
||||
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
|
||||
|
@ -1885,6 +1885,15 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
|
||||
|
||||
spin_lock(&bcm->irq_lock);
|
||||
|
||||
/* Only accept IRQs, if we are initialized properly.
|
||||
* This avoids an RX race while initializing.
|
||||
* We should probably not enable IRQs before we are initialized
|
||||
* completely, but some careful work is needed to fix this. I think it
|
||||
* is best to stay with this cheap workaround for now... .
|
||||
*/
|
||||
if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED))
|
||||
goto out;
|
||||
|
||||
reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
|
||||
if (reason == 0xffffffff) {
|
||||
/* irq not for us (shared irq) */
|
||||
@ -1906,19 +1915,11 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
|
||||
|
||||
bcm43xx_interrupt_ack(bcm, reason);
|
||||
|
||||
/* Only accept IRQs, if we are initialized properly.
|
||||
* This avoids an RX race while initializing.
|
||||
* We should probably not enable IRQs before we are initialized
|
||||
* completely, but some careful work is needed to fix this. I think it
|
||||
* is best to stay with this cheap workaround for now... .
|
||||
*/
|
||||
if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
|
||||
/* disable all IRQs. They are enabled again in the bottom half. */
|
||||
bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
|
||||
/* save the reason code and call our bottom half. */
|
||||
bcm->irq_reason = reason;
|
||||
tasklet_schedule(&bcm->isr_tasklet);
|
||||
}
|
||||
/* disable all IRQs. They are enabled again in the bottom half. */
|
||||
bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
|
||||
/* save the reason code and call our bottom half. */
|
||||
bcm->irq_reason = reason;
|
||||
tasklet_schedule(&bcm->isr_tasklet);
|
||||
|
||||
out:
|
||||
mmiowb();
|
||||
@ -3698,6 +3699,10 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
|
||||
secinfo->encrypt = sec->encrypt;
|
||||
dprintk(", .encrypt = %d", sec->encrypt);
|
||||
}
|
||||
if (sec->flags & SEC_AUTH_MODE) {
|
||||
secinfo->auth_mode = sec->auth_mode;
|
||||
dprintk(", .auth_mode = %d\n", sec->auth_mode);
|
||||
}
|
||||
dprintk("\n");
|
||||
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
|
||||
!bcm->ieee->host_encrypt) {
|
||||
|
@ -112,30 +112,6 @@ int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm,
|
||||
return bcm43xx_channel_to_freq_bg(channel);
|
||||
}
|
||||
|
||||
/* Lightweight function to check if a channel number is valid.
|
||||
* Note that this does _NOT_ check for geographical restrictions!
|
||||
*/
|
||||
static inline
|
||||
int bcm43xx_is_valid_channel_a(u8 channel)
|
||||
{
|
||||
return (channel >= IEEE80211_52GHZ_MIN_CHANNEL
|
||||
&& channel <= IEEE80211_52GHZ_MAX_CHANNEL);
|
||||
}
|
||||
static inline
|
||||
int bcm43xx_is_valid_channel_bg(u8 channel)
|
||||
{
|
||||
return (channel >= IEEE80211_24GHZ_MIN_CHANNEL
|
||||
&& channel <= IEEE80211_24GHZ_MAX_CHANNEL);
|
||||
}
|
||||
static inline
|
||||
int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
|
||||
u8 channel)
|
||||
{
|
||||
if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
|
||||
return bcm43xx_is_valid_channel_a(channel);
|
||||
return bcm43xx_is_valid_channel_bg(channel);
|
||||
}
|
||||
|
||||
void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
|
||||
void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
|
||||
|
||||
|
@ -1594,11 +1594,11 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
|
||||
u16 r8, tmp;
|
||||
u16 freq;
|
||||
|
||||
if (!ieee80211_is_valid_channel(bcm->ieee, channel))
|
||||
return -EINVAL;
|
||||
if ((radio->manufact == 0x17F) &&
|
||||
(radio->version == 0x2060) &&
|
||||
(radio->revision == 1)) {
|
||||
if (channel > 200)
|
||||
return -EINVAL;
|
||||
freq = channel2freq_a(channel);
|
||||
|
||||
r8 = bcm43xx_radio_read16(bcm, 0x0008);
|
||||
@ -1651,9 +1651,6 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
|
||||
TODO(); //TODO: TSSI2dbm workaround
|
||||
bcm43xx_phy_xmitpower(bcm);//FIXME correct?
|
||||
} else {
|
||||
if ((channel < 1) || (channel > 14))
|
||||
return -EINVAL;
|
||||
|
||||
if (synthetic_pu_workaround)
|
||||
bcm43xx_synth_pu_workaround(bcm, channel);
|
||||
|
||||
|
@ -119,7 +119,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
|
||||
channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
|
||||
freq = data->freq.m;
|
||||
}
|
||||
if (!bcm43xx_is_valid_channel(bcm, channel))
|
||||
if (!ieee80211_is_valid_channel(bcm->ieee, channel))
|
||||
goto out_unlock;
|
||||
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
|
||||
//ieee80211softmac_disassoc(softmac, $REASON);
|
||||
|
@ -296,11 +296,14 @@ void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
|
||||
u16 control = 0;
|
||||
u16 wsec_rate = 0;
|
||||
u16 encrypt_frame;
|
||||
const u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(wireless_header->frame_ctl));
|
||||
const int is_mgt = (ftype == IEEE80211_FTYPE_MGMT);
|
||||
|
||||
/* Now construct the TX header. */
|
||||
memset(txhdr, 0, sizeof(*txhdr));
|
||||
|
||||
bitrate = bcm->softmac->txrates.default_rate;
|
||||
bitrate = ieee80211softmac_suggest_txrate(bcm->softmac,
|
||||
is_multicast_ether_addr(wireless_header->addr1), is_mgt);
|
||||
ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
|
||||
fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
|
||||
fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
|
||||
|
@ -66,10 +66,12 @@ static struct pci_device_id prism2_plx_id_table[] __devinitdata = {
|
||||
PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
|
||||
PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
|
||||
PLXDEV(0x126c, 0x8030, "Nortel emobility"),
|
||||
PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
|
||||
PLXDEV(0x1385, 0x4100, "Netgear MA301"),
|
||||
PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
|
||||
PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
|
||||
PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
|
||||
PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
|
||||
PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
|
||||
PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
|
||||
PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
|
||||
|
19
drivers/net/wireless/zd1211rw/Kconfig
Normal file
19
drivers/net/wireless/zd1211rw/Kconfig
Normal file
@ -0,0 +1,19 @@
|
||||
config ZD1211RW
|
||||
tristate "ZyDAS ZD1211/ZD1211B USB-wireless support"
|
||||
depends on USB && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL
|
||||
select FW_LOADER
|
||||
---help---
|
||||
This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless
|
||||
chip, present in many USB-wireless adapters.
|
||||
|
||||
Device firmware is required alongside this driver. You can download the
|
||||
firmware distribution from http://zd1211.ath.cx/get-firmware
|
||||
|
||||
config ZD1211RW_DEBUG
|
||||
bool "ZyDAS ZD1211 debugging"
|
||||
depends on ZD1211RW
|
||||
---help---
|
||||
ZD1211 debugging messages. Choosing Y will result in additional debug
|
||||
messages being saved to your kernel logs, which may help debug any
|
||||
problems.
|
||||
|
11
drivers/net/wireless/zd1211rw/Makefile
Normal file
11
drivers/net/wireless/zd1211rw/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
obj-$(CONFIG_ZD1211RW) += zd1211rw.o
|
||||
|
||||
zd1211rw-objs := zd_chip.o zd_ieee80211.o \
|
||||
zd_mac.o zd_netdev.o \
|
||||
zd_rf_al2230.o zd_rf_rf2959.o \
|
||||
zd_rf.o zd_usb.o zd_util.o
|
||||
|
||||
ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
endif
|
||||
|
1615
drivers/net/wireless/zd1211rw/zd_chip.c
Normal file
1615
drivers/net/wireless/zd1211rw/zd_chip.c
Normal file
File diff suppressed because it is too large
Load Diff
825
drivers/net/wireless/zd1211rw/zd_chip.h
Normal file
825
drivers/net/wireless/zd1211rw/zd_chip.h
Normal file
@ -0,0 +1,825 @@
|
||||
/* zd_chip.h
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _ZD_CHIP_H
|
||||
#define _ZD_CHIP_H
|
||||
|
||||
#include "zd_types.h"
|
||||
#include "zd_rf.h"
|
||||
#include "zd_usb.h"
|
||||
|
||||
/* Header for the Media Access Controller (MAC) and the Baseband Processor
|
||||
* (BBP). It appears that the ZD1211 wraps the old ZD1205 with USB glue and
|
||||
* adds a processor for handling the USB protocol.
|
||||
*/
|
||||
|
||||
/* 8-bit hardware registers */
|
||||
#define CR0 CTL_REG(0x0000)
|
||||
#define CR1 CTL_REG(0x0004)
|
||||
#define CR2 CTL_REG(0x0008)
|
||||
#define CR3 CTL_REG(0x000C)
|
||||
|
||||
#define CR5 CTL_REG(0x0010)
|
||||
/* bit 5: if set short preamble used
|
||||
* bit 6: filter band - Japan channel 14 on, else off
|
||||
*/
|
||||
#define CR6 CTL_REG(0x0014)
|
||||
#define CR7 CTL_REG(0x0018)
|
||||
#define CR8 CTL_REG(0x001C)
|
||||
|
||||
#define CR4 CTL_REG(0x0020)
|
||||
|
||||
#define CR9 CTL_REG(0x0024)
|
||||
/* bit 2: antenna switch (together with CR10) */
|
||||
#define CR10 CTL_REG(0x0028)
|
||||
/* bit 1: antenna switch (together with CR9)
|
||||
* RF2959 controls with CR11 radion on and off
|
||||
*/
|
||||
#define CR11 CTL_REG(0x002C)
|
||||
/* bit 6: TX power control for OFDM
|
||||
* RF2959 controls with CR10 radio on and off
|
||||
*/
|
||||
#define CR12 CTL_REG(0x0030)
|
||||
#define CR13 CTL_REG(0x0034)
|
||||
#define CR14 CTL_REG(0x0038)
|
||||
#define CR15 CTL_REG(0x003C)
|
||||
#define CR16 CTL_REG(0x0040)
|
||||
#define CR17 CTL_REG(0x0044)
|
||||
#define CR18 CTL_REG(0x0048)
|
||||
#define CR19 CTL_REG(0x004C)
|
||||
#define CR20 CTL_REG(0x0050)
|
||||
#define CR21 CTL_REG(0x0054)
|
||||
#define CR22 CTL_REG(0x0058)
|
||||
#define CR23 CTL_REG(0x005C)
|
||||
#define CR24 CTL_REG(0x0060) /* CCA threshold */
|
||||
#define CR25 CTL_REG(0x0064)
|
||||
#define CR26 CTL_REG(0x0068)
|
||||
#define CR27 CTL_REG(0x006C)
|
||||
#define CR28 CTL_REG(0x0070)
|
||||
#define CR29 CTL_REG(0x0074)
|
||||
#define CR30 CTL_REG(0x0078)
|
||||
#define CR31 CTL_REG(0x007C) /* TX power control for RF in CCK mode */
|
||||
#define CR32 CTL_REG(0x0080)
|
||||
#define CR33 CTL_REG(0x0084)
|
||||
#define CR34 CTL_REG(0x0088)
|
||||
#define CR35 CTL_REG(0x008C)
|
||||
#define CR36 CTL_REG(0x0090)
|
||||
#define CR37 CTL_REG(0x0094)
|
||||
#define CR38 CTL_REG(0x0098)
|
||||
#define CR39 CTL_REG(0x009C)
|
||||
#define CR40 CTL_REG(0x00A0)
|
||||
#define CR41 CTL_REG(0x00A4)
|
||||
#define CR42 CTL_REG(0x00A8)
|
||||
#define CR43 CTL_REG(0x00AC)
|
||||
#define CR44 CTL_REG(0x00B0)
|
||||
#define CR45 CTL_REG(0x00B4)
|
||||
#define CR46 CTL_REG(0x00B8)
|
||||
#define CR47 CTL_REG(0x00BC) /* CCK baseband gain
|
||||
* (patch value might be in EEPROM)
|
||||
*/
|
||||
#define CR48 CTL_REG(0x00C0)
|
||||
#define CR49 CTL_REG(0x00C4)
|
||||
#define CR50 CTL_REG(0x00C8)
|
||||
#define CR51 CTL_REG(0x00CC) /* TX power control for RF in 6-36M modes */
|
||||
#define CR52 CTL_REG(0x00D0) /* TX power control for RF in 48M mode */
|
||||
#define CR53 CTL_REG(0x00D4) /* TX power control for RF in 54M mode */
|
||||
#define CR54 CTL_REG(0x00D8)
|
||||
#define CR55 CTL_REG(0x00DC)
|
||||
#define CR56 CTL_REG(0x00E0)
|
||||
#define CR57 CTL_REG(0x00E4)
|
||||
#define CR58 CTL_REG(0x00E8)
|
||||
#define CR59 CTL_REG(0x00EC)
|
||||
#define CR60 CTL_REG(0x00F0)
|
||||
#define CR61 CTL_REG(0x00F4)
|
||||
#define CR62 CTL_REG(0x00F8)
|
||||
#define CR63 CTL_REG(0x00FC)
|
||||
#define CR64 CTL_REG(0x0100)
|
||||
#define CR65 CTL_REG(0x0104) /* OFDM 54M calibration */
|
||||
#define CR66 CTL_REG(0x0108) /* OFDM 48M calibration */
|
||||
#define CR67 CTL_REG(0x010C) /* OFDM 36M calibration */
|
||||
#define CR68 CTL_REG(0x0110) /* CCK calibration */
|
||||
#define CR69 CTL_REG(0x0114)
|
||||
#define CR70 CTL_REG(0x0118)
|
||||
#define CR71 CTL_REG(0x011C)
|
||||
#define CR72 CTL_REG(0x0120)
|
||||
#define CR73 CTL_REG(0x0124)
|
||||
#define CR74 CTL_REG(0x0128)
|
||||
#define CR75 CTL_REG(0x012C)
|
||||
#define CR76 CTL_REG(0x0130)
|
||||
#define CR77 CTL_REG(0x0134)
|
||||
#define CR78 CTL_REG(0x0138)
|
||||
#define CR79 CTL_REG(0x013C)
|
||||
#define CR80 CTL_REG(0x0140)
|
||||
#define CR81 CTL_REG(0x0144)
|
||||
#define CR82 CTL_REG(0x0148)
|
||||
#define CR83 CTL_REG(0x014C)
|
||||
#define CR84 CTL_REG(0x0150)
|
||||
#define CR85 CTL_REG(0x0154)
|
||||
#define CR86 CTL_REG(0x0158)
|
||||
#define CR87 CTL_REG(0x015C)
|
||||
#define CR88 CTL_REG(0x0160)
|
||||
#define CR89 CTL_REG(0x0164)
|
||||
#define CR90 CTL_REG(0x0168)
|
||||
#define CR91 CTL_REG(0x016C)
|
||||
#define CR92 CTL_REG(0x0170)
|
||||
#define CR93 CTL_REG(0x0174)
|
||||
#define CR94 CTL_REG(0x0178)
|
||||
#define CR95 CTL_REG(0x017C)
|
||||
#define CR96 CTL_REG(0x0180)
|
||||
#define CR97 CTL_REG(0x0184)
|
||||
#define CR98 CTL_REG(0x0188)
|
||||
#define CR99 CTL_REG(0x018C)
|
||||
#define CR100 CTL_REG(0x0190)
|
||||
#define CR101 CTL_REG(0x0194)
|
||||
#define CR102 CTL_REG(0x0198)
|
||||
#define CR103 CTL_REG(0x019C)
|
||||
#define CR104 CTL_REG(0x01A0)
|
||||
#define CR105 CTL_REG(0x01A4)
|
||||
#define CR106 CTL_REG(0x01A8)
|
||||
#define CR107 CTL_REG(0x01AC)
|
||||
#define CR108 CTL_REG(0x01B0)
|
||||
#define CR109 CTL_REG(0x01B4)
|
||||
#define CR110 CTL_REG(0x01B8)
|
||||
#define CR111 CTL_REG(0x01BC)
|
||||
#define CR112 CTL_REG(0x01C0)
|
||||
#define CR113 CTL_REG(0x01C4)
|
||||
#define CR114 CTL_REG(0x01C8)
|
||||
#define CR115 CTL_REG(0x01CC)
|
||||
#define CR116 CTL_REG(0x01D0)
|
||||
#define CR117 CTL_REG(0x01D4)
|
||||
#define CR118 CTL_REG(0x01D8)
|
||||
#define CR119 CTL_REG(0x01DC)
|
||||
#define CR120 CTL_REG(0x01E0)
|
||||
#define CR121 CTL_REG(0x01E4)
|
||||
#define CR122 CTL_REG(0x01E8)
|
||||
#define CR123 CTL_REG(0x01EC)
|
||||
#define CR124 CTL_REG(0x01F0)
|
||||
#define CR125 CTL_REG(0x01F4)
|
||||
#define CR126 CTL_REG(0x01F8)
|
||||
#define CR127 CTL_REG(0x01FC)
|
||||
#define CR128 CTL_REG(0x0200)
|
||||
#define CR129 CTL_REG(0x0204)
|
||||
#define CR130 CTL_REG(0x0208)
|
||||
#define CR131 CTL_REG(0x020C)
|
||||
#define CR132 CTL_REG(0x0210)
|
||||
#define CR133 CTL_REG(0x0214)
|
||||
#define CR134 CTL_REG(0x0218)
|
||||
#define CR135 CTL_REG(0x021C)
|
||||
#define CR136 CTL_REG(0x0220)
|
||||
#define CR137 CTL_REG(0x0224)
|
||||
#define CR138 CTL_REG(0x0228)
|
||||
#define CR139 CTL_REG(0x022C)
|
||||
#define CR140 CTL_REG(0x0230)
|
||||
#define CR141 CTL_REG(0x0234)
|
||||
#define CR142 CTL_REG(0x0238)
|
||||
#define CR143 CTL_REG(0x023C)
|
||||
#define CR144 CTL_REG(0x0240)
|
||||
#define CR145 CTL_REG(0x0244)
|
||||
#define CR146 CTL_REG(0x0248)
|
||||
#define CR147 CTL_REG(0x024C)
|
||||
#define CR148 CTL_REG(0x0250)
|
||||
#define CR149 CTL_REG(0x0254)
|
||||
#define CR150 CTL_REG(0x0258)
|
||||
#define CR151 CTL_REG(0x025C)
|
||||
#define CR152 CTL_REG(0x0260)
|
||||
#define CR153 CTL_REG(0x0264)
|
||||
#define CR154 CTL_REG(0x0268)
|
||||
#define CR155 CTL_REG(0x026C)
|
||||
#define CR156 CTL_REG(0x0270)
|
||||
#define CR157 CTL_REG(0x0274)
|
||||
#define CR158 CTL_REG(0x0278)
|
||||
#define CR159 CTL_REG(0x027C)
|
||||
#define CR160 CTL_REG(0x0280)
|
||||
#define CR161 CTL_REG(0x0284)
|
||||
#define CR162 CTL_REG(0x0288)
|
||||
#define CR163 CTL_REG(0x028C)
|
||||
#define CR164 CTL_REG(0x0290)
|
||||
#define CR165 CTL_REG(0x0294)
|
||||
#define CR166 CTL_REG(0x0298)
|
||||
#define CR167 CTL_REG(0x029C)
|
||||
#define CR168 CTL_REG(0x02A0)
|
||||
#define CR169 CTL_REG(0x02A4)
|
||||
#define CR170 CTL_REG(0x02A8)
|
||||
#define CR171 CTL_REG(0x02AC)
|
||||
#define CR172 CTL_REG(0x02B0)
|
||||
#define CR173 CTL_REG(0x02B4)
|
||||
#define CR174 CTL_REG(0x02B8)
|
||||
#define CR175 CTL_REG(0x02BC)
|
||||
#define CR176 CTL_REG(0x02C0)
|
||||
#define CR177 CTL_REG(0x02C4)
|
||||
#define CR178 CTL_REG(0x02C8)
|
||||
#define CR179 CTL_REG(0x02CC)
|
||||
#define CR180 CTL_REG(0x02D0)
|
||||
#define CR181 CTL_REG(0x02D4)
|
||||
#define CR182 CTL_REG(0x02D8)
|
||||
#define CR183 CTL_REG(0x02DC)
|
||||
#define CR184 CTL_REG(0x02E0)
|
||||
#define CR185 CTL_REG(0x02E4)
|
||||
#define CR186 CTL_REG(0x02E8)
|
||||
#define CR187 CTL_REG(0x02EC)
|
||||
#define CR188 CTL_REG(0x02F0)
|
||||
#define CR189 CTL_REG(0x02F4)
|
||||
#define CR190 CTL_REG(0x02F8)
|
||||
#define CR191 CTL_REG(0x02FC)
|
||||
#define CR192 CTL_REG(0x0300)
|
||||
#define CR193 CTL_REG(0x0304)
|
||||
#define CR194 CTL_REG(0x0308)
|
||||
#define CR195 CTL_REG(0x030C)
|
||||
#define CR196 CTL_REG(0x0310)
|
||||
#define CR197 CTL_REG(0x0314)
|
||||
#define CR198 CTL_REG(0x0318)
|
||||
#define CR199 CTL_REG(0x031C)
|
||||
#define CR200 CTL_REG(0x0320)
|
||||
#define CR201 CTL_REG(0x0324)
|
||||
#define CR202 CTL_REG(0x0328)
|
||||
#define CR203 CTL_REG(0x032C) /* I2C bus template value & flash control */
|
||||
#define CR204 CTL_REG(0x0330)
|
||||
#define CR205 CTL_REG(0x0334)
|
||||
#define CR206 CTL_REG(0x0338)
|
||||
#define CR207 CTL_REG(0x033C)
|
||||
#define CR208 CTL_REG(0x0340)
|
||||
#define CR209 CTL_REG(0x0344)
|
||||
#define CR210 CTL_REG(0x0348)
|
||||
#define CR211 CTL_REG(0x034C)
|
||||
#define CR212 CTL_REG(0x0350)
|
||||
#define CR213 CTL_REG(0x0354)
|
||||
#define CR214 CTL_REG(0x0358)
|
||||
#define CR215 CTL_REG(0x035C)
|
||||
#define CR216 CTL_REG(0x0360)
|
||||
#define CR217 CTL_REG(0x0364)
|
||||
#define CR218 CTL_REG(0x0368)
|
||||
#define CR219 CTL_REG(0x036C)
|
||||
#define CR220 CTL_REG(0x0370)
|
||||
#define CR221 CTL_REG(0x0374)
|
||||
#define CR222 CTL_REG(0x0378)
|
||||
#define CR223 CTL_REG(0x037C)
|
||||
#define CR224 CTL_REG(0x0380)
|
||||
#define CR225 CTL_REG(0x0384)
|
||||
#define CR226 CTL_REG(0x0388)
|
||||
#define CR227 CTL_REG(0x038C)
|
||||
#define CR228 CTL_REG(0x0390)
|
||||
#define CR229 CTL_REG(0x0394)
|
||||
#define CR230 CTL_REG(0x0398)
|
||||
#define CR231 CTL_REG(0x039C)
|
||||
#define CR232 CTL_REG(0x03A0)
|
||||
#define CR233 CTL_REG(0x03A4)
|
||||
#define CR234 CTL_REG(0x03A8)
|
||||
#define CR235 CTL_REG(0x03AC)
|
||||
#define CR236 CTL_REG(0x03B0)
|
||||
|
||||
#define CR240 CTL_REG(0x03C0)
|
||||
/* bit 7: host-controlled RF register writes
|
||||
* CR241-CR245: for hardware controlled writing of RF bits, not needed for
|
||||
* USB
|
||||
*/
|
||||
#define CR241 CTL_REG(0x03C4)
|
||||
#define CR242 CTL_REG(0x03C8)
|
||||
#define CR243 CTL_REG(0x03CC)
|
||||
#define CR244 CTL_REG(0x03D0)
|
||||
#define CR245 CTL_REG(0x03D4)
|
||||
|
||||
#define CR251 CTL_REG(0x03EC) /* only used for activation and deactivation of
|
||||
* Airoha RFs AL2230 and AL7230B
|
||||
*/
|
||||
#define CR252 CTL_REG(0x03F0)
|
||||
#define CR253 CTL_REG(0x03F4)
|
||||
#define CR254 CTL_REG(0x03F8)
|
||||
#define CR255 CTL_REG(0x03FC)
|
||||
|
||||
#define CR_MAX_PHY_REG 255
|
||||
|
||||
/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211
|
||||
* driver.
|
||||
*/
|
||||
|
||||
#define CR_RF_IF_CLK CTL_REG(0x0400)
|
||||
#define CR_RF_IF_DATA CTL_REG(0x0404)
|
||||
#define CR_PE1_PE2 CTL_REG(0x0408)
|
||||
#define CR_PE2_DLY CTL_REG(0x040C)
|
||||
#define CR_LE1 CTL_REG(0x0410)
|
||||
#define CR_LE2 CTL_REG(0x0414)
|
||||
/* Seems to enable/disable GPI (General Purpose IO?) */
|
||||
#define CR_GPI_EN CTL_REG(0x0418)
|
||||
#define CR_RADIO_PD CTL_REG(0x042C)
|
||||
#define CR_RF2948_PD CTL_REG(0x042C)
|
||||
#define CR_ENABLE_PS_MANUAL_AGC CTL_REG(0x043C)
|
||||
#define CR_CONFIG_PHILIPS CTL_REG(0x0440)
|
||||
#define CR_SA2400_SER_AP CTL_REG(0x0444)
|
||||
#define CR_I2C_WRITE CTL_REG(0x0444)
|
||||
#define CR_SA2400_SER_RP CTL_REG(0x0448)
|
||||
#define CR_RADIO_PE CTL_REG(0x0458)
|
||||
#define CR_RST_BUS_MASTER CTL_REG(0x045C)
|
||||
#define CR_RFCFG CTL_REG(0x0464)
|
||||
#define CR_HSTSCHG CTL_REG(0x046C)
|
||||
#define CR_PHY_ON CTL_REG(0x0474)
|
||||
#define CR_RX_DELAY CTL_REG(0x0478)
|
||||
#define CR_RX_PE_DELAY CTL_REG(0x047C)
|
||||
#define CR_GPIO_1 CTL_REG(0x0490)
|
||||
#define CR_GPIO_2 CTL_REG(0x0494)
|
||||
#define CR_EncryBufMux CTL_REG(0x04A8)
|
||||
#define CR_PS_CTRL CTL_REG(0x0500)
|
||||
#define CR_ADDA_PWR_DWN CTL_REG(0x0504)
|
||||
#define CR_ADDA_MBIAS_WARMTIME CTL_REG(0x0508)
|
||||
#define CR_MAC_PS_STATE CTL_REG(0x050C)
|
||||
|
||||
#define CR_INTERRUPT CTL_REG(0x0510)
|
||||
#define INT_TX_COMPLETE 0x00000001
|
||||
#define INT_RX_COMPLETE 0x00000002
|
||||
#define INT_RETRY_FAIL 0x00000004
|
||||
#define INT_WAKEUP 0x00000008
|
||||
#define INT_DTIM_NOTIFY 0x00000020
|
||||
#define INT_CFG_NEXT_BCN 0x00000040
|
||||
#define INT_BUS_ABORT 0x00000080
|
||||
#define INT_TX_FIFO_READY 0x00000100
|
||||
#define INT_UART 0x00000200
|
||||
#define INT_TX_COMPLETE_EN 0x00010000
|
||||
#define INT_RX_COMPLETE_EN 0x00020000
|
||||
#define INT_RETRY_FAIL_EN 0x00040000
|
||||
#define INT_WAKEUP_EN 0x00080000
|
||||
#define INT_DTIM_NOTIFY_EN 0x00200000
|
||||
#define INT_CFG_NEXT_BCN_EN 0x00400000
|
||||
#define INT_BUS_ABORT_EN 0x00800000
|
||||
#define INT_TX_FIFO_READY_EN 0x01000000
|
||||
#define INT_UART_EN 0x02000000
|
||||
|
||||
#define CR_TSF_LOW_PART CTL_REG(0x0514)
|
||||
#define CR_TSF_HIGH_PART CTL_REG(0x0518)
|
||||
|
||||
/* Following three values are in time units (1024us)
|
||||
* Following condition must be met:
|
||||
* atim < tbtt < bcn
|
||||
*/
|
||||
#define CR_ATIM_WND_PERIOD CTL_REG(0x051C)
|
||||
#define CR_BCN_INTERVAL CTL_REG(0x0520)
|
||||
#define CR_PRE_TBTT CTL_REG(0x0524)
|
||||
/* in units of TU(1024us) */
|
||||
|
||||
/* for UART support */
|
||||
#define CR_UART_RBR_THR_DLL CTL_REG(0x0540)
|
||||
#define CR_UART_DLM_IER CTL_REG(0x0544)
|
||||
#define CR_UART_IIR_FCR CTL_REG(0x0548)
|
||||
#define CR_UART_LCR CTL_REG(0x054c)
|
||||
#define CR_UART_MCR CTL_REG(0x0550)
|
||||
#define CR_UART_LSR CTL_REG(0x0554)
|
||||
#define CR_UART_MSR CTL_REG(0x0558)
|
||||
#define CR_UART_ECR CTL_REG(0x055c)
|
||||
#define CR_UART_STATUS CTL_REG(0x0560)
|
||||
|
||||
#define CR_PCI_TX_ADDR_P1 CTL_REG(0x0600)
|
||||
#define CR_PCI_TX_AddR_P2 CTL_REG(0x0604)
|
||||
#define CR_PCI_RX_AddR_P1 CTL_REG(0x0608)
|
||||
#define CR_PCI_RX_AddR_P2 CTL_REG(0x060C)
|
||||
|
||||
/* must be overwritten if custom MAC address will be used */
|
||||
#define CR_MAC_ADDR_P1 CTL_REG(0x0610)
|
||||
#define CR_MAC_ADDR_P2 CTL_REG(0x0614)
|
||||
#define CR_BSSID_P1 CTL_REG(0x0618)
|
||||
#define CR_BSSID_P2 CTL_REG(0x061C)
|
||||
#define CR_BCN_PLCP_CFG CTL_REG(0x0620)
|
||||
#define CR_GROUP_HASH_P1 CTL_REG(0x0624)
|
||||
#define CR_GROUP_HASH_P2 CTL_REG(0x0628)
|
||||
#define CR_RX_TIMEOUT CTL_REG(0x062C)
|
||||
|
||||
/* Basic rates supported by the BSS. When producing ACK or CTS messages, the
|
||||
* device will use a rate in this table that is less than or equal to the rate
|
||||
* of the incoming frame which prompted the response */
|
||||
#define CR_BASIC_RATE_TBL CTL_REG(0x0630)
|
||||
#define CR_RATE_1M 0x0001 /* 802.11b */
|
||||
#define CR_RATE_2M 0x0002 /* 802.11b */
|
||||
#define CR_RATE_5_5M 0x0004 /* 802.11b */
|
||||
#define CR_RATE_11M 0x0008 /* 802.11b */
|
||||
#define CR_RATE_6M 0x0100 /* 802.11g */
|
||||
#define CR_RATE_9M 0x0200 /* 802.11g */
|
||||
#define CR_RATE_12M 0x0400 /* 802.11g */
|
||||
#define CR_RATE_18M 0x0800 /* 802.11g */
|
||||
#define CR_RATE_24M 0x1000 /* 802.11g */
|
||||
#define CR_RATE_36M 0x2000 /* 802.11g */
|
||||
#define CR_RATE_48M 0x4000 /* 802.11g */
|
||||
#define CR_RATE_54M 0x8000 /* 802.11g */
|
||||
#define CR_RATES_80211G 0xff00
|
||||
#define CR_RATES_80211B 0x000f
|
||||
|
||||
/* Mandatory rates required in the BSS. When producing ACK or CTS messages, if
|
||||
* the device could not find an appropriate rate in CR_BASIC_RATE_TBL, it will
|
||||
* look for a rate in this table that is less than or equal to the rate of
|
||||
* the incoming frame. */
|
||||
#define CR_MANDATORY_RATE_TBL CTL_REG(0x0634)
|
||||
#define CR_RTS_CTS_RATE CTL_REG(0x0638)
|
||||
|
||||
#define CR_WEP_PROTECT CTL_REG(0x063C)
|
||||
#define CR_RX_THRESHOLD CTL_REG(0x0640)
|
||||
|
||||
/* register for controlling the LEDS */
|
||||
#define CR_LED CTL_REG(0x0644)
|
||||
/* masks for controlling LEDs */
|
||||
#define LED1 0x0100
|
||||
#define LED2 0x0200
|
||||
|
||||
/* Seems to indicate that the configuration is over.
|
||||
*/
|
||||
#define CR_AFTER_PNP CTL_REG(0x0648)
|
||||
#define CR_ACK_TIME_80211 CTL_REG(0x0658)
|
||||
|
||||
#define CR_RX_OFFSET CTL_REG(0x065c)
|
||||
|
||||
#define CR_PHY_DELAY CTL_REG(0x066C)
|
||||
#define CR_BCN_FIFO CTL_REG(0x0670)
|
||||
#define CR_SNIFFER_ON CTL_REG(0x0674)
|
||||
|
||||
#define CR_ENCRYPTION_TYPE CTL_REG(0x0678)
|
||||
#define NO_WEP 0
|
||||
#define WEP64 1
|
||||
#define WEP128 5
|
||||
#define WEP256 6
|
||||
#define ENC_SNIFFER 8
|
||||
|
||||
#define CR_ZD1211_RETRY_MAX CTL_REG(0x067C)
|
||||
|
||||
#define CR_REG1 CTL_REG(0x0680)
|
||||
/* Setting the bit UNLOCK_PHY_REGS disallows the write access to physical
|
||||
* registers, so one could argue it is a LOCK bit. But calling it
|
||||
* LOCK_PHY_REGS makes it confusing.
|
||||
*/
|
||||
#define UNLOCK_PHY_REGS 0x0080
|
||||
|
||||
#define CR_DEVICE_STATE CTL_REG(0x0684)
|
||||
#define CR_UNDERRUN_CNT CTL_REG(0x0688)
|
||||
|
||||
#define CR_RX_FILTER CTL_REG(0x068c)
|
||||
#define RX_FILTER_ASSOC_RESPONSE 0x0002
|
||||
#define RX_FILTER_PROBE_RESPONSE 0x0020
|
||||
#define RX_FILTER_BEACON 0x0100
|
||||
#define RX_FILTER_AUTH 0x0800
|
||||
/* Sniff modus sets filter to 0xfffff */
|
||||
|
||||
#define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690)
|
||||
#define CR_BCN_FIFO_SEMAPHORE CTL_REG(0x0694)
|
||||
#define CR_IFS_VALUE CTL_REG(0x0698)
|
||||
#define CR_RX_TIME_OUT CTL_REG(0x069C)
|
||||
#define CR_TOTAL_RX_FRM CTL_REG(0x06A0)
|
||||
#define CR_CRC32_CNT CTL_REG(0x06A4)
|
||||
#define CR_CRC16_CNT CTL_REG(0x06A8)
|
||||
#define CR_DECRYPTION_ERR_UNI CTL_REG(0x06AC)
|
||||
#define CR_RX_FIFO_OVERRUN CTL_REG(0x06B0)
|
||||
|
||||
#define CR_DECRYPTION_ERR_MUL CTL_REG(0x06BC)
|
||||
|
||||
#define CR_NAV_CNT CTL_REG(0x06C4)
|
||||
#define CR_NAV_CCA CTL_REG(0x06C8)
|
||||
#define CR_RETRY_CNT CTL_REG(0x06CC)
|
||||
|
||||
#define CR_READ_TCB_ADDR CTL_REG(0x06E8)
|
||||
#define CR_READ_RFD_ADDR CTL_REG(0x06EC)
|
||||
#define CR_CWMIN_CWMAX CTL_REG(0x06F0)
|
||||
#define CR_TOTAL_TX_FRM CTL_REG(0x06F4)
|
||||
|
||||
/* CAM: Continuous Access Mode (power management) */
|
||||
#define CR_CAM_MODE CTL_REG(0x0700)
|
||||
#define CR_CAM_ROLL_TB_LOW CTL_REG(0x0704)
|
||||
#define CR_CAM_ROLL_TB_HIGH CTL_REG(0x0708)
|
||||
#define CR_CAM_ADDRESS CTL_REG(0x070C)
|
||||
#define CR_CAM_DATA CTL_REG(0x0710)
|
||||
|
||||
#define CR_ROMDIR CTL_REG(0x0714)
|
||||
|
||||
#define CR_DECRY_ERR_FLG_LOW CTL_REG(0x0714)
|
||||
#define CR_DECRY_ERR_FLG_HIGH CTL_REG(0x0718)
|
||||
|
||||
#define CR_WEPKEY0 CTL_REG(0x0720)
|
||||
#define CR_WEPKEY1 CTL_REG(0x0724)
|
||||
#define CR_WEPKEY2 CTL_REG(0x0728)
|
||||
#define CR_WEPKEY3 CTL_REG(0x072C)
|
||||
#define CR_WEPKEY4 CTL_REG(0x0730)
|
||||
#define CR_WEPKEY5 CTL_REG(0x0734)
|
||||
#define CR_WEPKEY6 CTL_REG(0x0738)
|
||||
#define CR_WEPKEY7 CTL_REG(0x073C)
|
||||
#define CR_WEPKEY8 CTL_REG(0x0740)
|
||||
#define CR_WEPKEY9 CTL_REG(0x0744)
|
||||
#define CR_WEPKEY10 CTL_REG(0x0748)
|
||||
#define CR_WEPKEY11 CTL_REG(0x074C)
|
||||
#define CR_WEPKEY12 CTL_REG(0x0750)
|
||||
#define CR_WEPKEY13 CTL_REG(0x0754)
|
||||
#define CR_WEPKEY14 CTL_REG(0x0758)
|
||||
#define CR_WEPKEY15 CTL_REG(0x075c)
|
||||
#define CR_TKIP_MODE CTL_REG(0x0760)
|
||||
|
||||
#define CR_EEPROM_PROTECT0 CTL_REG(0x0758)
|
||||
#define CR_EEPROM_PROTECT1 CTL_REG(0x075C)
|
||||
|
||||
#define CR_DBG_FIFO_RD CTL_REG(0x0800)
|
||||
#define CR_DBG_SELECT CTL_REG(0x0804)
|
||||
#define CR_FIFO_Length CTL_REG(0x0808)
|
||||
|
||||
|
||||
#define CR_RSSI_MGC CTL_REG(0x0810)
|
||||
|
||||
#define CR_PON CTL_REG(0x0818)
|
||||
#define CR_RX_ON CTL_REG(0x081C)
|
||||
#define CR_TX_ON CTL_REG(0x0820)
|
||||
#define CR_CHIP_EN CTL_REG(0x0824)
|
||||
#define CR_LO_SW CTL_REG(0x0828)
|
||||
#define CR_TXRX_SW CTL_REG(0x082C)
|
||||
#define CR_S_MD CTL_REG(0x0830)
|
||||
|
||||
#define CR_USB_DEBUG_PORT CTL_REG(0x0888)
|
||||
|
||||
#define CR_ZD1211B_TX_PWR_CTL1 CTL_REG(0x0b00)
|
||||
#define CR_ZD1211B_TX_PWR_CTL2 CTL_REG(0x0b04)
|
||||
#define CR_ZD1211B_TX_PWR_CTL3 CTL_REG(0x0b08)
|
||||
#define CR_ZD1211B_TX_PWR_CTL4 CTL_REG(0x0b0c)
|
||||
#define CR_ZD1211B_AIFS_CTL1 CTL_REG(0x0b10)
|
||||
#define CR_ZD1211B_AIFS_CTL2 CTL_REG(0x0b14)
|
||||
#define CR_ZD1211B_TXOP CTL_REG(0x0b20)
|
||||
#define CR_ZD1211B_RETRY_MAX CTL_REG(0x0b28)
|
||||
|
||||
#define AP_RX_FILTER 0x0400feff
|
||||
#define STA_RX_FILTER 0x0000ffff
|
||||
|
||||
#define CWIN_SIZE 0x007f043f
|
||||
|
||||
|
||||
#define HWINT_ENABLED 0x004f0000
|
||||
#define HWINT_DISABLED 0
|
||||
|
||||
#define E2P_PWR_INT_GUARD 8
|
||||
#define E2P_CHANNEL_COUNT 14
|
||||
|
||||
/* If you compare this addresses with the ZYDAS orignal driver, please notify
|
||||
* that we use word mapping for the EEPROM.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Upper 16 bit contains the regulatory domain.
|
||||
*/
|
||||
#define E2P_SUBID E2P_REG(0x00)
|
||||
#define E2P_POD E2P_REG(0x02)
|
||||
#define E2P_MAC_ADDR_P1 E2P_REG(0x04)
|
||||
#define E2P_MAC_ADDR_P2 E2P_REG(0x06)
|
||||
#define E2P_PWR_CAL_VALUE1 E2P_REG(0x08)
|
||||
#define E2P_PWR_CAL_VALUE2 E2P_REG(0x0a)
|
||||
#define E2P_PWR_CAL_VALUE3 E2P_REG(0x0c)
|
||||
#define E2P_PWR_CAL_VALUE4 E2P_REG(0x0e)
|
||||
#define E2P_PWR_INT_VALUE1 E2P_REG(0x10)
|
||||
#define E2P_PWR_INT_VALUE2 E2P_REG(0x12)
|
||||
#define E2P_PWR_INT_VALUE3 E2P_REG(0x14)
|
||||
#define E2P_PWR_INT_VALUE4 E2P_REG(0x16)
|
||||
|
||||
/* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30)
|
||||
* also only 11 channels. */
|
||||
#define E2P_ALLOWED_CHANNEL E2P_REG(0x18)
|
||||
|
||||
#define E2P_PHY_REG E2P_REG(0x1a)
|
||||
#define E2P_DEVICE_VER E2P_REG(0x20)
|
||||
#define E2P_36M_CAL_VALUE1 E2P_REG(0x28)
|
||||
#define E2P_36M_CAL_VALUE2 E2P_REG(0x2a)
|
||||
#define E2P_36M_CAL_VALUE3 E2P_REG(0x2c)
|
||||
#define E2P_36M_CAL_VALUE4 E2P_REG(0x2e)
|
||||
#define E2P_11A_INT_VALUE1 E2P_REG(0x30)
|
||||
#define E2P_11A_INT_VALUE2 E2P_REG(0x32)
|
||||
#define E2P_11A_INT_VALUE3 E2P_REG(0x34)
|
||||
#define E2P_11A_INT_VALUE4 E2P_REG(0x36)
|
||||
#define E2P_48M_CAL_VALUE1 E2P_REG(0x38)
|
||||
#define E2P_48M_CAL_VALUE2 E2P_REG(0x3a)
|
||||
#define E2P_48M_CAL_VALUE3 E2P_REG(0x3c)
|
||||
#define E2P_48M_CAL_VALUE4 E2P_REG(0x3e)
|
||||
#define E2P_48M_INT_VALUE1 E2P_REG(0x40)
|
||||
#define E2P_48M_INT_VALUE2 E2P_REG(0x42)
|
||||
#define E2P_48M_INT_VALUE3 E2P_REG(0x44)
|
||||
#define E2P_48M_INT_VALUE4 E2P_REG(0x46)
|
||||
#define E2P_54M_CAL_VALUE1 E2P_REG(0x48) /* ??? */
|
||||
#define E2P_54M_CAL_VALUE2 E2P_REG(0x4a)
|
||||
#define E2P_54M_CAL_VALUE3 E2P_REG(0x4c)
|
||||
#define E2P_54M_CAL_VALUE4 E2P_REG(0x4e)
|
||||
#define E2P_54M_INT_VALUE1 E2P_REG(0x50)
|
||||
#define E2P_54M_INT_VALUE2 E2P_REG(0x52)
|
||||
#define E2P_54M_INT_VALUE3 E2P_REG(0x54)
|
||||
#define E2P_54M_INT_VALUE4 E2P_REG(0x56)
|
||||
|
||||
/* All 16 bit values */
|
||||
#define FW_FIRMWARE_VER FW_REG(0)
|
||||
/* non-zero if USB high speed connection */
|
||||
#define FW_USB_SPEED FW_REG(1)
|
||||
#define FW_FIX_TX_RATE FW_REG(2)
|
||||
/* Seems to be able to control LEDs over the firmware */
|
||||
#define FW_LINK_STATUS FW_REG(3)
|
||||
#define FW_SOFT_RESET FW_REG(4)
|
||||
#define FW_FLASH_CHK FW_REG(5)
|
||||
|
||||
enum {
|
||||
CR_BASE_OFFSET = 0x9000,
|
||||
FW_START_OFFSET = 0xee00,
|
||||
FW_BASE_ADDR_OFFSET = FW_START_OFFSET + 0x1d,
|
||||
EEPROM_START_OFFSET = 0xf800,
|
||||
EEPROM_SIZE = 0x800, /* words */
|
||||
LOAD_CODE_SIZE = 0xe, /* words */
|
||||
LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */
|
||||
EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE,
|
||||
E2P_BASE_OFFSET = EEPROM_START_OFFSET +
|
||||
EEPROM_REGS_OFFSET,
|
||||
};
|
||||
|
||||
#define FW_REG_TABLE_ADDR USB_ADDR(FW_START_OFFSET + 0x1d)
|
||||
|
||||
enum {
|
||||
/* indices for ofdm_cal_values */
|
||||
OFDM_36M_INDEX = 0,
|
||||
OFDM_48M_INDEX = 1,
|
||||
OFDM_54M_INDEX = 2,
|
||||
};
|
||||
|
||||
struct zd_chip {
|
||||
struct zd_usb usb;
|
||||
struct zd_rf rf;
|
||||
struct mutex mutex;
|
||||
u8 e2p_mac[ETH_ALEN];
|
||||
/* EepSetPoint in the vendor driver */
|
||||
u8 pwr_cal_values[E2P_CHANNEL_COUNT];
|
||||
/* integration values in the vendor driver */
|
||||
u8 pwr_int_values[E2P_CHANNEL_COUNT];
|
||||
/* SetPointOFDM in the vendor driver */
|
||||
u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT];
|
||||
u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
|
||||
is_zd1211b:1;
|
||||
};
|
||||
|
||||
static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
|
||||
{
|
||||
return container_of(usb, struct zd_chip, usb);
|
||||
}
|
||||
|
||||
static inline struct zd_chip *zd_rf_to_chip(struct zd_rf *rf)
|
||||
{
|
||||
return container_of(rf, struct zd_chip, rf);
|
||||
}
|
||||
|
||||
#define zd_chip_dev(chip) (&(chip)->usb.intf->dev)
|
||||
|
||||
void zd_chip_init(struct zd_chip *chip,
|
||||
struct net_device *netdev,
|
||||
struct usb_interface *intf);
|
||||
void zd_chip_clear(struct zd_chip *chip);
|
||||
int zd_chip_init_hw(struct zd_chip *chip, u8 device_type);
|
||||
int zd_chip_reset(struct zd_chip *chip);
|
||||
|
||||
static inline int zd_ioread16v_locked(struct zd_chip *chip, u16 *values,
|
||||
const zd_addr_t *addresses,
|
||||
unsigned int count)
|
||||
{
|
||||
ZD_ASSERT(mutex_is_locked(&chip->mutex));
|
||||
return zd_usb_ioread16v(&chip->usb, values, addresses, count);
|
||||
}
|
||||
|
||||
static inline int zd_ioread16_locked(struct zd_chip *chip, u16 *value,
|
||||
const zd_addr_t addr)
|
||||
{
|
||||
ZD_ASSERT(mutex_is_locked(&chip->mutex));
|
||||
return zd_usb_ioread16(&chip->usb, value, addr);
|
||||
}
|
||||
|
||||
int zd_ioread32v_locked(struct zd_chip *chip, u32 *values,
|
||||
const zd_addr_t *addresses, unsigned int count);
|
||||
|
||||
static inline int zd_ioread32_locked(struct zd_chip *chip, u32 *value,
|
||||
const zd_addr_t addr)
|
||||
{
|
||||
return zd_ioread32v_locked(chip, value, (const zd_addr_t *)&addr, 1);
|
||||
}
|
||||
|
||||
static inline int zd_iowrite16_locked(struct zd_chip *chip, u16 value,
|
||||
zd_addr_t addr)
|
||||
{
|
||||
struct zd_ioreq16 ioreq;
|
||||
|
||||
ZD_ASSERT(mutex_is_locked(&chip->mutex));
|
||||
ioreq.addr = addr;
|
||||
ioreq.value = value;
|
||||
|
||||
return zd_usb_iowrite16v(&chip->usb, &ioreq, 1);
|
||||
}
|
||||
|
||||
int zd_iowrite16a_locked(struct zd_chip *chip,
|
||||
const struct zd_ioreq16 *ioreqs, unsigned int count);
|
||||
|
||||
int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
|
||||
unsigned int count);
|
||||
|
||||
static inline int zd_iowrite32_locked(struct zd_chip *chip, u32 value,
|
||||
zd_addr_t addr)
|
||||
{
|
||||
struct zd_ioreq32 ioreq;
|
||||
|
||||
ioreq.addr = addr;
|
||||
ioreq.value = value;
|
||||
|
||||
return _zd_iowrite32v_locked(chip, &ioreq, 1);
|
||||
}
|
||||
|
||||
int zd_iowrite32a_locked(struct zd_chip *chip,
|
||||
const struct zd_ioreq32 *ioreqs, unsigned int count);
|
||||
|
||||
static inline int zd_rfwrite_locked(struct zd_chip *chip, u32 value, u8 bits)
|
||||
{
|
||||
ZD_ASSERT(mutex_is_locked(&chip->mutex));
|
||||
return zd_usb_rfwrite(&chip->usb, value, bits);
|
||||
}
|
||||
|
||||
int zd_rfwritev_locked(struct zd_chip *chip,
|
||||
const u32* values, unsigned int count, u8 bits);
|
||||
|
||||
/* Locking functions for reading and writing registers.
|
||||
* The different parameters are intentional.
|
||||
*/
|
||||
int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value);
|
||||
int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value);
|
||||
int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value);
|
||||
int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value);
|
||||
int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses,
|
||||
u32 *values, unsigned int count);
|
||||
int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
|
||||
unsigned int count);
|
||||
|
||||
int zd_chip_set_channel(struct zd_chip *chip, u8 channel);
|
||||
static inline u8 _zd_chip_get_channel(struct zd_chip *chip)
|
||||
{
|
||||
return chip->rf.channel;
|
||||
}
|
||||
u8 zd_chip_get_channel(struct zd_chip *chip);
|
||||
int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain);
|
||||
void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr);
|
||||
int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr);
|
||||
int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr);
|
||||
int zd_chip_switch_radio_on(struct zd_chip *chip);
|
||||
int zd_chip_switch_radio_off(struct zd_chip *chip);
|
||||
int zd_chip_enable_int(struct zd_chip *chip);
|
||||
void zd_chip_disable_int(struct zd_chip *chip);
|
||||
int zd_chip_enable_rx(struct zd_chip *chip);
|
||||
void zd_chip_disable_rx(struct zd_chip *chip);
|
||||
int zd_chip_enable_hwint(struct zd_chip *chip);
|
||||
int zd_chip_disable_hwint(struct zd_chip *chip);
|
||||
|
||||
static inline int zd_get_encryption_type(struct zd_chip *chip, u32 *type)
|
||||
{
|
||||
return zd_ioread32(chip, CR_ENCRYPTION_TYPE, type);
|
||||
}
|
||||
|
||||
static inline int zd_set_encryption_type(struct zd_chip *chip, u32 type)
|
||||
{
|
||||
return zd_iowrite32(chip, CR_ENCRYPTION_TYPE, type);
|
||||
}
|
||||
|
||||
static inline int zd_chip_get_basic_rates(struct zd_chip *chip, u16 *cr_rates)
|
||||
{
|
||||
return zd_ioread16(chip, CR_BASIC_RATE_TBL, cr_rates);
|
||||
}
|
||||
|
||||
int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates);
|
||||
|
||||
static inline int zd_chip_set_rx_filter(struct zd_chip *chip, u32 filter)
|
||||
{
|
||||
return zd_iowrite32(chip, CR_RX_FILTER, filter);
|
||||
}
|
||||
|
||||
int zd_chip_lock_phy_regs(struct zd_chip *chip);
|
||||
int zd_chip_unlock_phy_regs(struct zd_chip *chip);
|
||||
|
||||
enum led_status {
|
||||
LED_OFF = 0,
|
||||
LED_ON = 1,
|
||||
LED_FLIP = 2,
|
||||
LED_STATUS = 3,
|
||||
};
|
||||
|
||||
int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status);
|
||||
int zd_chip_led_flip(struct zd_chip *chip, int led,
|
||||
const unsigned int *phases_msecs, unsigned int count);
|
||||
|
||||
int zd_set_beacon_interval(struct zd_chip *chip, u32 interval);
|
||||
|
||||
static inline int zd_get_beacon_interval(struct zd_chip *chip, u32 *interval)
|
||||
{
|
||||
return zd_ioread32(chip, CR_BCN_INTERVAL, interval);
|
||||
}
|
||||
|
||||
struct rx_status;
|
||||
|
||||
u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
|
||||
const struct rx_status *status);
|
||||
u8 zd_rx_strength_percent(u8 rssi);
|
||||
|
||||
u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
|
||||
|
||||
#endif /* _ZD_CHIP_H */
|
48
drivers/net/wireless/zd1211rw/zd_def.h
Normal file
48
drivers/net/wireless/zd1211rw/zd_def.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* zd_def.h
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _ZD_DEF_H
|
||||
#define _ZD_DEF_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#define dev_printk_f(level, dev, fmt, args...) \
|
||||
dev_printk(level, dev, "%s() " fmt, __func__, ##args)
|
||||
|
||||
#ifdef DEBUG
|
||||
# define dev_dbg_f(dev, fmt, args...) \
|
||||
dev_printk_f(KERN_DEBUG, dev, fmt, ## args)
|
||||
#else
|
||||
# define dev_dbg_f(dev, fmt, args...) do { (void)(dev); } while (0)
|
||||
#endif /* DEBUG */
|
||||
|
||||
#ifdef DEBUG
|
||||
# define ZD_ASSERT(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
pr_debug("%s:%d ASSERT %s VIOLATED!\n", \
|
||||
__FILE__, __LINE__, __stringify(x)); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
# define ZD_ASSERT(x) do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif /* _ZD_DEF_H */
|
191
drivers/net/wireless/zd1211rw/zd_ieee80211.c
Normal file
191
drivers/net/wireless/zd1211rw/zd_ieee80211.c
Normal file
@ -0,0 +1,191 @@
|
||||
/* zd_ieee80211.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* A lot of this code is generic and should be moved into the upper layers
|
||||
* at some point.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <net/ieee80211.h>
|
||||
|
||||
#include "zd_def.h"
|
||||
#include "zd_ieee80211.h"
|
||||
#include "zd_mac.h"
|
||||
|
||||
static const struct channel_range channel_ranges[] = {
|
||||
[0] = { 0, 0},
|
||||
[ZD_REGDOMAIN_FCC] = { 1, 12},
|
||||
[ZD_REGDOMAIN_IC] = { 1, 12},
|
||||
[ZD_REGDOMAIN_ETSI] = { 1, 14},
|
||||
[ZD_REGDOMAIN_JAPAN] = { 1, 14},
|
||||
[ZD_REGDOMAIN_SPAIN] = { 1, 14},
|
||||
[ZD_REGDOMAIN_FRANCE] = { 1, 14},
|
||||
[ZD_REGDOMAIN_JAPAN_ADD] = {14, 15},
|
||||
};
|
||||
|
||||
const struct channel_range *zd_channel_range(u8 regdomain)
|
||||
{
|
||||
if (regdomain >= ARRAY_SIZE(channel_ranges))
|
||||
regdomain = 0;
|
||||
return &channel_ranges[regdomain];
|
||||
}
|
||||
|
||||
int zd_regdomain_supports_channel(u8 regdomain, u8 channel)
|
||||
{
|
||||
const struct channel_range *range = zd_channel_range(regdomain);
|
||||
return range->start <= channel && channel < range->end;
|
||||
}
|
||||
|
||||
int zd_regdomain_supported(u8 regdomain)
|
||||
{
|
||||
const struct channel_range *range = zd_channel_range(regdomain);
|
||||
return range->start != 0;
|
||||
}
|
||||
|
||||
/* Stores channel frequencies in MHz. */
|
||||
static const u16 channel_frequencies[] = {
|
||||
2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447,
|
||||
2452, 2457, 2462, 2467, 2472, 2484,
|
||||
};
|
||||
|
||||
#define NUM_CHANNELS ARRAY_SIZE(channel_frequencies)
|
||||
|
||||
static int compute_freq(struct iw_freq *freq, u32 mhz, u32 hz)
|
||||
{
|
||||
u32 factor;
|
||||
|
||||
freq->e = 0;
|
||||
if (mhz >= 1000000000U) {
|
||||
pr_debug("zd1211 mhz %u to large\n", mhz);
|
||||
freq->m = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
factor = 1000;
|
||||
while (mhz >= factor) {
|
||||
|
||||
freq->e += 1;
|
||||
factor *= 10;
|
||||
}
|
||||
|
||||
factor /= 1000U;
|
||||
freq->m = mhz * (1000000U/factor) + hz/factor;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zd_channel_to_freq(struct iw_freq *freq, u8 channel)
|
||||
{
|
||||
if (channel > NUM_CHANNELS) {
|
||||
freq->m = 0;
|
||||
freq->e = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!channel) {
|
||||
freq->m = 0;
|
||||
freq->e = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
return compute_freq(freq, channel_frequencies[channel-1], 0);
|
||||
}
|
||||
|
||||
static int freq_to_mhz(const struct iw_freq *freq)
|
||||
{
|
||||
u32 factor;
|
||||
int e;
|
||||
|
||||
/* Such high frequencies are not supported. */
|
||||
if (freq->e > 6)
|
||||
return -EINVAL;
|
||||
|
||||
factor = 1;
|
||||
for (e = freq->e; e > 0; --e) {
|
||||
factor *= 10;
|
||||
}
|
||||
factor = 1000000U / factor;
|
||||
|
||||
if (freq->m % factor) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return freq->m / factor;
|
||||
}
|
||||
|
||||
int zd_find_channel(u8 *channel, const struct iw_freq *freq)
|
||||
{
|
||||
int i, r;
|
||||
u32 mhz;
|
||||
|
||||
if (!(freq->flags & IW_FREQ_FIXED))
|
||||
return 0;
|
||||
|
||||
if (freq->m < 1000) {
|
||||
if (freq->m > NUM_CHANNELS || freq->m == 0)
|
||||
return -EINVAL;
|
||||
*channel = freq->m;
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = freq_to_mhz(freq);
|
||||
if (r < 0)
|
||||
return r;
|
||||
mhz = r;
|
||||
|
||||
for (i = 0; i < NUM_CHANNELS; i++) {
|
||||
if (mhz == channel_frequencies[i]) {
|
||||
*channel = i+1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain)
|
||||
{
|
||||
struct ieee80211_geo geo;
|
||||
const struct channel_range *range;
|
||||
int i;
|
||||
u8 channel;
|
||||
|
||||
dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)),
|
||||
"regdomain %#04x\n", regdomain);
|
||||
|
||||
range = zd_channel_range(regdomain);
|
||||
if (range->start == 0) {
|
||||
dev_err(zd_mac_dev(zd_netdev_mac(ieee->dev)),
|
||||
"zd1211 regdomain %#04x not supported\n",
|
||||
regdomain);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&geo, 0, sizeof(geo));
|
||||
|
||||
for (i = 0, channel = range->start; channel < range->end; channel++) {
|
||||
struct ieee80211_channel *chan = &geo.bg[i++];
|
||||
chan->freq = channel_frequencies[channel - 1];
|
||||
chan->channel = channel;
|
||||
}
|
||||
|
||||
geo.bg_channels = i;
|
||||
memcpy(geo.name, "XX ", 4);
|
||||
ieee80211_set_geo(ieee, &geo);
|
||||
return 0;
|
||||
}
|
85
drivers/net/wireless/zd1211rw/zd_ieee80211.h
Normal file
85
drivers/net/wireless/zd1211rw/zd_ieee80211.h
Normal file
@ -0,0 +1,85 @@
|
||||
#ifndef _ZD_IEEE80211_H
|
||||
#define _ZD_IEEE80211_H
|
||||
|
||||
#include <net/ieee80211.h>
|
||||
#include "zd_types.h"
|
||||
|
||||
/* Additional definitions from the standards.
|
||||
*/
|
||||
|
||||
#define ZD_REGDOMAIN_FCC 0x10
|
||||
#define ZD_REGDOMAIN_IC 0x20
|
||||
#define ZD_REGDOMAIN_ETSI 0x30
|
||||
#define ZD_REGDOMAIN_SPAIN 0x31
|
||||
#define ZD_REGDOMAIN_FRANCE 0x32
|
||||
#define ZD_REGDOMAIN_JAPAN_ADD 0x40
|
||||
#define ZD_REGDOMAIN_JAPAN 0x41
|
||||
|
||||
enum {
|
||||
MIN_CHANNEL24 = 1,
|
||||
MAX_CHANNEL24 = 14,
|
||||
};
|
||||
|
||||
struct channel_range {
|
||||
u8 start;
|
||||
u8 end; /* exclusive (channel must be less than end) */
|
||||
};
|
||||
|
||||
struct iw_freq;
|
||||
|
||||
int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain);
|
||||
|
||||
const struct channel_range *zd_channel_range(u8 regdomain);
|
||||
int zd_regdomain_supports_channel(u8 regdomain, u8 channel);
|
||||
int zd_regdomain_supported(u8 regdomain);
|
||||
|
||||
/* for 2.4 GHz band */
|
||||
int zd_channel_to_freq(struct iw_freq *freq, u8 channel);
|
||||
int zd_find_channel(u8 *channel, const struct iw_freq *freq);
|
||||
|
||||
#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80
|
||||
|
||||
struct ofdm_plcp_header {
|
||||
u8 prefix[3];
|
||||
__le16 service;
|
||||
} __attribute__((packed));
|
||||
|
||||
static inline u8 zd_ofdm_plcp_header_rate(
|
||||
const struct ofdm_plcp_header *header)
|
||||
{
|
||||
return header->prefix[0] & 0xf;
|
||||
}
|
||||
|
||||
#define ZD_OFDM_RATE_6M 0xb
|
||||
#define ZD_OFDM_RATE_9M 0xf
|
||||
#define ZD_OFDM_RATE_12M 0xa
|
||||
#define ZD_OFDM_RATE_18M 0xe
|
||||
#define ZD_OFDM_RATE_24M 0x9
|
||||
#define ZD_OFDM_RATE_36M 0xd
|
||||
#define ZD_OFDM_RATE_48M 0x8
|
||||
#define ZD_OFDM_RATE_54M 0xc
|
||||
|
||||
struct cck_plcp_header {
|
||||
u8 signal;
|
||||
u8 service;
|
||||
__le16 length;
|
||||
__le16 crc16;
|
||||
} __attribute__((packed));
|
||||
|
||||
static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header)
|
||||
{
|
||||
return header->signal;
|
||||
}
|
||||
|
||||
#define ZD_CCK_SIGNAL_1M 0x0a
|
||||
#define ZD_CCK_SIGNAL_2M 0x14
|
||||
#define ZD_CCK_SIGNAL_5M5 0x37
|
||||
#define ZD_CCK_SIGNAL_11M 0x6e
|
||||
|
||||
enum ieee80211_std {
|
||||
IEEE80211B = 0x01,
|
||||
IEEE80211A = 0x02,
|
||||
IEEE80211G = 0x04,
|
||||
};
|
||||
|
||||
#endif /* _ZD_IEEE80211_H */
|
1057
drivers/net/wireless/zd1211rw/zd_mac.c
Normal file
1057
drivers/net/wireless/zd1211rw/zd_mac.c
Normal file
File diff suppressed because it is too large
Load Diff
190
drivers/net/wireless/zd1211rw/zd_mac.h
Normal file
190
drivers/net/wireless/zd1211rw/zd_mac.h
Normal file
@ -0,0 +1,190 @@
|
||||
/* zd_mac.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _ZD_MAC_H
|
||||
#define _ZD_MAC_H
|
||||
|
||||
#include <linux/wireless.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <net/ieee80211.h>
|
||||
#include <net/ieee80211softmac.h>
|
||||
|
||||
#include "zd_chip.h"
|
||||
#include "zd_netdev.h"
|
||||
|
||||
struct zd_ctrlset {
|
||||
u8 modulation;
|
||||
__le16 tx_length;
|
||||
u8 control;
|
||||
/* stores only the difference to tx_length on ZD1211B */
|
||||
__le16 packet_length;
|
||||
__le16 current_length;
|
||||
u8 service;
|
||||
__le16 next_frame_length;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define ZD_CS_RESERVED_SIZE 25
|
||||
|
||||
/* zd_crtlset field modulation */
|
||||
#define ZD_CS_RATE_MASK 0x0f
|
||||
#define ZD_CS_TYPE_MASK 0x10
|
||||
#define ZD_CS_RATE(modulation) ((modulation) & ZD_CS_RATE_MASK)
|
||||
#define ZD_CS_TYPE(modulation) ((modulation) & ZD_CS_TYPE_MASK)
|
||||
|
||||
#define ZD_CS_CCK 0x00
|
||||
#define ZD_CS_OFDM 0x10
|
||||
|
||||
#define ZD_CS_CCK_RATE_1M 0x00
|
||||
#define ZD_CS_CCK_RATE_2M 0x01
|
||||
#define ZD_CS_CCK_RATE_5_5M 0x02
|
||||
#define ZD_CS_CCK_RATE_11M 0x03
|
||||
/* The rates for OFDM are encoded as in the PLCP header. Use ZD_OFDM_RATE_*.
|
||||
*/
|
||||
|
||||
/* bit 5 is preamble (when in CCK mode), or a/g selection (when in OFDM mode) */
|
||||
#define ZD_CS_CCK_PREA_LONG 0x00
|
||||
#define ZD_CS_CCK_PREA_SHORT 0x20
|
||||
#define ZD_CS_OFDM_MODE_11G 0x00
|
||||
#define ZD_CS_OFDM_MODE_11A 0x20
|
||||
|
||||
/* zd_ctrlset control field */
|
||||
#define ZD_CS_NEED_RANDOM_BACKOFF 0x01
|
||||
#define ZD_CS_MULTICAST 0x02
|
||||
|
||||
#define ZD_CS_FRAME_TYPE_MASK 0x0c
|
||||
#define ZD_CS_DATA_FRAME 0x00
|
||||
#define ZD_CS_PS_POLL_FRAME 0x04
|
||||
#define ZD_CS_MANAGEMENT_FRAME 0x08
|
||||
#define ZD_CS_NO_SEQUENCE_CTL_FRAME 0x0c
|
||||
|
||||
#define ZD_CS_WAKE_DESTINATION 0x10
|
||||
#define ZD_CS_RTS 0x20
|
||||
#define ZD_CS_ENCRYPT 0x40
|
||||
#define ZD_CS_SELF_CTS 0x80
|
||||
|
||||
/* Incoming frames are prepended by a PLCP header */
|
||||
#define ZD_PLCP_HEADER_SIZE 5
|
||||
|
||||
struct rx_length_info {
|
||||
__le16 length[3];
|
||||
__le16 tag;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define RX_LENGTH_INFO_TAG 0x697e
|
||||
|
||||
struct rx_status {
|
||||
/* rssi */
|
||||
u8 signal_strength;
|
||||
u8 signal_quality_cck;
|
||||
u8 signal_quality_ofdm;
|
||||
u8 decryption_type;
|
||||
u8 frame_status;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* rx_status field decryption_type */
|
||||
#define ZD_RX_NO_WEP 0
|
||||
#define ZD_RX_WEP64 1
|
||||
#define ZD_RX_TKIP 2
|
||||
#define ZD_RX_AES 4
|
||||
#define ZD_RX_WEP128 5
|
||||
#define ZD_RX_WEP256 6
|
||||
|
||||
/* rx_status field frame_status */
|
||||
#define ZD_RX_FRAME_MODULATION_MASK 0x01
|
||||
#define ZD_RX_CCK 0x00
|
||||
#define ZD_RX_OFDM 0x01
|
||||
|
||||
#define ZD_RX_TIMEOUT_ERROR 0x02
|
||||
#define ZD_RX_FIFO_OVERRUN_ERROR 0x04
|
||||
#define ZD_RX_DECRYPTION_ERROR 0x08
|
||||
#define ZD_RX_CRC32_ERROR 0x10
|
||||
#define ZD_RX_NO_ADDR1_MATCH_ERROR 0x20
|
||||
#define ZD_RX_CRC16_ERROR 0x40
|
||||
#define ZD_RX_ERROR 0x80
|
||||
|
||||
enum mac_flags {
|
||||
MAC_FIXED_CHANNEL = 0x01,
|
||||
};
|
||||
|
||||
struct zd_mac {
|
||||
struct net_device *netdev;
|
||||
struct zd_chip chip;
|
||||
spinlock_t lock;
|
||||
/* Unlocked reading possible */
|
||||
struct iw_statistics iw_stats;
|
||||
u8 qual_average;
|
||||
u8 rssi_average;
|
||||
u8 regdomain;
|
||||
u8 default_regdomain;
|
||||
u8 requested_channel;
|
||||
};
|
||||
|
||||
static inline struct ieee80211_device *zd_mac_to_ieee80211(struct zd_mac *mac)
|
||||
{
|
||||
return zd_netdev_ieee80211(mac->netdev);
|
||||
}
|
||||
|
||||
static inline struct zd_mac *zd_netdev_mac(struct net_device *netdev)
|
||||
{
|
||||
return ieee80211softmac_priv(netdev);
|
||||
}
|
||||
|
||||
static inline struct zd_mac *zd_chip_to_mac(struct zd_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct zd_mac, chip);
|
||||
}
|
||||
|
||||
static inline struct zd_mac *zd_usb_to_mac(struct zd_usb *usb)
|
||||
{
|
||||
return zd_chip_to_mac(zd_usb_to_chip(usb));
|
||||
}
|
||||
|
||||
#define zd_mac_dev(mac) (zd_chip_dev(&(mac)->chip))
|
||||
|
||||
int zd_mac_init(struct zd_mac *mac,
|
||||
struct net_device *netdev,
|
||||
struct usb_interface *intf);
|
||||
void zd_mac_clear(struct zd_mac *mac);
|
||||
|
||||
int zd_mac_init_hw(struct zd_mac *mac, u8 device_type);
|
||||
|
||||
int zd_mac_open(struct net_device *netdev);
|
||||
int zd_mac_stop(struct net_device *netdev);
|
||||
int zd_mac_set_mac_address(struct net_device *dev, void *p);
|
||||
|
||||
int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length);
|
||||
|
||||
int zd_mac_set_regdomain(struct zd_mac *zd_mac, u8 regdomain);
|
||||
u8 zd_mac_get_regdomain(struct zd_mac *zd_mac);
|
||||
|
||||
int zd_mac_request_channel(struct zd_mac *mac, u8 channel);
|
||||
int zd_mac_get_channel(struct zd_mac *mac, u8 *channel, u8 *flags);
|
||||
|
||||
int zd_mac_set_mode(struct zd_mac *mac, u32 mode);
|
||||
int zd_mac_get_mode(struct zd_mac *mac, u32 *mode);
|
||||
|
||||
int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range);
|
||||
|
||||
struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev);
|
||||
|
||||
#ifdef DEBUG
|
||||
void zd_dump_rx_status(const struct rx_status *status);
|
||||
#else
|
||||
#define zd_dump_rx_status(status)
|
||||
#endif /* DEBUG */
|
||||
|
||||
#endif /* _ZD_MAC_H */
|
267
drivers/net/wireless/zd1211rw/zd_netdev.c
Normal file
267
drivers/net/wireless/zd1211rw/zd_netdev.c
Normal file
@ -0,0 +1,267 @@
|
||||
/* zd_netdev.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/ieee80211.h>
|
||||
#include <net/ieee80211softmac.h>
|
||||
#include <net/ieee80211softmac_wx.h>
|
||||
#include <net/iw_handler.h>
|
||||
|
||||
#include "zd_def.h"
|
||||
#include "zd_netdev.h"
|
||||
#include "zd_mac.h"
|
||||
#include "zd_ieee80211.h"
|
||||
|
||||
/* Region 0 means reset regdomain to default. */
|
||||
static int zd_set_regdomain(struct net_device *netdev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *req, char *extra)
|
||||
{
|
||||
const u8 *regdomain = (u8 *)req;
|
||||
return zd_mac_set_regdomain(zd_netdev_mac(netdev), *regdomain);
|
||||
}
|
||||
|
||||
static int zd_get_regdomain(struct net_device *netdev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *req, char *extra)
|
||||
{
|
||||
u8 *regdomain = (u8 *)req;
|
||||
if (!regdomain)
|
||||
return -EINVAL;
|
||||
*regdomain = zd_mac_get_regdomain(zd_netdev_mac(netdev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iw_priv_args zd_priv_args[] = {
|
||||
{
|
||||
.cmd = ZD_PRIV_SET_REGDOMAIN,
|
||||
.set_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
|
||||
.name = "set_regdomain",
|
||||
},
|
||||
{
|
||||
.cmd = ZD_PRIV_GET_REGDOMAIN,
|
||||
.get_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
|
||||
.name = "get_regdomain",
|
||||
},
|
||||
};
|
||||
|
||||
#define PRIV_OFFSET(x) [(x)-SIOCIWFIRSTPRIV]
|
||||
|
||||
static const iw_handler zd_priv_handler[] = {
|
||||
PRIV_OFFSET(ZD_PRIV_SET_REGDOMAIN) = zd_set_regdomain,
|
||||
PRIV_OFFSET(ZD_PRIV_GET_REGDOMAIN) = zd_get_regdomain,
|
||||
};
|
||||
|
||||
static int iw_get_name(struct net_device *netdev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *req, char *extra)
|
||||
{
|
||||
/* FIXME: check whether 802.11a will also supported, add also
|
||||
* zd1211B, if we support it.
|
||||
*/
|
||||
strlcpy(req->name, "802.11g zd1211", IFNAMSIZ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iw_set_freq(struct net_device *netdev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *req, char *extra)
|
||||
{
|
||||
int r;
|
||||
struct zd_mac *mac = zd_netdev_mac(netdev);
|
||||
struct iw_freq *freq = &req->freq;
|
||||
u8 channel;
|
||||
|
||||
r = zd_find_channel(&channel, freq);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = zd_mac_request_channel(mac, channel);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int iw_get_freq(struct net_device *netdev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *req, char *extra)
|
||||
{
|
||||
int r;
|
||||
struct zd_mac *mac = zd_netdev_mac(netdev);
|
||||
struct iw_freq *freq = &req->freq;
|
||||
u8 channel;
|
||||
u8 flags;
|
||||
|
||||
r = zd_mac_get_channel(mac, &channel, &flags);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
freq->flags = (flags & MAC_FIXED_CHANNEL) ?
|
||||
IW_FREQ_FIXED : IW_FREQ_AUTO;
|
||||
dev_dbg_f(zd_mac_dev(mac), "channel %s\n",
|
||||
(flags & MAC_FIXED_CHANNEL) ? "fixed" : "auto");
|
||||
return zd_channel_to_freq(freq, channel);
|
||||
}
|
||||
|
||||
static int iw_set_mode(struct net_device *netdev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *req, char *extra)
|
||||
{
|
||||
return zd_mac_set_mode(zd_netdev_mac(netdev), req->mode);
|
||||
}
|
||||
|
||||
static int iw_get_mode(struct net_device *netdev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *req, char *extra)
|
||||
{
|
||||
return zd_mac_get_mode(zd_netdev_mac(netdev), &req->mode);
|
||||
}
|
||||
|
||||
static int iw_get_range(struct net_device *netdev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *req, char *extra)
|
||||
{
|
||||
struct iw_range *range = (struct iw_range *)extra;
|
||||
|
||||
dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
|
||||
req->data.length = sizeof(*range);
|
||||
return zd_mac_get_range(zd_netdev_mac(netdev), range);
|
||||
}
|
||||
|
||||
static int iw_set_encode(struct net_device *netdev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *data,
|
||||
char *extra)
|
||||
{
|
||||
return ieee80211_wx_set_encode(zd_netdev_ieee80211(netdev), info,
|
||||
data, extra);
|
||||
}
|
||||
|
||||
static int iw_get_encode(struct net_device *netdev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *data,
|
||||
char *extra)
|
||||
{
|
||||
return ieee80211_wx_get_encode(zd_netdev_ieee80211(netdev), info,
|
||||
data, extra);
|
||||
}
|
||||
|
||||
static int iw_set_encodeext(struct net_device *netdev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *data,
|
||||
char *extra)
|
||||
{
|
||||
return ieee80211_wx_set_encodeext(zd_netdev_ieee80211(netdev), info,
|
||||
data, extra);
|
||||
}
|
||||
|
||||
static int iw_get_encodeext(struct net_device *netdev,
|
||||
struct iw_request_info *info,
|
||||
union iwreq_data *data,
|
||||
char *extra)
|
||||
{
|
||||
return ieee80211_wx_get_encodeext(zd_netdev_ieee80211(netdev), info,
|
||||
data, extra);
|
||||
}
|
||||
|
||||
#define WX(x) [(x)-SIOCIWFIRST]
|
||||
|
||||
static const iw_handler zd_standard_iw_handlers[] = {
|
||||
WX(SIOCGIWNAME) = iw_get_name,
|
||||
WX(SIOCSIWFREQ) = iw_set_freq,
|
||||
WX(SIOCGIWFREQ) = iw_get_freq,
|
||||
WX(SIOCSIWMODE) = iw_set_mode,
|
||||
WX(SIOCGIWMODE) = iw_get_mode,
|
||||
WX(SIOCGIWRANGE) = iw_get_range,
|
||||
WX(SIOCSIWENCODE) = iw_set_encode,
|
||||
WX(SIOCGIWENCODE) = iw_get_encode,
|
||||
WX(SIOCSIWENCODEEXT) = iw_set_encodeext,
|
||||
WX(SIOCGIWENCODEEXT) = iw_get_encodeext,
|
||||
WX(SIOCSIWAUTH) = ieee80211_wx_set_auth,
|
||||
WX(SIOCGIWAUTH) = ieee80211_wx_get_auth,
|
||||
WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan,
|
||||
WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results,
|
||||
WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid,
|
||||
WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid,
|
||||
WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap,
|
||||
WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap,
|
||||
WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate,
|
||||
WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate,
|
||||
WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie,
|
||||
WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie,
|
||||
WX(SIOCSIWMLME) = ieee80211softmac_wx_set_mlme,
|
||||
};
|
||||
|
||||
static const struct iw_handler_def iw_handler_def = {
|
||||
.standard = zd_standard_iw_handlers,
|
||||
.num_standard = ARRAY_SIZE(zd_standard_iw_handlers),
|
||||
.private = zd_priv_handler,
|
||||
.num_private = ARRAY_SIZE(zd_priv_handler),
|
||||
.private_args = zd_priv_args,
|
||||
.num_private_args = ARRAY_SIZE(zd_priv_args),
|
||||
.get_wireless_stats = zd_mac_get_wireless_stats,
|
||||
};
|
||||
|
||||
struct net_device *zd_netdev_alloc(struct usb_interface *intf)
|
||||
{
|
||||
int r;
|
||||
struct net_device *netdev;
|
||||
struct zd_mac *mac;
|
||||
|
||||
netdev = alloc_ieee80211softmac(sizeof(struct zd_mac));
|
||||
if (!netdev) {
|
||||
dev_dbg_f(&intf->dev, "out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mac = zd_netdev_mac(netdev);
|
||||
r = zd_mac_init(mac, netdev, intf);
|
||||
if (r) {
|
||||
usb_set_intfdata(intf, NULL);
|
||||
free_ieee80211(netdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SET_MODULE_OWNER(netdev);
|
||||
SET_NETDEV_DEV(netdev, &intf->dev);
|
||||
|
||||
dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags);
|
||||
dev_dbg_f(&intf->dev, "netdev->features %#010lx\n", netdev->features);
|
||||
|
||||
netdev->open = zd_mac_open;
|
||||
netdev->stop = zd_mac_stop;
|
||||
/* netdev->get_stats = */
|
||||
/* netdev->set_multicast_list = */
|
||||
netdev->set_mac_address = zd_mac_set_mac_address;
|
||||
netdev->wireless_handlers = &iw_handler_def;
|
||||
/* netdev->ethtool_ops = */
|
||||
|
||||
return netdev;
|
||||
}
|
||||
|
||||
void zd_netdev_free(struct net_device *netdev)
|
||||
{
|
||||
if (!netdev)
|
||||
return;
|
||||
|
||||
zd_mac_clear(zd_netdev_mac(netdev));
|
||||
free_ieee80211(netdev);
|
||||
}
|
||||
|
||||
void zd_netdev_disconnect(struct net_device *netdev)
|
||||
{
|
||||
unregister_netdev(netdev);
|
||||
}
|
45
drivers/net/wireless/zd1211rw/zd_netdev.h
Normal file
45
drivers/net/wireless/zd1211rw/zd_netdev.h
Normal file
@ -0,0 +1,45 @@
|
||||
/* zd_netdev.h: Header for net device related functions.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _ZD_NETDEV_H
|
||||
#define _ZD_NETDEV_H
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/ieee80211.h>
|
||||
|
||||
#define ZD_PRIV_SET_REGDOMAIN (SIOCIWFIRSTPRIV)
|
||||
#define ZD_PRIV_GET_REGDOMAIN (SIOCIWFIRSTPRIV+1)
|
||||
|
||||
static inline struct ieee80211_device *zd_netdev_ieee80211(
|
||||
struct net_device *ndev)
|
||||
{
|
||||
return netdev_priv(ndev);
|
||||
}
|
||||
|
||||
static inline struct net_device *zd_ieee80211_to_netdev(
|
||||
struct ieee80211_device *ieee)
|
||||
{
|
||||
return ieee->dev;
|
||||
}
|
||||
|
||||
struct net_device *zd_netdev_alloc(struct usb_interface *intf);
|
||||
void zd_netdev_free(struct net_device *netdev);
|
||||
|
||||
void zd_netdev_disconnect(struct net_device *netdev);
|
||||
|
||||
#endif /* _ZD_NETDEV_H */
|
151
drivers/net/wireless/zd1211rw/zd_rf.c
Normal file
151
drivers/net/wireless/zd1211rw/zd_rf.c
Normal file
@ -0,0 +1,151 @@
|
||||
/* zd_rf.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "zd_def.h"
|
||||
#include "zd_rf.h"
|
||||
#include "zd_ieee80211.h"
|
||||
#include "zd_chip.h"
|
||||
|
||||
static const char *rfs[] = {
|
||||
[0] = "unknown RF0",
|
||||
[1] = "unknown RF1",
|
||||
[UW2451_RF] = "UW2451_RF",
|
||||
[UCHIP_RF] = "UCHIP_RF",
|
||||
[AL2230_RF] = "AL2230_RF",
|
||||
[AL7230B_RF] = "AL7230B_RF",
|
||||
[THETA_RF] = "THETA_RF",
|
||||
[AL2210_RF] = "AL2210_RF",
|
||||
[MAXIM_NEW_RF] = "MAXIM_NEW_RF",
|
||||
[UW2453_RF] = "UW2453_RF",
|
||||
[AL2230S_RF] = "AL2230S_RF",
|
||||
[RALINK_RF] = "RALINK_RF",
|
||||
[INTERSIL_RF] = "INTERSIL_RF",
|
||||
[RF2959_RF] = "RF2959_RF",
|
||||
[MAXIM_NEW2_RF] = "MAXIM_NEW2_RF",
|
||||
[PHILIPS_RF] = "PHILIPS_RF",
|
||||
};
|
||||
|
||||
const char *zd_rf_name(u8 type)
|
||||
{
|
||||
if (type & 0xf0)
|
||||
type = 0;
|
||||
return rfs[type];
|
||||
}
|
||||
|
||||
void zd_rf_init(struct zd_rf *rf)
|
||||
{
|
||||
memset(rf, 0, sizeof(*rf));
|
||||
}
|
||||
|
||||
void zd_rf_clear(struct zd_rf *rf)
|
||||
{
|
||||
memset(rf, 0, sizeof(*rf));
|
||||
}
|
||||
|
||||
int zd_rf_init_hw(struct zd_rf *rf, u8 type)
|
||||
{
|
||||
int r, t;
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
|
||||
ZD_ASSERT(mutex_is_locked(&chip->mutex));
|
||||
switch (type) {
|
||||
case RF2959_RF:
|
||||
r = zd_rf_init_rf2959(rf);
|
||||
if (r)
|
||||
return r;
|
||||
break;
|
||||
case AL2230_RF:
|
||||
r = zd_rf_init_al2230(rf);
|
||||
if (r)
|
||||
return r;
|
||||
break;
|
||||
default:
|
||||
dev_err(zd_chip_dev(chip),
|
||||
"RF %s %#x is not supported\n", zd_rf_name(type), type);
|
||||
rf->type = 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rf->type = type;
|
||||
|
||||
r = zd_chip_lock_phy_regs(chip);
|
||||
if (r)
|
||||
return r;
|
||||
t = rf->init_hw(rf);
|
||||
r = zd_chip_unlock_phy_regs(chip);
|
||||
if (t)
|
||||
r = t;
|
||||
return r;
|
||||
}
|
||||
|
||||
int zd_rf_scnprint_id(struct zd_rf *rf, char *buffer, size_t size)
|
||||
{
|
||||
return scnprintf(buffer, size, "%s", zd_rf_name(rf->type));
|
||||
}
|
||||
|
||||
int zd_rf_set_channel(struct zd_rf *rf, u8 channel)
|
||||
{
|
||||
int r;
|
||||
|
||||
ZD_ASSERT(mutex_is_locked(&zd_rf_to_chip(rf)->mutex));
|
||||
if (channel < MIN_CHANNEL24)
|
||||
return -EINVAL;
|
||||
if (channel > MAX_CHANNEL24)
|
||||
return -EINVAL;
|
||||
dev_dbg_f(zd_chip_dev(zd_rf_to_chip(rf)), "channel: %d\n", channel);
|
||||
|
||||
r = rf->set_channel(rf, channel);
|
||||
if (r >= 0)
|
||||
rf->channel = channel;
|
||||
return r;
|
||||
}
|
||||
|
||||
int zd_switch_radio_on(struct zd_rf *rf)
|
||||
{
|
||||
int r, t;
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
|
||||
ZD_ASSERT(mutex_is_locked(&chip->mutex));
|
||||
r = zd_chip_lock_phy_regs(chip);
|
||||
if (r)
|
||||
return r;
|
||||
t = rf->switch_radio_on(rf);
|
||||
r = zd_chip_unlock_phy_regs(chip);
|
||||
if (t)
|
||||
r = t;
|
||||
return r;
|
||||
}
|
||||
|
||||
int zd_switch_radio_off(struct zd_rf *rf)
|
||||
{
|
||||
int r, t;
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
|
||||
/* TODO: move phy regs handling to zd_chip */
|
||||
ZD_ASSERT(mutex_is_locked(&chip->mutex));
|
||||
r = zd_chip_lock_phy_regs(chip);
|
||||
if (r)
|
||||
return r;
|
||||
t = rf->switch_radio_off(rf);
|
||||
r = zd_chip_unlock_phy_regs(chip);
|
||||
if (t)
|
||||
r = t;
|
||||
return r;
|
||||
}
|
82
drivers/net/wireless/zd1211rw/zd_rf.h
Normal file
82
drivers/net/wireless/zd1211rw/zd_rf.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* zd_rf.h
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _ZD_RF_H
|
||||
#define _ZD_RF_H
|
||||
|
||||
#include "zd_types.h"
|
||||
|
||||
#define UW2451_RF 0x2
|
||||
#define UCHIP_RF 0x3
|
||||
#define AL2230_RF 0x4
|
||||
#define AL7230B_RF 0x5 /* a,b,g */
|
||||
#define THETA_RF 0x6
|
||||
#define AL2210_RF 0x7
|
||||
#define MAXIM_NEW_RF 0x8
|
||||
#define UW2453_RF 0x9
|
||||
#define AL2230S_RF 0xa
|
||||
#define RALINK_RF 0xb
|
||||
#define INTERSIL_RF 0xc
|
||||
#define RF2959_RF 0xd
|
||||
#define MAXIM_NEW2_RF 0xe
|
||||
#define PHILIPS_RF 0xf
|
||||
|
||||
#define RF_CHANNEL(ch) [(ch)-1]
|
||||
|
||||
/* Provides functions of the RF transceiver. */
|
||||
|
||||
enum {
|
||||
RF_REG_BITS = 6,
|
||||
RF_VALUE_BITS = 18,
|
||||
RF_RV_BITS = RF_REG_BITS + RF_VALUE_BITS,
|
||||
};
|
||||
|
||||
struct zd_rf {
|
||||
u8 type;
|
||||
|
||||
u8 channel;
|
||||
/*
|
||||
* Whether this RF should patch the 6M band edge
|
||||
* (assuming E2P_POD agrees)
|
||||
*/
|
||||
u8 patch_6m_band_edge:1;
|
||||
|
||||
/* RF-specific functions */
|
||||
int (*init_hw)(struct zd_rf *rf);
|
||||
int (*set_channel)(struct zd_rf *rf, u8 channel);
|
||||
int (*switch_radio_on)(struct zd_rf *rf);
|
||||
int (*switch_radio_off)(struct zd_rf *rf);
|
||||
};
|
||||
|
||||
const char *zd_rf_name(u8 type);
|
||||
void zd_rf_init(struct zd_rf *rf);
|
||||
void zd_rf_clear(struct zd_rf *rf);
|
||||
int zd_rf_init_hw(struct zd_rf *rf, u8 type);
|
||||
|
||||
int zd_rf_scnprint_id(struct zd_rf *rf, char *buffer, size_t size);
|
||||
|
||||
int zd_rf_set_channel(struct zd_rf *rf, u8 channel);
|
||||
|
||||
int zd_switch_radio_on(struct zd_rf *rf);
|
||||
int zd_switch_radio_off(struct zd_rf *rf);
|
||||
|
||||
/* Functions for individual RF chips */
|
||||
|
||||
int zd_rf_init_rf2959(struct zd_rf *rf);
|
||||
int zd_rf_init_al2230(struct zd_rf *rf);
|
||||
|
||||
#endif /* _ZD_RF_H */
|
308
drivers/net/wireless/zd1211rw/zd_rf_al2230.c
Normal file
308
drivers/net/wireless/zd1211rw/zd_rf_al2230.c
Normal file
@ -0,0 +1,308 @@
|
||||
/* zd_rf_al2230.c: Functions for the AL2230 RF controller
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "zd_rf.h"
|
||||
#include "zd_usb.h"
|
||||
#include "zd_chip.h"
|
||||
|
||||
static const u32 al2230_table[][3] = {
|
||||
RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, },
|
||||
RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, },
|
||||
RF_CHANNEL( 3) = { 0x03e790, 0x033331, 0x00000d, },
|
||||
RF_CHANNEL( 4) = { 0x03e790, 0x0b3331, 0x00000d, },
|
||||
RF_CHANNEL( 5) = { 0x03f7a0, 0x033331, 0x00000d, },
|
||||
RF_CHANNEL( 6) = { 0x03f7a0, 0x0b3331, 0x00000d, },
|
||||
RF_CHANNEL( 7) = { 0x03e7a0, 0x033331, 0x00000d, },
|
||||
RF_CHANNEL( 8) = { 0x03e7a0, 0x0b3331, 0x00000d, },
|
||||
RF_CHANNEL( 9) = { 0x03f7b0, 0x033331, 0x00000d, },
|
||||
RF_CHANNEL(10) = { 0x03f7b0, 0x0b3331, 0x00000d, },
|
||||
RF_CHANNEL(11) = { 0x03e7b0, 0x033331, 0x00000d, },
|
||||
RF_CHANNEL(12) = { 0x03e7b0, 0x0b3331, 0x00000d, },
|
||||
RF_CHANNEL(13) = { 0x03f7c0, 0x033331, 0x00000d, },
|
||||
RF_CHANNEL(14) = { 0x03e7c0, 0x066661, 0x00000d, },
|
||||
};
|
||||
|
||||
static int zd1211_al2230_init_hw(struct zd_rf *rf)
|
||||
{
|
||||
int r;
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
|
||||
static const struct zd_ioreq16 ioreqs[] = {
|
||||
{ CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 },
|
||||
{ CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 },
|
||||
{ CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a },
|
||||
{ CR109, 0x09 }, { CR110, 0x27 }, { CR111, 0x2b },
|
||||
{ CR112, 0x2b }, { CR119, 0x0a }, { CR10, 0x89 },
|
||||
/* for newest (3rd cut) AL2300 */
|
||||
{ CR17, 0x28 },
|
||||
{ CR26, 0x93 }, { CR34, 0x30 },
|
||||
/* for newest (3rd cut) AL2300 */
|
||||
{ CR35, 0x3e },
|
||||
{ CR41, 0x24 }, { CR44, 0x32 },
|
||||
/* for newest (3rd cut) AL2300 */
|
||||
{ CR46, 0x96 },
|
||||
{ CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 },
|
||||
{ CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 },
|
||||
{ CR92, 0x0a }, { CR99, 0x28 }, { CR100, 0x00 },
|
||||
{ CR101, 0x13 }, { CR102, 0x27 }, { CR106, 0x24 },
|
||||
{ CR107, 0x2a }, { CR109, 0x09 }, { CR110, 0x13 },
|
||||
{ CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
|
||||
{ CR114, 0x27 },
|
||||
/* for newest (3rd cut) AL2300 */
|
||||
{ CR115, 0x24 },
|
||||
{ CR116, 0x24 }, { CR117, 0xf4 }, { CR118, 0xfc },
|
||||
{ CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 },
|
||||
{ CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff },
|
||||
{ CR253, 0xff },
|
||||
|
||||
/* These following happen separately in the vendor driver */
|
||||
{ },
|
||||
|
||||
/* shdnb(PLL_ON)=0 */
|
||||
{ CR251, 0x2f },
|
||||
/* shdnb(PLL_ON)=1 */
|
||||
{ CR251, 0x3f },
|
||||
{ CR138, 0x28 }, { CR203, 0x06 },
|
||||
};
|
||||
|
||||
static const u32 rv[] = {
|
||||
/* Channel 1 */
|
||||
0x03f790,
|
||||
0x033331,
|
||||
0x00000d,
|
||||
|
||||
0x0b3331,
|
||||
0x03b812,
|
||||
0x00fff3,
|
||||
0x000da4,
|
||||
0x0f4dc5, /* fix freq shift, 0x04edc5 */
|
||||
0x0805b6,
|
||||
0x011687,
|
||||
0x000688,
|
||||
0x0403b9, /* external control TX power (CR31) */
|
||||
0x00dbba,
|
||||
0x00099b,
|
||||
0x0bdffc,
|
||||
0x00000d,
|
||||
0x00500f,
|
||||
|
||||
/* These writes happen separately in the vendor driver */
|
||||
0x00d00f,
|
||||
0x004c0f,
|
||||
0x00540f,
|
||||
0x00700f,
|
||||
0x00500f,
|
||||
};
|
||||
|
||||
r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zd1211b_al2230_init_hw(struct zd_rf *rf)
|
||||
{
|
||||
int r;
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
|
||||
static const struct zd_ioreq16 ioreqs1[] = {
|
||||
{ CR10, 0x89 }, { CR15, 0x20 },
|
||||
{ CR17, 0x2B }, /* for newest(3rd cut) AL2230 */
|
||||
{ CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 },
|
||||
{ CR28, 0x3e }, { CR29, 0x00 },
|
||||
{ CR33, 0x28 }, /* 5621 */
|
||||
{ CR34, 0x30 },
|
||||
{ CR35, 0x3e }, /* for newest(3rd cut) AL2230 */
|
||||
{ CR41, 0x24 }, { CR44, 0x32 },
|
||||
{ CR46, 0x99 }, /* for newest(3rd cut) AL2230 */
|
||||
{ CR47, 0x1e },
|
||||
|
||||
/* ZD1211B 05.06.10 */
|
||||
{ CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 },
|
||||
{ CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 },
|
||||
{ CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 },
|
||||
{ CR69, 0x28 },
|
||||
|
||||
{ CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 },
|
||||
{ CR87, 0x0a }, { CR89, 0x04 },
|
||||
{ CR91, 0x00 }, /* 5621 */
|
||||
{ CR92, 0x0a },
|
||||
{ CR98, 0x8d }, /* 4804, for 1212 new algorithm */
|
||||
{ CR99, 0x00 }, /* 5621 */
|
||||
{ CR101, 0x13 }, { CR102, 0x27 },
|
||||
{ CR106, 0x24 }, /* for newest(3rd cut) AL2230 */
|
||||
{ CR107, 0x2a },
|
||||
{ CR109, 0x13 }, /* 4804, for 1212 new algorithm */
|
||||
{ CR110, 0x1f }, /* 4804, for 1212 new algorithm */
|
||||
{ CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
|
||||
{ CR114, 0x27 },
|
||||
{ CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) AL2230 */
|
||||
{ CR116, 0x24 },
|
||||
{ CR117, 0xfa }, /* for 1211b */
|
||||
{ CR118, 0xfa }, /* for 1211b */
|
||||
{ CR119, 0x10 },
|
||||
{ CR120, 0x4f },
|
||||
{ CR121, 0x6c }, /* for 1211b */
|
||||
{ CR122, 0xfc }, /* E0->FC at 4902 */
|
||||
{ CR123, 0x57 }, /* 5623 */
|
||||
{ CR125, 0xad }, /* 4804, for 1212 new algorithm */
|
||||
{ CR126, 0x6c }, /* 5614 */
|
||||
{ CR127, 0x03 }, /* 4804, for 1212 new algorithm */
|
||||
{ CR137, 0x50 }, /* 5614 */
|
||||
{ CR138, 0xa8 },
|
||||
{ CR144, 0xac }, /* 5621 */
|
||||
{ CR150, 0x0d }, { CR252, 0x00 }, { CR253, 0x00 },
|
||||
};
|
||||
|
||||
static const u32 rv1[] = {
|
||||
/* channel 1 */
|
||||
0x03f790,
|
||||
0x033331,
|
||||
0x00000d,
|
||||
|
||||
0x0b3331,
|
||||
0x03b812,
|
||||
0x00fff3,
|
||||
0x0005a4,
|
||||
0x0f4dc5, /* fix freq shift 0x044dc5 */
|
||||
0x0805b6,
|
||||
0x0146c7,
|
||||
0x000688,
|
||||
0x0403b9, /* External control TX power (CR31) */
|
||||
0x00dbba,
|
||||
0x00099b,
|
||||
0x0bdffc,
|
||||
0x00000d,
|
||||
0x00580f,
|
||||
};
|
||||
|
||||
static const struct zd_ioreq16 ioreqs2[] = {
|
||||
{ CR47, 0x1e }, { CR_RFCFG, 0x03 },
|
||||
};
|
||||
|
||||
static const u32 rv2[] = {
|
||||
0x00880f,
|
||||
0x00080f,
|
||||
};
|
||||
|
||||
static const struct zd_ioreq16 ioreqs3[] = {
|
||||
{ CR_RFCFG, 0x00 }, { CR47, 0x1e }, { CR251, 0x7f },
|
||||
};
|
||||
|
||||
static const u32 rv3[] = {
|
||||
0x00d80f,
|
||||
0x00780f,
|
||||
0x00580f,
|
||||
};
|
||||
|
||||
static const struct zd_ioreq16 ioreqs4[] = {
|
||||
{ CR138, 0x28 }, { CR203, 0x06 },
|
||||
};
|
||||
|
||||
r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
|
||||
if (r)
|
||||
return r;
|
||||
r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS);
|
||||
if (r)
|
||||
return r;
|
||||
r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
|
||||
if (r)
|
||||
return r;
|
||||
r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS);
|
||||
if (r)
|
||||
return r;
|
||||
r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
|
||||
if (r)
|
||||
return r;
|
||||
r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS);
|
||||
if (r)
|
||||
return r;
|
||||
return zd_iowrite16a_locked(chip, ioreqs4, ARRAY_SIZE(ioreqs4));
|
||||
}
|
||||
|
||||
static int al2230_set_channel(struct zd_rf *rf, u8 channel)
|
||||
{
|
||||
int r;
|
||||
const u32 *rv = al2230_table[channel-1];
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
static const struct zd_ioreq16 ioreqs[] = {
|
||||
{ CR138, 0x28 },
|
||||
{ CR203, 0x06 },
|
||||
};
|
||||
|
||||
r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS);
|
||||
if (r)
|
||||
return r;
|
||||
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
|
||||
}
|
||||
|
||||
static int zd1211_al2230_switch_radio_on(struct zd_rf *rf)
|
||||
{
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
static const struct zd_ioreq16 ioreqs[] = {
|
||||
{ CR11, 0x00 },
|
||||
{ CR251, 0x3f },
|
||||
};
|
||||
|
||||
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
|
||||
}
|
||||
|
||||
static int zd1211b_al2230_switch_radio_on(struct zd_rf *rf)
|
||||
{
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
static const struct zd_ioreq16 ioreqs[] = {
|
||||
{ CR11, 0x00 },
|
||||
{ CR251, 0x7f },
|
||||
};
|
||||
|
||||
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
|
||||
}
|
||||
|
||||
static int al2230_switch_radio_off(struct zd_rf *rf)
|
||||
{
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
static const struct zd_ioreq16 ioreqs[] = {
|
||||
{ CR11, 0x04 },
|
||||
{ CR251, 0x2f },
|
||||
};
|
||||
|
||||
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
|
||||
}
|
||||
|
||||
int zd_rf_init_al2230(struct zd_rf *rf)
|
||||
{
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
|
||||
rf->set_channel = al2230_set_channel;
|
||||
rf->switch_radio_off = al2230_switch_radio_off;
|
||||
if (chip->is_zd1211b) {
|
||||
rf->init_hw = zd1211b_al2230_init_hw;
|
||||
rf->switch_radio_on = zd1211b_al2230_switch_radio_on;
|
||||
} else {
|
||||
rf->init_hw = zd1211_al2230_init_hw;
|
||||
rf->switch_radio_on = zd1211_al2230_switch_radio_on;
|
||||
}
|
||||
rf->patch_6m_band_edge = 1;
|
||||
return 0;
|
||||
}
|
279
drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
Normal file
279
drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
Normal file
@ -0,0 +1,279 @@
|
||||
/* zd_rf_rfmd.c: Functions for the RFMD RF controller
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "zd_rf.h"
|
||||
#include "zd_usb.h"
|
||||
#include "zd_chip.h"
|
||||
|
||||
static u32 rf2959_table[][2] = {
|
||||
RF_CHANNEL( 1) = { 0x181979, 0x1e6666 },
|
||||
RF_CHANNEL( 2) = { 0x181989, 0x1e6666 },
|
||||
RF_CHANNEL( 3) = { 0x181999, 0x1e6666 },
|
||||
RF_CHANNEL( 4) = { 0x1819a9, 0x1e6666 },
|
||||
RF_CHANNEL( 5) = { 0x1819b9, 0x1e6666 },
|
||||
RF_CHANNEL( 6) = { 0x1819c9, 0x1e6666 },
|
||||
RF_CHANNEL( 7) = { 0x1819d9, 0x1e6666 },
|
||||
RF_CHANNEL( 8) = { 0x1819e9, 0x1e6666 },
|
||||
RF_CHANNEL( 9) = { 0x1819f9, 0x1e6666 },
|
||||
RF_CHANNEL(10) = { 0x181a09, 0x1e6666 },
|
||||
RF_CHANNEL(11) = { 0x181a19, 0x1e6666 },
|
||||
RF_CHANNEL(12) = { 0x181a29, 0x1e6666 },
|
||||
RF_CHANNEL(13) = { 0x181a39, 0x1e6666 },
|
||||
RF_CHANNEL(14) = { 0x181a60, 0x1c0000 },
|
||||
};
|
||||
|
||||
#if 0
|
||||
static int bits(u32 rw, int from, int to)
|
||||
{
|
||||
rw &= ~(0xffffffffU << (to+1));
|
||||
rw >>= from;
|
||||
return rw;
|
||||
}
|
||||
|
||||
static int bit(u32 rw, int bit)
|
||||
{
|
||||
return bits(rw, bit, bit);
|
||||
}
|
||||
|
||||
static void dump_regwrite(u32 rw)
|
||||
{
|
||||
int reg = bits(rw, 18, 22);
|
||||
int rw_flag = bits(rw, 23, 23);
|
||||
PDEBUG("rf2959 %#010x reg %d rw %d", rw, reg, rw_flag);
|
||||
|
||||
switch (reg) {
|
||||
case 0:
|
||||
PDEBUG("reg0 CFG1 ref_sel %d hybernate %d rf_vco_reg_en %d"
|
||||
" if_vco_reg_en %d if_vga_en %d",
|
||||
bits(rw, 14, 15), bit(rw, 3), bit(rw, 2), bit(rw, 1),
|
||||
bit(rw, 0));
|
||||
break;
|
||||
case 1:
|
||||
PDEBUG("reg1 IFPLL1 pll_en1 %d kv_en1 %d vtc_en1 %d lpf1 %d"
|
||||
" cpl1 %d pdp1 %d autocal_en1 %d ld_en1 %d ifloopr %d"
|
||||
" ifloopc %d dac1 %d",
|
||||
bit(rw, 17), bit(rw, 16), bit(rw, 15), bit(rw, 14),
|
||||
bit(rw, 13), bit(rw, 12), bit(rw, 11), bit(rw, 10),
|
||||
bits(rw, 7, 9), bits(rw, 4, 6), bits(rw, 0, 3));
|
||||
break;
|
||||
case 2:
|
||||
PDEBUG("reg2 IFPLL2 n1 %d num1 %d",
|
||||
bits(rw, 6, 17), bits(rw, 0, 5));
|
||||
break;
|
||||
case 3:
|
||||
PDEBUG("reg3 IFPLL3 num %d", bits(rw, 0, 17));
|
||||
break;
|
||||
case 4:
|
||||
PDEBUG("reg4 IFPLL4 dn1 %#04x ct_def1 %d kv_def1 %d",
|
||||
bits(rw, 8, 16), bits(rw, 4, 7), bits(rw, 0, 3));
|
||||
break;
|
||||
case 5:
|
||||
PDEBUG("reg5 RFPLL1 pll_en %d kv_en %d vtc_en %d lpf %d cpl %d"
|
||||
" pdp %d autocal_en %d ld_en %d rfloopr %d rfloopc %d"
|
||||
" dac %d",
|
||||
bit(rw, 17), bit(rw, 16), bit(rw, 15), bit(rw, 14),
|
||||
bit(rw, 13), bit(rw, 12), bit(rw, 11), bit(rw, 10),
|
||||
bits(rw, 7, 9), bits(rw, 4, 6), bits(rw, 0,3));
|
||||
break;
|
||||
case 6:
|
||||
PDEBUG("reg6 RFPLL2 n %d num %d",
|
||||
bits(rw, 6, 17), bits(rw, 0, 5));
|
||||
break;
|
||||
case 7:
|
||||
PDEBUG("reg7 RFPLL3 num2 %d", bits(rw, 0, 17));
|
||||
break;
|
||||
case 8:
|
||||
PDEBUG("reg8 RFPLL4 dn %#06x ct_def %d kv_def %d",
|
||||
bits(rw, 8, 16), bits(rw, 4, 7), bits(rw, 0, 3));
|
||||
break;
|
||||
case 9:
|
||||
PDEBUG("reg9 CAL1 tvco %d tlock %d m_ct_value %d ld_window %d",
|
||||
bits(rw, 13, 17), bits(rw, 8, 12), bits(rw, 3, 7),
|
||||
bits(rw, 0, 2));
|
||||
break;
|
||||
case 10:
|
||||
PDEBUG("reg10 TXRX1 rxdcfbbyps %d pcontrol %d txvgc %d"
|
||||
" rxlpfbw %d txlpfbw %d txdiffmode %d txenmode %d"
|
||||
" intbiasen %d tybypass %d",
|
||||
bit(rw, 17), bits(rw, 15, 16), bits(rw, 10, 14),
|
||||
bits(rw, 7, 9), bits(rw, 4, 6), bit(rw, 3), bit(rw, 2),
|
||||
bit(rw, 1), bit(rw, 0));
|
||||
break;
|
||||
case 11:
|
||||
PDEBUG("reg11 PCNT1 mid_bias %d p_desired %d pc_offset %d"
|
||||
" tx_delay %d",
|
||||
bits(rw, 15, 17), bits(rw, 9, 14), bits(rw, 3, 8),
|
||||
bits(rw, 0, 2));
|
||||
break;
|
||||
case 12:
|
||||
PDEBUG("reg12 PCNT2 max_power %d mid_power %d min_power %d",
|
||||
bits(rw, 12, 17), bits(rw, 6, 11), bits(rw, 0, 5));
|
||||
break;
|
||||
case 13:
|
||||
PDEBUG("reg13 VCOT1 rfpll vco comp %d ifpll vco comp %d"
|
||||
" lobias %d if_biasbuf %d if_biasvco %d rf_biasbuf %d"
|
||||
" rf_biasvco %d",
|
||||
bit(rw, 17), bit(rw, 16), bit(rw, 15),
|
||||
bits(rw, 8, 9), bits(rw, 5, 7), bits(rw, 3, 4),
|
||||
bits(rw, 0, 2));
|
||||
break;
|
||||
case 14:
|
||||
PDEBUG("reg14 IQCAL rx_acal %d rx_pcal %d"
|
||||
" tx_acal %d tx_pcal %d",
|
||||
bits(rw, 13, 17), bits(rw, 9, 12), bits(rw, 4, 8),
|
||||
bits(rw, 0, 3));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
static int rf2959_init_hw(struct zd_rf *rf)
|
||||
{
|
||||
int r;
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
|
||||
static const struct zd_ioreq16 ioreqs[] = {
|
||||
{ CR2, 0x1E }, { CR9, 0x20 }, { CR10, 0x89 },
|
||||
{ CR11, 0x00 }, { CR15, 0xD0 }, { CR17, 0x68 },
|
||||
{ CR19, 0x4a }, { CR20, 0x0c }, { CR21, 0x0E },
|
||||
{ CR23, 0x48 },
|
||||
/* normal size for cca threshold */
|
||||
{ CR24, 0x14 },
|
||||
/* { CR24, 0x20 }, */
|
||||
{ CR26, 0x90 }, { CR27, 0x30 }, { CR29, 0x20 },
|
||||
{ CR31, 0xb2 }, { CR32, 0x43 }, { CR33, 0x28 },
|
||||
{ CR38, 0x30 }, { CR34, 0x0f }, { CR35, 0xF0 },
|
||||
{ CR41, 0x2a }, { CR46, 0x7F }, { CR47, 0x1E },
|
||||
{ CR51, 0xc5 }, { CR52, 0xc5 }, { CR53, 0xc5 },
|
||||
{ CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 },
|
||||
{ CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 },
|
||||
{ CR85, 0x00 }, { CR86, 0x10 }, { CR87, 0x2A },
|
||||
{ CR88, 0x10 }, { CR89, 0x24 }, { CR90, 0x18 },
|
||||
/* { CR91, 0x18 }, */
|
||||
/* should solve continous CTS frame problems */
|
||||
{ CR91, 0x00 },
|
||||
{ CR92, 0x0a }, { CR93, 0x00 }, { CR94, 0x01 },
|
||||
{ CR95, 0x00 }, { CR96, 0x40 }, { CR97, 0x37 },
|
||||
{ CR98, 0x05 }, { CR99, 0x28 }, { CR100, 0x00 },
|
||||
{ CR101, 0x13 }, { CR102, 0x27 }, { CR103, 0x27 },
|
||||
{ CR104, 0x18 }, { CR105, 0x12 },
|
||||
/* normal size */
|
||||
{ CR106, 0x1a },
|
||||
/* { CR106, 0x22 }, */
|
||||
{ CR107, 0x24 }, { CR108, 0x0a }, { CR109, 0x13 },
|
||||
{ CR110, 0x2F }, { CR111, 0x27 }, { CR112, 0x27 },
|
||||
{ CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x40 },
|
||||
{ CR116, 0x40 }, { CR117, 0xF0 }, { CR118, 0xF0 },
|
||||
{ CR119, 0x16 },
|
||||
/* no TX continuation */
|
||||
{ CR122, 0x00 },
|
||||
/* { CR122, 0xff }, */
|
||||
{ CR127, 0x03 }, { CR131, 0x08 }, { CR138, 0x28 },
|
||||
{ CR148, 0x44 }, { CR150, 0x10 }, { CR169, 0xBB },
|
||||
{ CR170, 0xBB },
|
||||
};
|
||||
|
||||
static const u32 rv[] = {
|
||||
0x000007, /* REG0(CFG1) */
|
||||
0x07dd43, /* REG1(IFPLL1) */
|
||||
0x080959, /* REG2(IFPLL2) */
|
||||
0x0e6666,
|
||||
0x116a57, /* REG4 */
|
||||
0x17dd43, /* REG5 */
|
||||
0x1819f9, /* REG6 */
|
||||
0x1e6666,
|
||||
0x214554,
|
||||
0x25e7fa,
|
||||
0x27fffa,
|
||||
/* The Zydas driver somehow forgets to set this value. It's
|
||||
* only set for Japan. We are using internal power control
|
||||
* for now.
|
||||
*/
|
||||
0x294128, /* internal power */
|
||||
/* 0x28252c, */ /* External control TX power */
|
||||
/* CR31_CCK, CR51_6-36M, CR52_48M, CR53_54M */
|
||||
0x2c0000,
|
||||
0x300000,
|
||||
0x340000, /* REG13(0xD) */
|
||||
0x381e0f, /* REG14(0xE) */
|
||||
/* Bogus, RF2959's data sheet doesn't know register 27, which is
|
||||
* actually referenced here. The commented 0x11 is 17.
|
||||
*/
|
||||
0x6c180f, /* REG27(0x11) */
|
||||
};
|
||||
|
||||
r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
|
||||
}
|
||||
|
||||
static int rf2959_set_channel(struct zd_rf *rf, u8 channel)
|
||||
{
|
||||
int i, r;
|
||||
u32 *rv = rf2959_table[channel-1];
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
r = zd_rfwrite_locked(chip, rv[i], RF_RV_BITS);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rf2959_switch_radio_on(struct zd_rf *rf)
|
||||
{
|
||||
static const struct zd_ioreq16 ioreqs[] = {
|
||||
{ CR10, 0x89 },
|
||||
{ CR11, 0x00 },
|
||||
};
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
|
||||
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
|
||||
}
|
||||
|
||||
static int rf2959_switch_radio_off(struct zd_rf *rf)
|
||||
{
|
||||
static const struct zd_ioreq16 ioreqs[] = {
|
||||
{ CR10, 0x15 },
|
||||
{ CR11, 0x81 },
|
||||
};
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
|
||||
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
|
||||
}
|
||||
|
||||
int zd_rf_init_rf2959(struct zd_rf *rf)
|
||||
{
|
||||
struct zd_chip *chip = zd_rf_to_chip(rf);
|
||||
|
||||
if (chip->is_zd1211b) {
|
||||
dev_err(zd_chip_dev(chip),
|
||||
"RF2959 is currently not supported for ZD1211B"
|
||||
" devices\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
rf->init_hw = rf2959_init_hw;
|
||||
rf->set_channel = rf2959_set_channel;
|
||||
rf->switch_radio_on = rf2959_switch_radio_on;
|
||||
rf->switch_radio_off = rf2959_switch_radio_off;
|
||||
return 0;
|
||||
}
|
71
drivers/net/wireless/zd1211rw/zd_types.h
Normal file
71
drivers/net/wireless/zd1211rw/zd_types.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* zd_types.h
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _ZD_TYPES_H
|
||||
#define _ZD_TYPES_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* We have three register spaces mapped into the overall USB address space of
|
||||
* 64K words (16-bit values). There is the control register space of
|
||||
* double-word registers, the eeprom register space and the firmware register
|
||||
* space. The control register space is byte mapped, the others are word
|
||||
* mapped.
|
||||
*
|
||||
* For that reason, we are using byte offsets for control registers and word
|
||||
* offsets for everything else.
|
||||
*/
|
||||
|
||||
typedef u32 __nocast zd_addr_t;
|
||||
|
||||
enum {
|
||||
ADDR_BASE_MASK = 0xff000000,
|
||||
ADDR_OFFSET_MASK = 0x0000ffff,
|
||||
ADDR_ZERO_MASK = 0x00ff0000,
|
||||
NULL_BASE = 0x00000000,
|
||||
USB_BASE = 0x01000000,
|
||||
CR_BASE = 0x02000000,
|
||||
CR_MAX_OFFSET = 0x0b30,
|
||||
E2P_BASE = 0x03000000,
|
||||
E2P_MAX_OFFSET = 0x007e,
|
||||
FW_BASE = 0x04000000,
|
||||
FW_MAX_OFFSET = 0x0005,
|
||||
};
|
||||
|
||||
#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK)
|
||||
#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK)
|
||||
|
||||
#define ZD_ADDR(base, offset) \
|
||||
((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK)))
|
||||
|
||||
#define ZD_NULL_ADDR ((zd_addr_t)0)
|
||||
#define USB_REG(offset) ZD_ADDR(USB_BASE, offset) /* word addressing */
|
||||
#define CTL_REG(offset) ZD_ADDR(CR_BASE, offset) /* byte addressing */
|
||||
#define E2P_REG(offset) ZD_ADDR(E2P_BASE, offset) /* word addressing */
|
||||
#define FW_REG(offset) ZD_ADDR(FW_BASE, offset) /* word addressing */
|
||||
|
||||
static inline zd_addr_t zd_inc_word(zd_addr_t addr)
|
||||
{
|
||||
u32 base = ZD_ADDR_BASE(addr);
|
||||
u32 offset = ZD_OFFSET(addr);
|
||||
|
||||
offset += base == CR_BASE ? 2 : 1;
|
||||
|
||||
return base | offset;
|
||||
}
|
||||
|
||||
#endif /* _ZD_TYPES_H */
|
1316
drivers/net/wireless/zd1211rw/zd_usb.c
Normal file
1316
drivers/net/wireless/zd1211rw/zd_usb.c
Normal file
File diff suppressed because it is too large
Load Diff
240
drivers/net/wireless/zd1211rw/zd_usb.h
Normal file
240
drivers/net/wireless/zd1211rw/zd_usb.h
Normal file
@ -0,0 +1,240 @@
|
||||
/* zd_usb.h: Header for USB interface implemented by ZD1211 chip
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _ZD_USB_H
|
||||
#define _ZD_USB_H
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "zd_def.h"
|
||||
#include "zd_types.h"
|
||||
|
||||
enum devicetype {
|
||||
DEVICE_ZD1211 = 0,
|
||||
DEVICE_ZD1211B = 1,
|
||||
};
|
||||
|
||||
enum endpoints {
|
||||
EP_CTRL = 0,
|
||||
EP_DATA_OUT = 1,
|
||||
EP_DATA_IN = 2,
|
||||
EP_INT_IN = 3,
|
||||
EP_REGS_OUT = 4,
|
||||
};
|
||||
|
||||
enum {
|
||||
USB_MAX_TRANSFER_SIZE = 4096, /* bytes */
|
||||
/* FIXME: The original driver uses this value. We have to check,
|
||||
* whether the MAX_TRANSFER_SIZE is sufficient and this needs only be
|
||||
* used if one combined frame is split over two USB transactions.
|
||||
*/
|
||||
USB_MAX_RX_SIZE = 4800, /* bytes */
|
||||
USB_MAX_IOWRITE16_COUNT = 15,
|
||||
USB_MAX_IOWRITE32_COUNT = USB_MAX_IOWRITE16_COUNT/2,
|
||||
USB_MAX_IOREAD16_COUNT = 15,
|
||||
USB_MAX_IOREAD32_COUNT = USB_MAX_IOREAD16_COUNT/2,
|
||||
USB_MIN_RFWRITE_BIT_COUNT = 16,
|
||||
USB_MAX_RFWRITE_BIT_COUNT = 28,
|
||||
USB_MAX_EP_INT_BUFFER = 64,
|
||||
USB_ZD1211B_BCD_DEVICE = 0x4810,
|
||||
};
|
||||
|
||||
enum control_requests {
|
||||
USB_REQ_WRITE_REGS = 0x21,
|
||||
USB_REQ_READ_REGS = 0x22,
|
||||
USB_REQ_WRITE_RF = 0x23,
|
||||
USB_REQ_PROG_FLASH = 0x24,
|
||||
USB_REQ_EEPROM_START = 0x0128, /* ? request is a byte */
|
||||
USB_REQ_EEPROM_MID = 0x28,
|
||||
USB_REQ_EEPROM_END = 0x0228, /* ? request is a byte */
|
||||
USB_REQ_FIRMWARE_DOWNLOAD = 0x30,
|
||||
USB_REQ_FIRMWARE_CONFIRM = 0x31,
|
||||
USB_REQ_FIRMWARE_READ_DATA = 0x32,
|
||||
};
|
||||
|
||||
struct usb_req_read_regs {
|
||||
__le16 id;
|
||||
__le16 addr[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct reg_data {
|
||||
__le16 addr;
|
||||
__le16 value;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct usb_req_write_regs {
|
||||
__le16 id;
|
||||
struct reg_data reg_writes[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
enum {
|
||||
RF_IF_LE = 0x02,
|
||||
RF_CLK = 0x04,
|
||||
RF_DATA = 0x08,
|
||||
};
|
||||
|
||||
struct usb_req_rfwrite {
|
||||
__le16 id;
|
||||
__le16 value;
|
||||
/* 1: 3683a */
|
||||
/* 2: other (default) */
|
||||
__le16 bits;
|
||||
/* RF2595: 24 */
|
||||
__le16 bit_values[0];
|
||||
/* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* USB interrupt */
|
||||
|
||||
enum usb_int_id {
|
||||
USB_INT_TYPE = 0x01,
|
||||
USB_INT_ID_REGS = 0x90,
|
||||
USB_INT_ID_RETRY_FAILED = 0xa0,
|
||||
};
|
||||
|
||||
enum usb_int_flags {
|
||||
USB_INT_READ_REGS_EN = 0x01,
|
||||
};
|
||||
|
||||
struct usb_int_header {
|
||||
u8 type; /* must always be 1 */
|
||||
u8 id;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct usb_int_regs {
|
||||
struct usb_int_header hdr;
|
||||
struct reg_data regs[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct usb_int_retry_fail {
|
||||
struct usb_int_header hdr;
|
||||
u8 new_rate;
|
||||
u8 _dummy;
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 ibss_wakeup_dest;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct read_regs_int {
|
||||
struct completion completion;
|
||||
/* Stores the USB int structure and contains the USB address of the
|
||||
* first requested register before request.
|
||||
*/
|
||||
u8 buffer[USB_MAX_EP_INT_BUFFER];
|
||||
int length;
|
||||
__le16 cr_int_addr;
|
||||
};
|
||||
|
||||
struct zd_ioreq16 {
|
||||
zd_addr_t addr;
|
||||
u16 value;
|
||||
};
|
||||
|
||||
struct zd_ioreq32 {
|
||||
zd_addr_t addr;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
struct zd_usb_interrupt {
|
||||
struct read_regs_int read_regs;
|
||||
spinlock_t lock;
|
||||
struct urb *urb;
|
||||
int interval;
|
||||
u8 read_regs_enabled:1;
|
||||
};
|
||||
|
||||
static inline struct usb_int_regs *get_read_regs(struct zd_usb_interrupt *intr)
|
||||
{
|
||||
return (struct usb_int_regs *)intr->read_regs.buffer;
|
||||
}
|
||||
|
||||
#define URBS_COUNT 5
|
||||
|
||||
struct zd_usb_rx {
|
||||
spinlock_t lock;
|
||||
u8 fragment[2*USB_MAX_RX_SIZE];
|
||||
unsigned int fragment_length;
|
||||
unsigned int usb_packet_size;
|
||||
struct urb **urbs;
|
||||
int urbs_count;
|
||||
};
|
||||
|
||||
struct zd_usb_tx {
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/* Contains the usb parts. The structure doesn't require a lock, because intf
|
||||
* and fw_base_offset, will not be changed after initialization.
|
||||
*/
|
||||
struct zd_usb {
|
||||
struct zd_usb_interrupt intr;
|
||||
struct zd_usb_rx rx;
|
||||
struct zd_usb_tx tx;
|
||||
struct usb_interface *intf;
|
||||
u16 fw_base_offset;
|
||||
};
|
||||
|
||||
#define zd_usb_dev(usb) (&usb->intf->dev)
|
||||
|
||||
static inline struct usb_device *zd_usb_to_usbdev(struct zd_usb *usb)
|
||||
{
|
||||
return interface_to_usbdev(usb->intf);
|
||||
}
|
||||
|
||||
static inline struct net_device *zd_intf_to_netdev(struct usb_interface *intf)
|
||||
{
|
||||
return usb_get_intfdata(intf);
|
||||
}
|
||||
|
||||
static inline struct net_device *zd_usb_to_netdev(struct zd_usb *usb)
|
||||
{
|
||||
return zd_intf_to_netdev(usb->intf);
|
||||
}
|
||||
|
||||
void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
|
||||
struct usb_interface *intf);
|
||||
int zd_usb_init_hw(struct zd_usb *usb);
|
||||
void zd_usb_clear(struct zd_usb *usb);
|
||||
|
||||
int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size);
|
||||
|
||||
int zd_usb_enable_int(struct zd_usb *usb);
|
||||
void zd_usb_disable_int(struct zd_usb *usb);
|
||||
|
||||
int zd_usb_enable_rx(struct zd_usb *usb);
|
||||
void zd_usb_disable_rx(struct zd_usb *usb);
|
||||
|
||||
int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length);
|
||||
|
||||
int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
|
||||
const zd_addr_t *addresses, unsigned int count);
|
||||
|
||||
static inline int zd_usb_ioread16(struct zd_usb *usb, u16 *value,
|
||||
const zd_addr_t addr)
|
||||
{
|
||||
return zd_usb_ioread16v(usb, value, (const zd_addr_t *)&addr, 1);
|
||||
}
|
||||
|
||||
int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
|
||||
unsigned int count);
|
||||
|
||||
int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits);
|
||||
|
||||
#endif /* _ZD_USB_H */
|
82
drivers/net/wireless/zd1211rw/zd_util.c
Normal file
82
drivers/net/wireless/zd1211rw/zd_util.c
Normal file
@ -0,0 +1,82 @@
|
||||
/* zd_util.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Utility program
|
||||
*/
|
||||
|
||||
#include "zd_def.h"
|
||||
#include "zd_util.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
static char hex(u8 v)
|
||||
{
|
||||
v &= 0xf;
|
||||
return (v < 10 ? '0' : 'a' - 10) + v;
|
||||
}
|
||||
|
||||
static char hex_print(u8 c)
|
||||
{
|
||||
return (0x20 <= c && c < 0x7f) ? c : '.';
|
||||
}
|
||||
|
||||
static void dump_line(const u8 *bytes, size_t size)
|
||||
{
|
||||
char c;
|
||||
size_t i;
|
||||
|
||||
size = size <= 8 ? size : 8;
|
||||
printk(KERN_DEBUG "zd1211 %p ", bytes);
|
||||
for (i = 0; i < 8; i++) {
|
||||
switch (i) {
|
||||
case 1:
|
||||
case 5:
|
||||
c = '.';
|
||||
break;
|
||||
case 3:
|
||||
c = ':';
|
||||
break;
|
||||
default:
|
||||
c = ' ';
|
||||
}
|
||||
if (i < size) {
|
||||
printk("%c%c%c", hex(bytes[i] >> 4), hex(bytes[i]), c);
|
||||
} else {
|
||||
printk(" %c", c);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
printk("%c", hex_print(bytes[i]));
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
void zd_hexdump(const void *bytes, size_t size)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
do {
|
||||
dump_line((u8 *)bytes + i, size-i);
|
||||
i += 8;
|
||||
} while (i < size);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size)
|
||||
{
|
||||
if (buffer_size < tail_size)
|
||||
return NULL;
|
||||
return (u8 *)buffer + (buffer_size - tail_size);
|
||||
}
|
29
drivers/net/wireless/zd1211rw/zd_util.h
Normal file
29
drivers/net/wireless/zd1211rw/zd_util.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* zd_util.h
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _ZD_UTIL_H
|
||||
#define _ZD_UTIL_H
|
||||
|
||||
void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size);
|
||||
|
||||
#ifdef DEBUG
|
||||
void zd_hexdump(const void *bytes, size_t size);
|
||||
#else
|
||||
#define zd_hexdump(bytes, size)
|
||||
#endif /* DEBUG */
|
||||
|
||||
#endif /* _ZD_UTIL_H */
|
@ -19,37 +19,13 @@
|
||||
|
||||
Support and updates available at
|
||||
http://www.scyld.com/network/yellowfin.html
|
||||
[link no longer provides useful info -jgarzik]
|
||||
|
||||
|
||||
Linux kernel changelog:
|
||||
-----------------------
|
||||
|
||||
LK1.1.1 (jgarzik): Port to 2.4 kernel
|
||||
|
||||
LK1.1.2 (jgarzik):
|
||||
* Merge in becker version 1.05
|
||||
|
||||
LK1.1.3 (jgarzik):
|
||||
* Various cleanups
|
||||
* Update yellowfin_timer to correctly calculate duplex.
|
||||
(suggested by Manfred Spraul)
|
||||
|
||||
LK1.1.4 (val@nmt.edu):
|
||||
* Fix three endian-ness bugs
|
||||
* Support dual function SYM53C885E ethernet chip
|
||||
|
||||
LK1.1.5 (val@nmt.edu):
|
||||
* Fix forced full-duplex bug I introduced
|
||||
|
||||
LK1.1.6 (val@nmt.edu):
|
||||
* Only print warning on truly "oversized" packets
|
||||
* Fix theoretical bug on gigabit cards - return to 1.1.3 behavior
|
||||
|
||||
*/
|
||||
|
||||
#define DRV_NAME "yellowfin"
|
||||
#define DRV_VERSION "1.05+LK1.1.6"
|
||||
#define DRV_RELDATE "Feb 11, 2002"
|
||||
#define DRV_VERSION "2.0"
|
||||
#define DRV_RELDATE "Jun 27, 2006"
|
||||
|
||||
#define PFX DRV_NAME ": "
|
||||
|
||||
@ -239,8 +215,11 @@ enum capability_flags {
|
||||
HasMACAddrBug=32, /* Only on early revs. */
|
||||
DontUseEeprom=64, /* Don't read the MAC from the EEPROm. */
|
||||
};
|
||||
|
||||
/* The PCI I/O space extent. */
|
||||
#define YELLOWFIN_SIZE 0x100
|
||||
enum {
|
||||
YELLOWFIN_SIZE = 0x100,
|
||||
};
|
||||
|
||||
struct pci_id_info {
|
||||
const char *name;
|
||||
@ -248,16 +227,14 @@ struct pci_id_info {
|
||||
int pci, pci_mask, subsystem, subsystem_mask;
|
||||
int revision, revision_mask; /* Only 8 bits. */
|
||||
} id;
|
||||
int io_size; /* Needed for I/O region check or ioremap(). */
|
||||
int drv_flags; /* Driver use, intended as capability flags. */
|
||||
};
|
||||
|
||||
static const struct pci_id_info pci_id_tbl[] = {
|
||||
{"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff},
|
||||
YELLOWFIN_SIZE,
|
||||
FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom},
|
||||
{"Symbios SYM83C885", { 0x07011000, 0xffffffff},
|
||||
YELLOWFIN_SIZE, HasMII | DontUseEeprom },
|
||||
HasMII | DontUseEeprom },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -1052,7 +1052,7 @@ static void ahci_thaw(struct ata_port *ap)
|
||||
|
||||
static void ahci_error_handler(struct ata_port *ap)
|
||||
{
|
||||
if (!(ap->flags & ATA_FLAG_FROZEN)) {
|
||||
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
|
||||
/* restart engine */
|
||||
ahci_stop_engine(ap);
|
||||
ahci_start_engine(ap);
|
||||
@ -1323,6 +1323,17 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
if (!printed_version++)
|
||||
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
|
||||
|
||||
/* JMicron-specific fixup: make sure we're in AHCI mode */
|
||||
/* This is protected from races with ata_jmicron by the pci probe
|
||||
locking */
|
||||
if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
|
||||
/* AHCI enable, AHCI on function 0 */
|
||||
pci_write_config_byte(pdev, 0x41, 0xa1);
|
||||
/* Function 1 is the PATA controller */
|
||||
if (PCI_FUNC(pdev->devfn))
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = pci_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -1378,10 +1389,6 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
if (have_msi)
|
||||
hpriv->flags |= AHCI_FLAG_MSI;
|
||||
|
||||
/* JMicron-specific fixup: make sure we're in AHCI mode */
|
||||
if (pdev->vendor == 0x197b)
|
||||
pci_write_config_byte(pdev, 0x41, 0xa1);
|
||||
|
||||
/* initialize adapter */
|
||||
rc = ahci_host_init(probe_ent);
|
||||
if (rc)
|
||||
|
@ -61,9 +61,9 @@
|
||||
#include "libata.h"
|
||||
|
||||
/* debounce timing parameters in msecs { interval, duration, timeout } */
|
||||
const unsigned long sata_deb_timing_boot[] = { 5, 100, 2000 };
|
||||
const unsigned long sata_deb_timing_eh[] = { 25, 500, 2000 };
|
||||
const unsigned long sata_deb_timing_before_fsrst[] = { 100, 2000, 5000 };
|
||||
const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
|
||||
const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 };
|
||||
const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 };
|
||||
|
||||
static unsigned int ata_dev_init_params(struct ata_device *dev,
|
||||
u16 heads, u16 sectors);
|
||||
@ -907,7 +907,7 @@ void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (ap->flags & ATA_FLAG_FLUSH_PORT_TASK)
|
||||
if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK)
|
||||
return;
|
||||
|
||||
PREPARE_WORK(&ap->port_task, fn, data);
|
||||
@ -938,7 +938,7 @@ void ata_port_flush_task(struct ata_port *ap)
|
||||
DPRINTK("ENTER\n");
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
ap->flags |= ATA_FLAG_FLUSH_PORT_TASK;
|
||||
ap->pflags |= ATA_PFLAG_FLUSH_PORT_TASK;
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
DPRINTK("flush #1\n");
|
||||
@ -957,7 +957,7 @@ void ata_port_flush_task(struct ata_port *ap)
|
||||
}
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK;
|
||||
ap->pflags &= ~ATA_PFLAG_FLUSH_PORT_TASK;
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
if (ata_msg_ctl(ap))
|
||||
@ -1009,7 +1009,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
/* no internal command while frozen */
|
||||
if (ap->flags & ATA_FLAG_FROZEN) {
|
||||
if (ap->pflags & ATA_PFLAG_FROZEN) {
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
return AC_ERR_SYSTEM;
|
||||
}
|
||||
@ -1325,6 +1325,19 @@ static void ata_dev_config_ncq(struct ata_device *dev,
|
||||
snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
|
||||
}
|
||||
|
||||
static void ata_set_port_max_cmd_len(struct ata_port *ap)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ap->host) {
|
||||
ap->host->max_cmd_len = 0;
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++)
|
||||
ap->host->max_cmd_len = max_t(unsigned int,
|
||||
ap->host->max_cmd_len,
|
||||
ap->device[i].cdb_len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_dev_configure - Configure the specified ATA/ATAPI device
|
||||
* @dev: Target device to configure
|
||||
@ -1344,7 +1357,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
|
||||
struct ata_port *ap = dev->ap;
|
||||
const u16 *id = dev->id;
|
||||
unsigned int xfer_mask;
|
||||
int i, rc;
|
||||
int rc;
|
||||
|
||||
if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
|
||||
ata_dev_printk(dev, KERN_INFO,
|
||||
@ -1404,7 +1417,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
|
||||
ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
|
||||
|
||||
/* print device info to dmesg */
|
||||
if (ata_msg_info(ap))
|
||||
if (ata_msg_drv(ap) && print_info)
|
||||
ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
|
||||
"max %s, %Lu sectors: %s %s\n",
|
||||
ata_id_major_version(id),
|
||||
@ -1427,7 +1440,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
|
||||
}
|
||||
|
||||
/* print device info to dmesg */
|
||||
if (ata_msg_info(ap))
|
||||
if (ata_msg_drv(ap) && print_info)
|
||||
ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
|
||||
"max %s, %Lu sectors: CHS %u/%u/%u\n",
|
||||
ata_id_major_version(id),
|
||||
@ -1439,7 +1452,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
|
||||
|
||||
if (dev->id[59] & 0x100) {
|
||||
dev->multi_count = dev->id[59] & 0xff;
|
||||
if (ata_msg_info(ap))
|
||||
if (ata_msg_drv(ap) && print_info)
|
||||
ata_dev_printk(dev, KERN_INFO,
|
||||
"ata%u: dev %u multi count %u\n",
|
||||
ap->id, dev->devno, dev->multi_count);
|
||||
@ -1468,21 +1481,17 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
|
||||
}
|
||||
|
||||
/* print device info to dmesg */
|
||||
if (ata_msg_info(ap))
|
||||
if (ata_msg_drv(ap) && print_info)
|
||||
ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
|
||||
ata_mode_string(xfer_mask),
|
||||
cdb_intr_string);
|
||||
}
|
||||
|
||||
ap->host->max_cmd_len = 0;
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++)
|
||||
ap->host->max_cmd_len = max_t(unsigned int,
|
||||
ap->host->max_cmd_len,
|
||||
ap->device[i].cdb_len);
|
||||
ata_set_port_max_cmd_len(ap);
|
||||
|
||||
/* limit bridge transfers to udma5, 200 sectors */
|
||||
if (ata_dev_knobble(dev)) {
|
||||
if (ata_msg_info(ap))
|
||||
if (ata_msg_drv(ap) && print_info)
|
||||
ata_dev_printk(dev, KERN_INFO,
|
||||
"applying bridge limits\n");
|
||||
dev->udma_mask &= ATA_UDMA5;
|
||||
@ -2137,7 +2146,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
|
||||
* return error code and failing device on failure.
|
||||
*/
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++) {
|
||||
if (ata_dev_enabled(&ap->device[i])) {
|
||||
if (ata_dev_ready(&ap->device[i])) {
|
||||
ap->ops->set_mode(ap);
|
||||
break;
|
||||
}
|
||||
@ -2203,7 +2212,8 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++) {
|
||||
dev = &ap->device[i];
|
||||
|
||||
if (!ata_dev_enabled(dev))
|
||||
/* don't udpate suspended devices' xfer mode */
|
||||
if (!ata_dev_ready(dev))
|
||||
continue;
|
||||
|
||||
rc = ata_dev_set_mode(dev);
|
||||
@ -2579,7 +2589,7 @@ static void ata_wait_spinup(struct ata_port *ap)
|
||||
|
||||
/* first, debounce phy if SATA */
|
||||
if (ap->cbl == ATA_CBL_SATA) {
|
||||
rc = sata_phy_debounce(ap, sata_deb_timing_eh);
|
||||
rc = sata_phy_debounce(ap, sata_deb_timing_hotplug);
|
||||
|
||||
/* if debounced successfully and offline, no need to wait */
|
||||
if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
|
||||
@ -2615,16 +2625,17 @@ static void ata_wait_spinup(struct ata_port *ap)
|
||||
int ata_std_prereset(struct ata_port *ap)
|
||||
{
|
||||
struct ata_eh_context *ehc = &ap->eh_context;
|
||||
const unsigned long *timing;
|
||||
const unsigned long *timing = sata_ehc_deb_timing(ehc);
|
||||
int rc;
|
||||
|
||||
/* hotplug? */
|
||||
if (ehc->i.flags & ATA_EHI_HOTPLUGGED) {
|
||||
if (ap->flags & ATA_FLAG_HRST_TO_RESUME)
|
||||
ehc->i.action |= ATA_EH_HARDRESET;
|
||||
if (ap->flags & ATA_FLAG_SKIP_D2H_BSY)
|
||||
ata_wait_spinup(ap);
|
||||
}
|
||||
/* handle link resume & hotplug spinup */
|
||||
if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
|
||||
(ap->flags & ATA_FLAG_HRST_TO_RESUME))
|
||||
ehc->i.action |= ATA_EH_HARDRESET;
|
||||
|
||||
if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) &&
|
||||
(ap->flags & ATA_FLAG_SKIP_D2H_BSY))
|
||||
ata_wait_spinup(ap);
|
||||
|
||||
/* if we're about to do hardreset, nothing more to do */
|
||||
if (ehc->i.action & ATA_EH_HARDRESET)
|
||||
@ -2632,11 +2643,6 @@ int ata_std_prereset(struct ata_port *ap)
|
||||
|
||||
/* if SATA, resume phy */
|
||||
if (ap->cbl == ATA_CBL_SATA) {
|
||||
if (ap->flags & ATA_FLAG_LOADING)
|
||||
timing = sata_deb_timing_boot;
|
||||
else
|
||||
timing = sata_deb_timing_eh;
|
||||
|
||||
rc = sata_phy_resume(ap, timing);
|
||||
if (rc && rc != -EOPNOTSUPP) {
|
||||
/* phy resume failed */
|
||||
@ -2724,6 +2730,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
|
||||
*/
|
||||
int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
|
||||
{
|
||||
struct ata_eh_context *ehc = &ap->eh_context;
|
||||
const unsigned long *timing = sata_ehc_deb_timing(ehc);
|
||||
u32 scontrol;
|
||||
int rc;
|
||||
|
||||
@ -2761,7 +2769,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
|
||||
msleep(1);
|
||||
|
||||
/* bring phy back */
|
||||
sata_phy_resume(ap, sata_deb_timing_eh);
|
||||
sata_phy_resume(ap, timing);
|
||||
|
||||
/* TODO: phy layer with polling, timeouts, etc. */
|
||||
if (ata_port_offline(ap)) {
|
||||
@ -4285,7 +4293,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
|
||||
unsigned int i;
|
||||
|
||||
/* no command while frozen */
|
||||
if (unlikely(ap->flags & ATA_FLAG_FROZEN))
|
||||
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
|
||||
return NULL;
|
||||
|
||||
/* the last tag is reserved for internal command. */
|
||||
@ -4407,7 +4415,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
|
||||
* taken care of.
|
||||
*/
|
||||
if (ap->ops->error_handler) {
|
||||
WARN_ON(ap->flags & ATA_FLAG_FROZEN);
|
||||
WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
|
||||
|
||||
if (unlikely(qc->err_mask))
|
||||
qc->flags |= ATA_QCFLAG_FAILED;
|
||||
@ -5001,86 +5009,120 @@ int ata_flush_cache(struct ata_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ata_standby_drive(struct ata_device *dev)
|
||||
static int ata_host_set_request_pm(struct ata_host_set *host_set,
|
||||
pm_message_t mesg, unsigned int action,
|
||||
unsigned int ehi_flags, int wait)
|
||||
{
|
||||
unsigned int err_mask;
|
||||
unsigned long flags;
|
||||
int i, rc;
|
||||
|
||||
err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
|
||||
if (err_mask) {
|
||||
ata_dev_printk(dev, KERN_ERR, "failed to standby drive "
|
||||
"(err_mask=0x%x)\n", err_mask);
|
||||
return -EIO;
|
||||
}
|
||||
for (i = 0; i < host_set->n_ports; i++) {
|
||||
struct ata_port *ap = host_set->ports[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* Previous resume operation might still be in
|
||||
* progress. Wait for PM_PENDING to clear.
|
||||
*/
|
||||
if (ap->pflags & ATA_PFLAG_PM_PENDING) {
|
||||
ata_port_wait_eh(ap);
|
||||
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
|
||||
}
|
||||
|
||||
static int ata_start_drive(struct ata_device *dev)
|
||||
{
|
||||
unsigned int err_mask;
|
||||
/* request PM ops to EH */
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
|
||||
if (err_mask) {
|
||||
ata_dev_printk(dev, KERN_ERR, "failed to start drive "
|
||||
"(err_mask=0x%x)\n", err_mask);
|
||||
return -EIO;
|
||||
ap->pm_mesg = mesg;
|
||||
if (wait) {
|
||||
rc = 0;
|
||||
ap->pm_result = &rc;
|
||||
}
|
||||
|
||||
ap->pflags |= ATA_PFLAG_PM_PENDING;
|
||||
ap->eh_info.action |= action;
|
||||
ap->eh_info.flags |= ehi_flags;
|
||||
|
||||
ata_port_schedule_eh(ap);
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
/* wait and check result */
|
||||
if (wait) {
|
||||
ata_port_wait_eh(ap);
|
||||
WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_device_resume - wakeup a previously suspended devices
|
||||
* @dev: the device to resume
|
||||
* ata_host_set_suspend - suspend host_set
|
||||
* @host_set: host_set to suspend
|
||||
* @mesg: PM message
|
||||
*
|
||||
* Kick the drive back into action, by sending it an idle immediate
|
||||
* command and making sure its transfer mode matches between drive
|
||||
* and host.
|
||||
* Suspend @host_set. Actual operation is performed by EH. This
|
||||
* function requests EH to perform PM operations and waits for EH
|
||||
* to finish.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep).
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, -errno on failure.
|
||||
*/
|
||||
int ata_device_resume(struct ata_device *dev)
|
||||
int ata_host_set_suspend(struct ata_host_set *host_set, pm_message_t mesg)
|
||||
{
|
||||
struct ata_port *ap = dev->ap;
|
||||
int i, j, rc;
|
||||
|
||||
if (ap->flags & ATA_FLAG_SUSPENDED) {
|
||||
struct ata_device *failed_dev;
|
||||
rc = ata_host_set_request_pm(host_set, mesg, 0, ATA_EHI_QUIET, 1);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
|
||||
ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
|
||||
/* EH is quiescent now. Fail if we have any ready device.
|
||||
* This happens if hotplug occurs between completion of device
|
||||
* suspension and here.
|
||||
*/
|
||||
for (i = 0; i < host_set->n_ports; i++) {
|
||||
struct ata_port *ap = host_set->ports[i];
|
||||
|
||||
ap->flags &= ~ATA_FLAG_SUSPENDED;
|
||||
while (ata_set_mode(ap, &failed_dev))
|
||||
ata_dev_disable(failed_dev);
|
||||
for (j = 0; j < ATA_MAX_DEVICES; j++) {
|
||||
struct ata_device *dev = &ap->device[j];
|
||||
|
||||
if (ata_dev_ready(dev)) {
|
||||
ata_port_printk(ap, KERN_WARNING,
|
||||
"suspend failed, device %d "
|
||||
"still active\n", dev->devno);
|
||||
rc = -EBUSY;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ata_dev_enabled(dev))
|
||||
return 0;
|
||||
if (dev->class == ATA_DEV_ATA)
|
||||
ata_start_drive(dev);
|
||||
|
||||
host_set->dev->power.power_state = mesg;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ata_host_set_resume(host_set);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_device_suspend - prepare a device for suspend
|
||||
* @dev: the device to suspend
|
||||
* @state: target power management state
|
||||
* ata_host_set_resume - resume host_set
|
||||
* @host_set: host_set to resume
|
||||
*
|
||||
* Flush the cache on the drive, if appropriate, then issue a
|
||||
* standbynow command.
|
||||
* Resume @host_set. Actual operation is performed by EH. This
|
||||
* function requests EH to perform PM operations and returns.
|
||||
* Note that all resume operations are performed parallely.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep).
|
||||
*/
|
||||
int ata_device_suspend(struct ata_device *dev, pm_message_t state)
|
||||
void ata_host_set_resume(struct ata_host_set *host_set)
|
||||
{
|
||||
struct ata_port *ap = dev->ap;
|
||||
|
||||
if (!ata_dev_enabled(dev))
|
||||
return 0;
|
||||
if (dev->class == ATA_DEV_ATA)
|
||||
ata_flush_cache(dev);
|
||||
|
||||
if (state.event != PM_EVENT_FREEZE)
|
||||
ata_standby_drive(dev);
|
||||
ap->flags |= ATA_FLAG_SUSPENDED;
|
||||
return 0;
|
||||
ata_host_set_request_pm(host_set, PMSG_ON, ATA_EH_SOFTRESET,
|
||||
ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
|
||||
host_set->dev->power.power_state = PMSG_ON;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5440,6 +5482,7 @@ int ata_device_add(const struct ata_probe_ent *ent)
|
||||
}
|
||||
|
||||
if (ap->ops->error_handler) {
|
||||
struct ata_eh_info *ehi = &ap->eh_info;
|
||||
unsigned long flags;
|
||||
|
||||
ata_port_probe(ap);
|
||||
@ -5447,10 +5490,11 @@ int ata_device_add(const struct ata_probe_ent *ent)
|
||||
/* kick EH for boot probing */
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1;
|
||||
ap->eh_info.action |= ATA_EH_SOFTRESET;
|
||||
ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
|
||||
ehi->action |= ATA_EH_SOFTRESET;
|
||||
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
|
||||
|
||||
ap->flags |= ATA_FLAG_LOADING;
|
||||
ap->pflags |= ATA_PFLAG_LOADING;
|
||||
ata_port_schedule_eh(ap);
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
@ -5518,7 +5562,7 @@ void ata_port_detach(struct ata_port *ap)
|
||||
|
||||
/* tell EH we're leaving & flush EH */
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
ap->flags |= ATA_FLAG_UNLOADING;
|
||||
ap->pflags |= ATA_PFLAG_UNLOADING;
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
ata_port_wait_eh(ap);
|
||||
@ -5723,20 +5767,55 @@ int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
|
||||
return (tmp == bits->val) ? 1 : 0;
|
||||
}
|
||||
|
||||
int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
{
|
||||
pci_save_state(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_set_power_state(pdev, PCI_D3hot);
|
||||
return 0;
|
||||
|
||||
if (state.event == PM_EVENT_SUSPEND) {
|
||||
pci_disable_device(pdev);
|
||||
pci_set_power_state(pdev, PCI_D3hot);
|
||||
}
|
||||
}
|
||||
|
||||
int ata_pci_device_resume(struct pci_dev *pdev)
|
||||
void ata_pci_device_do_resume(struct pci_dev *pdev)
|
||||
{
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
pci_enable_device(pdev);
|
||||
pci_set_master(pdev);
|
||||
}
|
||||
|
||||
int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
{
|
||||
struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
|
||||
int rc = 0;
|
||||
|
||||
rc = ata_host_set_suspend(host_set, state);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (host_set->next) {
|
||||
rc = ata_host_set_suspend(host_set->next, state);
|
||||
if (rc) {
|
||||
ata_host_set_resume(host_set);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
ata_pci_device_do_suspend(pdev, state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ata_pci_device_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
ata_pci_device_do_resume(pdev);
|
||||
ata_host_set_resume(host_set);
|
||||
if (host_set->next)
|
||||
ata_host_set_resume(host_set->next);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PCI */
|
||||
@ -5842,9 +5921,9 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
|
||||
* Do not depend on ABI/API stability.
|
||||
*/
|
||||
|
||||
EXPORT_SYMBOL_GPL(sata_deb_timing_boot);
|
||||
EXPORT_SYMBOL_GPL(sata_deb_timing_eh);
|
||||
EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst);
|
||||
EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
|
||||
EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
|
||||
EXPORT_SYMBOL_GPL(sata_deb_timing_long);
|
||||
EXPORT_SYMBOL_GPL(ata_std_bios_param);
|
||||
EXPORT_SYMBOL_GPL(ata_std_ports);
|
||||
EXPORT_SYMBOL_GPL(ata_device_add);
|
||||
@ -5916,6 +5995,8 @@ EXPORT_SYMBOL_GPL(sata_scr_write);
|
||||
EXPORT_SYMBOL_GPL(sata_scr_write_flush);
|
||||
EXPORT_SYMBOL_GPL(ata_port_online);
|
||||
EXPORT_SYMBOL_GPL(ata_port_offline);
|
||||
EXPORT_SYMBOL_GPL(ata_host_set_suspend);
|
||||
EXPORT_SYMBOL_GPL(ata_host_set_resume);
|
||||
EXPORT_SYMBOL_GPL(ata_id_string);
|
||||
EXPORT_SYMBOL_GPL(ata_id_c_string);
|
||||
EXPORT_SYMBOL_GPL(ata_scsi_simulate);
|
||||
@ -5930,14 +6011,14 @@ EXPORT_SYMBOL_GPL(ata_pci_host_stop);
|
||||
EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
|
||||
EXPORT_SYMBOL_GPL(ata_pci_init_one);
|
||||
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
|
||||
EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
|
||||
EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
|
||||
EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
|
||||
EXPORT_SYMBOL_GPL(ata_pci_device_resume);
|
||||
EXPORT_SYMBOL_GPL(ata_pci_default_filter);
|
||||
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
EXPORT_SYMBOL_GPL(ata_device_suspend);
|
||||
EXPORT_SYMBOL_GPL(ata_device_resume);
|
||||
EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
|
||||
EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
|
||||
|
||||
|
@ -47,6 +47,8 @@
|
||||
|
||||
static void __ata_port_freeze(struct ata_port *ap);
|
||||
static void ata_eh_finish(struct ata_port *ap);
|
||||
static void ata_eh_handle_port_suspend(struct ata_port *ap);
|
||||
static void ata_eh_handle_port_resume(struct ata_port *ap);
|
||||
|
||||
static void ata_ering_record(struct ata_ering *ering, int is_io,
|
||||
unsigned int err_mask)
|
||||
@ -190,7 +192,6 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
|
||||
void ata_scsi_error(struct Scsi_Host *host)
|
||||
{
|
||||
struct ata_port *ap = ata_shost_to_port(host);
|
||||
spinlock_t *ap_lock = ap->lock;
|
||||
int i, repeat_cnt = ATA_EH_MAX_REPEAT;
|
||||
unsigned long flags;
|
||||
|
||||
@ -217,7 +218,7 @@ void ata_scsi_error(struct Scsi_Host *host)
|
||||
struct scsi_cmnd *scmd, *tmp;
|
||||
int nr_timedout = 0;
|
||||
|
||||
spin_lock_irqsave(ap_lock, flags);
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
|
||||
struct ata_queued_cmd *qc;
|
||||
@ -256,43 +257,49 @@ void ata_scsi_error(struct Scsi_Host *host)
|
||||
if (nr_timedout)
|
||||
__ata_port_freeze(ap);
|
||||
|
||||
spin_unlock_irqrestore(ap_lock, flags);
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
} else
|
||||
spin_unlock_wait(ap_lock);
|
||||
spin_unlock_wait(ap->lock);
|
||||
|
||||
repeat:
|
||||
/* invoke error handler */
|
||||
if (ap->ops->error_handler) {
|
||||
/* process port resume request */
|
||||
ata_eh_handle_port_resume(ap);
|
||||
|
||||
/* fetch & clear EH info */
|
||||
spin_lock_irqsave(ap_lock, flags);
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
memset(&ap->eh_context, 0, sizeof(ap->eh_context));
|
||||
ap->eh_context.i = ap->eh_info;
|
||||
memset(&ap->eh_info, 0, sizeof(ap->eh_info));
|
||||
|
||||
ap->flags |= ATA_FLAG_EH_IN_PROGRESS;
|
||||
ap->flags &= ~ATA_FLAG_EH_PENDING;
|
||||
ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
|
||||
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
|
||||
|
||||
spin_unlock_irqrestore(ap_lock, flags);
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
/* invoke EH. if unloading, just finish failed qcs */
|
||||
if (!(ap->flags & ATA_FLAG_UNLOADING))
|
||||
/* invoke EH, skip if unloading or suspended */
|
||||
if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
|
||||
ap->ops->error_handler(ap);
|
||||
else
|
||||
ata_eh_finish(ap);
|
||||
|
||||
/* process port suspend request */
|
||||
ata_eh_handle_port_suspend(ap);
|
||||
|
||||
/* Exception might have happend after ->error_handler
|
||||
* recovered the port but before this point. Repeat
|
||||
* EH in such case.
|
||||
*/
|
||||
spin_lock_irqsave(ap_lock, flags);
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
if (ap->flags & ATA_FLAG_EH_PENDING) {
|
||||
if (ap->pflags & ATA_PFLAG_EH_PENDING) {
|
||||
if (--repeat_cnt) {
|
||||
ata_port_printk(ap, KERN_INFO,
|
||||
"EH pending after completion, "
|
||||
"repeating EH (cnt=%d)\n", repeat_cnt);
|
||||
spin_unlock_irqrestore(ap_lock, flags);
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
goto repeat;
|
||||
}
|
||||
ata_port_printk(ap, KERN_ERR, "EH pending after %d "
|
||||
@ -302,14 +309,14 @@ void ata_scsi_error(struct Scsi_Host *host)
|
||||
/* this run is complete, make sure EH info is clear */
|
||||
memset(&ap->eh_info, 0, sizeof(ap->eh_info));
|
||||
|
||||
/* Clear host_eh_scheduled while holding ap_lock such
|
||||
/* Clear host_eh_scheduled while holding ap->lock such
|
||||
* that if exception occurs after this point but
|
||||
* before EH completion, SCSI midlayer will
|
||||
* re-initiate EH.
|
||||
*/
|
||||
host->host_eh_scheduled = 0;
|
||||
|
||||
spin_unlock_irqrestore(ap_lock, flags);
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
} else {
|
||||
WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
|
||||
ap->ops->eng_timeout(ap);
|
||||
@ -321,24 +328,23 @@ void ata_scsi_error(struct Scsi_Host *host)
|
||||
scsi_eh_flush_done_q(&ap->eh_done_q);
|
||||
|
||||
/* clean up */
|
||||
spin_lock_irqsave(ap_lock, flags);
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
if (ap->flags & ATA_FLAG_LOADING) {
|
||||
ap->flags &= ~ATA_FLAG_LOADING;
|
||||
} else {
|
||||
if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
|
||||
queue_work(ata_aux_wq, &ap->hotplug_task);
|
||||
if (ap->flags & ATA_FLAG_RECOVERED)
|
||||
ata_port_printk(ap, KERN_INFO, "EH complete\n");
|
||||
}
|
||||
if (ap->pflags & ATA_PFLAG_LOADING)
|
||||
ap->pflags &= ~ATA_PFLAG_LOADING;
|
||||
else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
|
||||
queue_work(ata_aux_wq, &ap->hotplug_task);
|
||||
|
||||
ap->flags &= ~(ATA_FLAG_SCSI_HOTPLUG | ATA_FLAG_RECOVERED);
|
||||
if (ap->pflags & ATA_PFLAG_RECOVERED)
|
||||
ata_port_printk(ap, KERN_INFO, "EH complete\n");
|
||||
|
||||
ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED);
|
||||
|
||||
/* tell wait_eh that we're done */
|
||||
ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS;
|
||||
ap->pflags &= ~ATA_PFLAG_EH_IN_PROGRESS;
|
||||
wake_up_all(&ap->eh_wait_q);
|
||||
|
||||
spin_unlock_irqrestore(ap_lock, flags);
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
DPRINTK("EXIT\n");
|
||||
}
|
||||
@ -360,7 +366,7 @@ void ata_port_wait_eh(struct ata_port *ap)
|
||||
retry:
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
while (ap->flags & (ATA_FLAG_EH_PENDING | ATA_FLAG_EH_IN_PROGRESS)) {
|
||||
while (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS)) {
|
||||
prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
schedule();
|
||||
@ -489,7 +495,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
|
||||
WARN_ON(!ap->ops->error_handler);
|
||||
|
||||
qc->flags |= ATA_QCFLAG_FAILED;
|
||||
qc->ap->flags |= ATA_FLAG_EH_PENDING;
|
||||
qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
|
||||
|
||||
/* The following will fail if timeout has already expired.
|
||||
* ata_scsi_error() takes care of such scmds on EH entry.
|
||||
@ -513,7 +519,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
|
||||
{
|
||||
WARN_ON(!ap->ops->error_handler);
|
||||
|
||||
ap->flags |= ATA_FLAG_EH_PENDING;
|
||||
ap->pflags |= ATA_PFLAG_EH_PENDING;
|
||||
scsi_schedule_eh(ap->host);
|
||||
|
||||
DPRINTK("port EH scheduled\n");
|
||||
@ -578,7 +584,7 @@ static void __ata_port_freeze(struct ata_port *ap)
|
||||
if (ap->ops->freeze)
|
||||
ap->ops->freeze(ap);
|
||||
|
||||
ap->flags |= ATA_FLAG_FROZEN;
|
||||
ap->pflags |= ATA_PFLAG_FROZEN;
|
||||
|
||||
DPRINTK("ata%u port frozen\n", ap->id);
|
||||
}
|
||||
@ -646,7 +652,7 @@ void ata_eh_thaw_port(struct ata_port *ap)
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
ap->flags &= ~ATA_FLAG_FROZEN;
|
||||
ap->pflags &= ~ATA_PFLAG_FROZEN;
|
||||
|
||||
if (ap->ops->thaw)
|
||||
ap->ops->thaw(ap);
|
||||
@ -731,7 +737,7 @@ static void ata_eh_detach_dev(struct ata_device *dev)
|
||||
|
||||
if (ata_scsi_offline_dev(dev)) {
|
||||
dev->flags |= ATA_DFLAG_DETACHED;
|
||||
ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
|
||||
ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
|
||||
}
|
||||
|
||||
/* clear per-dev EH actions */
|
||||
@ -760,8 +766,12 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
ata_eh_clear_action(dev, &ap->eh_info, action);
|
||||
ap->flags |= ATA_FLAG_RECOVERED;
|
||||
|
||||
if (!(ap->eh_context.i.flags & ATA_EHI_QUIET))
|
||||
ap->pflags |= ATA_PFLAG_RECOVERED;
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
}
|
||||
|
||||
@ -1027,7 +1037,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
|
||||
int tag, rc;
|
||||
|
||||
/* if frozen, we can't do much */
|
||||
if (ap->flags & ATA_FLAG_FROZEN)
|
||||
if (ap->pflags & ATA_PFLAG_FROZEN)
|
||||
return;
|
||||
|
||||
/* is it NCQ device error? */
|
||||
@ -1275,6 +1285,9 @@ static void ata_eh_autopsy(struct ata_port *ap)
|
||||
|
||||
DPRINTK("ENTER\n");
|
||||
|
||||
if (ehc->i.flags & ATA_EHI_NO_AUTOPSY)
|
||||
return;
|
||||
|
||||
/* obtain and analyze SError */
|
||||
rc = sata_scr_read(ap, SCR_ERROR, &serror);
|
||||
if (rc == 0) {
|
||||
@ -1327,7 +1340,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
|
||||
}
|
||||
|
||||
/* enforce default EH actions */
|
||||
if (ap->flags & ATA_FLAG_FROZEN ||
|
||||
if (ap->pflags & ATA_PFLAG_FROZEN ||
|
||||
all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
|
||||
action |= ATA_EH_SOFTRESET;
|
||||
else if (all_err_mask)
|
||||
@ -1346,7 +1359,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
|
||||
|
||||
/* record autopsy result */
|
||||
ehc->i.dev = failed_dev;
|
||||
ehc->i.action = action;
|
||||
ehc->i.action |= action;
|
||||
|
||||
DPRINTK("EXIT\n");
|
||||
}
|
||||
@ -1385,7 +1398,7 @@ static void ata_eh_report(struct ata_port *ap)
|
||||
return;
|
||||
|
||||
frozen = "";
|
||||
if (ap->flags & ATA_FLAG_FROZEN)
|
||||
if (ap->pflags & ATA_PFLAG_FROZEN)
|
||||
frozen = " frozen";
|
||||
|
||||
if (ehc->i.dev) {
|
||||
@ -1465,7 +1478,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
|
||||
struct ata_eh_context *ehc = &ap->eh_context;
|
||||
unsigned int *classes = ehc->classes;
|
||||
int tries = ATA_EH_RESET_TRIES;
|
||||
int verbose = !(ap->flags & ATA_FLAG_LOADING);
|
||||
int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
|
||||
unsigned int action;
|
||||
ata_reset_fn_t reset;
|
||||
int i, did_followup_srst, rc;
|
||||
@ -1605,7 +1618,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
|
||||
dev = &ap->device[i];
|
||||
action = ata_eh_dev_action(dev);
|
||||
|
||||
if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) {
|
||||
if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
|
||||
if (ata_port_offline(ap)) {
|
||||
rc = -EIO;
|
||||
break;
|
||||
@ -1636,7 +1649,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
|
||||
}
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
|
||||
ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
}
|
||||
}
|
||||
@ -1648,6 +1661,164 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_eh_suspend - handle suspend EH action
|
||||
* @ap: target host port
|
||||
* @r_failed_dev: result parameter to indicate failing device
|
||||
*
|
||||
* Handle suspend EH action. Disk devices are spinned down and
|
||||
* other types of devices are just marked suspended. Once
|
||||
* suspended, no EH action to the device is allowed until it is
|
||||
* resumed.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep).
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, -errno otherwise
|
||||
*/
|
||||
static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
|
||||
{
|
||||
struct ata_device *dev;
|
||||
int i, rc = 0;
|
||||
|
||||
DPRINTK("ENTER\n");
|
||||
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++) {
|
||||
unsigned long flags;
|
||||
unsigned int action, err_mask;
|
||||
|
||||
dev = &ap->device[i];
|
||||
action = ata_eh_dev_action(dev);
|
||||
|
||||
if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND))
|
||||
continue;
|
||||
|
||||
WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED);
|
||||
|
||||
ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND);
|
||||
|
||||
if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
|
||||
/* flush cache */
|
||||
rc = ata_flush_cache(dev);
|
||||
if (rc)
|
||||
break;
|
||||
|
||||
/* spin down */
|
||||
err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
|
||||
if (err_mask) {
|
||||
ata_dev_printk(dev, KERN_ERR, "failed to "
|
||||
"spin down (err_mask=0x%x)\n",
|
||||
err_mask);
|
||||
rc = -EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
dev->flags |= ATA_DFLAG_SUSPENDED;
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
ata_eh_done(ap, dev, ATA_EH_SUSPEND);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
*r_failed_dev = dev;
|
||||
|
||||
DPRINTK("EXIT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_eh_prep_resume - prep for resume EH action
|
||||
* @ap: target host port
|
||||
*
|
||||
* Clear SUSPENDED in preparation for scheduled resume actions.
|
||||
* This allows other parts of EH to access the devices being
|
||||
* resumed.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep).
|
||||
*/
|
||||
static void ata_eh_prep_resume(struct ata_port *ap)
|
||||
{
|
||||
struct ata_device *dev;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
DPRINTK("ENTER\n");
|
||||
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++) {
|
||||
unsigned int action;
|
||||
|
||||
dev = &ap->device[i];
|
||||
action = ata_eh_dev_action(dev);
|
||||
|
||||
if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
|
||||
continue;
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
dev->flags &= ~ATA_DFLAG_SUSPENDED;
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
}
|
||||
|
||||
DPRINTK("EXIT\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_eh_resume - handle resume EH action
|
||||
* @ap: target host port
|
||||
* @r_failed_dev: result parameter to indicate failing device
|
||||
*
|
||||
* Handle resume EH action. Target devices are already reset and
|
||||
* revalidated. Spinning up is the only operation left.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep).
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, -errno otherwise
|
||||
*/
|
||||
static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev)
|
||||
{
|
||||
struct ata_device *dev;
|
||||
int i, rc = 0;
|
||||
|
||||
DPRINTK("ENTER\n");
|
||||
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++) {
|
||||
unsigned int action, err_mask;
|
||||
|
||||
dev = &ap->device[i];
|
||||
action = ata_eh_dev_action(dev);
|
||||
|
||||
if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
|
||||
continue;
|
||||
|
||||
ata_eh_about_to_do(ap, dev, ATA_EH_RESUME);
|
||||
|
||||
if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
|
||||
err_mask = ata_do_simple_cmd(dev,
|
||||
ATA_CMD_IDLEIMMEDIATE);
|
||||
if (err_mask) {
|
||||
ata_dev_printk(dev, KERN_ERR, "failed to "
|
||||
"spin up (err_mask=0x%x)\n",
|
||||
err_mask);
|
||||
rc = -EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ata_eh_done(ap, dev, ATA_EH_RESUME);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
*r_failed_dev = dev;
|
||||
|
||||
DPRINTK("EXIT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ata_port_nr_enabled(struct ata_port *ap)
|
||||
{
|
||||
int i, cnt = 0;
|
||||
@ -1673,7 +1844,19 @@ static int ata_eh_skip_recovery(struct ata_port *ap)
|
||||
struct ata_eh_context *ehc = &ap->eh_context;
|
||||
int i;
|
||||
|
||||
if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap))
|
||||
/* skip if all possible devices are suspended */
|
||||
for (i = 0; i < ata_port_max_devices(ap); i++) {
|
||||
struct ata_device *dev = &ap->device[i];
|
||||
|
||||
if (ata_dev_absent(dev) || ata_dev_ready(dev))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ata_port_max_devices(ap))
|
||||
return 1;
|
||||
|
||||
/* always thaw frozen port and recover failed devices */
|
||||
if (ap->pflags & ATA_PFLAG_FROZEN || ata_port_nr_enabled(ap))
|
||||
return 0;
|
||||
|
||||
/* skip if class codes for all vacant slots are ATA_DEV_NONE */
|
||||
@ -1744,9 +1927,12 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
|
||||
rc = 0;
|
||||
|
||||
/* if UNLOADING, finish immediately */
|
||||
if (ap->flags & ATA_FLAG_UNLOADING)
|
||||
if (ap->pflags & ATA_PFLAG_UNLOADING)
|
||||
goto out;
|
||||
|
||||
/* prep for resume */
|
||||
ata_eh_prep_resume(ap);
|
||||
|
||||
/* skip EH if possible. */
|
||||
if (ata_eh_skip_recovery(ap))
|
||||
ehc->i.action = 0;
|
||||
@ -1774,6 +1960,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
|
||||
if (rc)
|
||||
goto dev_fail;
|
||||
|
||||
/* resume devices */
|
||||
rc = ata_eh_resume(ap, &dev);
|
||||
if (rc)
|
||||
goto dev_fail;
|
||||
|
||||
/* configure transfer mode if the port has been reset */
|
||||
if (ehc->i.flags & ATA_EHI_DID_RESET) {
|
||||
rc = ata_set_mode(ap, &dev);
|
||||
@ -1783,6 +1974,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
|
||||
}
|
||||
}
|
||||
|
||||
/* suspend devices */
|
||||
rc = ata_eh_suspend(ap, &dev);
|
||||
if (rc)
|
||||
goto dev_fail;
|
||||
|
||||
goto out;
|
||||
|
||||
dev_fail:
|
||||
@ -1908,11 +2104,124 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
|
||||
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
|
||||
ata_postreset_fn_t postreset)
|
||||
{
|
||||
if (!(ap->flags & ATA_FLAG_LOADING)) {
|
||||
ata_eh_autopsy(ap);
|
||||
ata_eh_report(ap);
|
||||
}
|
||||
|
||||
ata_eh_autopsy(ap);
|
||||
ata_eh_report(ap);
|
||||
ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
|
||||
ata_eh_finish(ap);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_eh_handle_port_suspend - perform port suspend operation
|
||||
* @ap: port to suspend
|
||||
*
|
||||
* Suspend @ap.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep).
|
||||
*/
|
||||
static void ata_eh_handle_port_suspend(struct ata_port *ap)
|
||||
{
|
||||
unsigned long flags;
|
||||
int rc = 0;
|
||||
|
||||
/* are we suspending? */
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
|
||||
ap->pm_mesg.event == PM_EVENT_ON) {
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
return;
|
||||
}
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
|
||||
|
||||
/* suspend */
|
||||
ata_eh_freeze_port(ap);
|
||||
|
||||
if (ap->ops->port_suspend)
|
||||
rc = ap->ops->port_suspend(ap, ap->pm_mesg);
|
||||
|
||||
/* report result */
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
ap->pflags &= ~ATA_PFLAG_PM_PENDING;
|
||||
if (rc == 0)
|
||||
ap->pflags |= ATA_PFLAG_SUSPENDED;
|
||||
else
|
||||
ata_port_schedule_eh(ap);
|
||||
|
||||
if (ap->pm_result) {
|
||||
*ap->pm_result = rc;
|
||||
ap->pm_result = NULL;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_eh_handle_port_resume - perform port resume operation
|
||||
* @ap: port to resume
|
||||
*
|
||||
* Resume @ap.
|
||||
*
|
||||
* This function also waits upto one second until all devices
|
||||
* hanging off this port requests resume EH action. This is to
|
||||
* prevent invoking EH and thus reset multiple times on resume.
|
||||
*
|
||||
* On DPM resume, where some of devices might not be resumed
|
||||
* together, this may delay port resume upto one second, but such
|
||||
* DPM resumes are rare and 1 sec delay isn't too bad.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep).
|
||||
*/
|
||||
static void ata_eh_handle_port_resume(struct ata_port *ap)
|
||||
{
|
||||
unsigned long timeout;
|
||||
unsigned long flags;
|
||||
int i, rc = 0;
|
||||
|
||||
/* are we resuming? */
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
|
||||
ap->pm_mesg.event != PM_EVENT_ON) {
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
return;
|
||||
}
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
/* spurious? */
|
||||
if (!(ap->pflags & ATA_PFLAG_SUSPENDED))
|
||||
goto done;
|
||||
|
||||
if (ap->ops->port_resume)
|
||||
rc = ap->ops->port_resume(ap);
|
||||
|
||||
/* give devices time to request EH */
|
||||
timeout = jiffies + HZ; /* 1s max */
|
||||
while (1) {
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++) {
|
||||
struct ata_device *dev = &ap->device[i];
|
||||
unsigned int action = ata_eh_dev_action(dev);
|
||||
|
||||
if ((dev->flags & ATA_DFLAG_SUSPENDED) &&
|
||||
!(action & ATA_EH_RESUME))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ATA_MAX_DEVICES || time_after(jiffies, timeout))
|
||||
break;
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
done:
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
|
||||
if (ap->pm_result) {
|
||||
*ap->pm_result = rc;
|
||||
ap->pm_result = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
}
|
||||
|
@ -397,20 +397,129 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf)
|
||||
}
|
||||
}
|
||||
|
||||
int ata_scsi_device_resume(struct scsi_device *sdev)
|
||||
{
|
||||
struct ata_port *ap = ata_shost_to_port(sdev->host);
|
||||
struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
|
||||
|
||||
return ata_device_resume(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_scsi_device_suspend - suspend ATA device associated with sdev
|
||||
* @sdev: the SCSI device to suspend
|
||||
* @state: target power management state
|
||||
*
|
||||
* Request suspend EH action on the ATA device associated with
|
||||
* @sdev and wait for the operation to complete.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep).
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, -errno otherwise.
|
||||
*/
|
||||
int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
|
||||
{
|
||||
struct ata_port *ap = ata_shost_to_port(sdev->host);
|
||||
struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
|
||||
struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
|
||||
unsigned long flags;
|
||||
unsigned int action;
|
||||
int rc = 0;
|
||||
|
||||
return ata_device_suspend(dev, state);
|
||||
if (!dev)
|
||||
goto out;
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
/* wait for the previous resume to complete */
|
||||
while (dev->flags & ATA_DFLAG_SUSPENDED) {
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
ata_port_wait_eh(ap);
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
}
|
||||
|
||||
/* if @sdev is already detached, nothing to do */
|
||||
if (sdev->sdev_state == SDEV_OFFLINE ||
|
||||
sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
|
||||
goto out_unlock;
|
||||
|
||||
/* request suspend */
|
||||
action = ATA_EH_SUSPEND;
|
||||
if (state.event != PM_EVENT_SUSPEND)
|
||||
action |= ATA_EH_PM_FREEZE;
|
||||
ap->eh_info.dev_action[dev->devno] |= action;
|
||||
ap->eh_info.flags |= ATA_EHI_QUIET;
|
||||
ata_port_schedule_eh(ap);
|
||||
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
/* wait for EH to do the job */
|
||||
ata_port_wait_eh(ap);
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
/* If @sdev is still attached but the associated ATA device
|
||||
* isn't suspended, the operation failed.
|
||||
*/
|
||||
if (sdev->sdev_state != SDEV_OFFLINE &&
|
||||
sdev->sdev_state != SDEV_CANCEL && sdev->sdev_state != SDEV_DEL &&
|
||||
!(dev->flags & ATA_DFLAG_SUSPENDED))
|
||||
rc = -EIO;
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
out:
|
||||
if (rc == 0)
|
||||
sdev->sdev_gendev.power.power_state = state;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_scsi_device_resume - resume ATA device associated with sdev
|
||||
* @sdev: the SCSI device to resume
|
||||
*
|
||||
* Request resume EH action on the ATA device associated with
|
||||
* @sdev and return immediately. This enables parallel
|
||||
* wakeup/spinup of devices.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep).
|
||||
*
|
||||
* RETURNS:
|
||||
* 0.
|
||||
*/
|
||||
int ata_scsi_device_resume(struct scsi_device *sdev)
|
||||
{
|
||||
struct ata_port *ap = ata_shost_to_port(sdev->host);
|
||||
struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
|
||||
struct ata_eh_info *ehi = &ap->eh_info;
|
||||
unsigned long flags;
|
||||
unsigned int action;
|
||||
|
||||
if (!dev)
|
||||
goto out;
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
|
||||
/* if @sdev is already detached, nothing to do */
|
||||
if (sdev->sdev_state == SDEV_OFFLINE ||
|
||||
sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
|
||||
goto out_unlock;
|
||||
|
||||
/* request resume */
|
||||
action = ATA_EH_RESUME;
|
||||
if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND)
|
||||
__ata_ehi_hotplugged(ehi);
|
||||
else
|
||||
action |= ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET;
|
||||
ehi->dev_action[dev->devno] |= action;
|
||||
|
||||
/* We don't want autopsy and verbose EH messages. Disable
|
||||
* those if we're the only device on this link.
|
||||
*/
|
||||
if (ata_port_max_devices(ap) == 1)
|
||||
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
|
||||
|
||||
ata_port_schedule_eh(ap);
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
out:
|
||||
sdev->sdev_gendev.power.power_state = PMSG_ON;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2930,7 +3039,7 @@ void ata_scsi_hotplug(void *data)
|
||||
struct ata_port *ap = data;
|
||||
int i;
|
||||
|
||||
if (ap->flags & ATA_FLAG_UNLOADING) {
|
||||
if (ap->pflags & ATA_PFLAG_UNLOADING) {
|
||||
DPRINTK("ENTER/EXIT - unloading\n");
|
||||
return;
|
||||
}
|
||||
@ -3011,6 +3120,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
|
||||
if (dev) {
|
||||
ap->eh_info.probe_mask |= 1 << dev->devno;
|
||||
ap->eh_info.action |= ATA_EH_SOFTRESET;
|
||||
ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
|
||||
} else
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
@ -109,6 +109,7 @@ enum {
|
||||
};
|
||||
|
||||
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
|
||||
static int sil_pci_device_resume(struct pci_dev *pdev);
|
||||
static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
|
||||
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
|
||||
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
|
||||
@ -160,6 +161,8 @@ static struct pci_driver sil_pci_driver = {
|
||||
.id_table = sil_pci_tbl,
|
||||
.probe = sil_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = sil_pci_device_resume,
|
||||
};
|
||||
|
||||
static struct scsi_host_template sil_sht = {
|
||||
@ -178,6 +181,8 @@ static struct scsi_host_template sil_sht = {
|
||||
.slave_configure = ata_scsi_slave_config,
|
||||
.slave_destroy = ata_scsi_slave_destroy,
|
||||
.bios_param = ata_std_bios_param,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
.resume = ata_scsi_device_resume,
|
||||
};
|
||||
|
||||
static const struct ata_port_operations sil_ops = {
|
||||
@ -370,7 +375,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
|
||||
* during hardreset makes controllers with broken SIEN
|
||||
* repeat probing needlessly.
|
||||
*/
|
||||
if (!(ap->flags & ATA_FLAG_FROZEN)) {
|
||||
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
|
||||
ata_ehi_hotplugged(&ap->eh_info);
|
||||
ap->eh_info.serror |= serror;
|
||||
}
|
||||
@ -561,6 +566,52 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void sil_init_controller(struct pci_dev *pdev,
|
||||
int n_ports, unsigned long host_flags,
|
||||
void __iomem *mmio_base)
|
||||
{
|
||||
u8 cls;
|
||||
u32 tmp;
|
||||
int i;
|
||||
|
||||
/* Initialize FIFO PCI bus arbitration */
|
||||
cls = sil_get_device_cache_line(pdev);
|
||||
if (cls) {
|
||||
cls >>= 3;
|
||||
cls++; /* cls = (line_size/8)+1 */
|
||||
for (i = 0; i < n_ports; i++)
|
||||
writew(cls << 8 | cls,
|
||||
mmio_base + sil_port[i].fifo_cfg);
|
||||
} else
|
||||
dev_printk(KERN_WARNING, &pdev->dev,
|
||||
"cache line size not set. Driver may not function\n");
|
||||
|
||||
/* Apply R_ERR on DMA activate FIS errata workaround */
|
||||
if (host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
|
||||
int cnt;
|
||||
|
||||
for (i = 0, cnt = 0; i < n_ports; i++) {
|
||||
tmp = readl(mmio_base + sil_port[i].sfis_cfg);
|
||||
if ((tmp & 0x3) != 0x01)
|
||||
continue;
|
||||
if (!cnt)
|
||||
dev_printk(KERN_INFO, &pdev->dev,
|
||||
"Applying R_ERR on DMA activate "
|
||||
"FIS errata fix\n");
|
||||
writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (n_ports == 4) {
|
||||
/* flip the magic "make 4 ports work" bit */
|
||||
tmp = readl(mmio_base + sil_port[2].bmdma);
|
||||
if ((tmp & SIL_INTR_STEERING) == 0)
|
||||
writel(tmp | SIL_INTR_STEERING,
|
||||
mmio_base + sil_port[2].bmdma);
|
||||
}
|
||||
}
|
||||
|
||||
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
static int printed_version;
|
||||
@ -570,8 +621,6 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
int rc;
|
||||
unsigned int i;
|
||||
int pci_dev_busy = 0;
|
||||
u32 tmp;
|
||||
u8 cls;
|
||||
|
||||
if (!printed_version++)
|
||||
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
|
||||
@ -630,42 +679,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
ata_std_ports(&probe_ent->port[i]);
|
||||
}
|
||||
|
||||
/* Initialize FIFO PCI bus arbitration */
|
||||
cls = sil_get_device_cache_line(pdev);
|
||||
if (cls) {
|
||||
cls >>= 3;
|
||||
cls++; /* cls = (line_size/8)+1 */
|
||||
for (i = 0; i < probe_ent->n_ports; i++)
|
||||
writew(cls << 8 | cls,
|
||||
mmio_base + sil_port[i].fifo_cfg);
|
||||
} else
|
||||
dev_printk(KERN_WARNING, &pdev->dev,
|
||||
"cache line size not set. Driver may not function\n");
|
||||
|
||||
/* Apply R_ERR on DMA activate FIS errata workaround */
|
||||
if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
|
||||
int cnt;
|
||||
|
||||
for (i = 0, cnt = 0; i < probe_ent->n_ports; i++) {
|
||||
tmp = readl(mmio_base + sil_port[i].sfis_cfg);
|
||||
if ((tmp & 0x3) != 0x01)
|
||||
continue;
|
||||
if (!cnt)
|
||||
dev_printk(KERN_INFO, &pdev->dev,
|
||||
"Applying R_ERR on DMA activate "
|
||||
"FIS errata fix\n");
|
||||
writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ent->driver_data == sil_3114) {
|
||||
/* flip the magic "make 4 ports work" bit */
|
||||
tmp = readl(mmio_base + sil_port[2].bmdma);
|
||||
if ((tmp & SIL_INTR_STEERING) == 0)
|
||||
writel(tmp | SIL_INTR_STEERING,
|
||||
mmio_base + sil_port[2].bmdma);
|
||||
}
|
||||
sil_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
|
||||
mmio_base);
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
@ -685,6 +700,18 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sil_pci_device_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
ata_pci_device_do_resume(pdev);
|
||||
sil_init_controller(pdev, host_set->n_ports, host_set->ports[0]->flags,
|
||||
host_set->mmio_base);
|
||||
ata_host_set_resume(host_set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init sil_init(void)
|
||||
{
|
||||
return pci_module_init(&sil_pci_driver);
|
||||
|
@ -92,6 +92,7 @@ enum {
|
||||
HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */
|
||||
HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */
|
||||
HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */
|
||||
HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */
|
||||
|
||||
/*
|
||||
* Port registers
|
||||
@ -338,6 +339,7 @@ static int sil24_port_start(struct ata_port *ap);
|
||||
static void sil24_port_stop(struct ata_port *ap);
|
||||
static void sil24_host_stop(struct ata_host_set *host_set);
|
||||
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
|
||||
static int sil24_pci_device_resume(struct pci_dev *pdev);
|
||||
|
||||
static const struct pci_device_id sil24_pci_tbl[] = {
|
||||
{ 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
|
||||
@ -353,6 +355,8 @@ static struct pci_driver sil24_pci_driver = {
|
||||
.id_table = sil24_pci_tbl,
|
||||
.probe = sil24_init_one,
|
||||
.remove = ata_pci_remove_one, /* safe? */
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = sil24_pci_device_resume,
|
||||
};
|
||||
|
||||
static struct scsi_host_template sil24_sht = {
|
||||
@ -372,6 +376,8 @@ static struct scsi_host_template sil24_sht = {
|
||||
.slave_configure = ata_scsi_slave_config,
|
||||
.slave_destroy = ata_scsi_slave_destroy,
|
||||
.bios_param = ata_std_bios_param,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
.resume = ata_scsi_device_resume,
|
||||
};
|
||||
|
||||
static const struct ata_port_operations sil24_ops = {
|
||||
@ -607,7 +613,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
|
||||
/* SStatus oscillates between zero and valid status after
|
||||
* DEV_RST, debounce it.
|
||||
*/
|
||||
rc = sata_phy_debounce(ap, sata_deb_timing_before_fsrst);
|
||||
rc = sata_phy_debounce(ap, sata_deb_timing_long);
|
||||
if (rc) {
|
||||
reason = "PHY debouncing failed";
|
||||
goto err;
|
||||
@ -988,6 +994,64 @@ static void sil24_host_stop(struct ata_host_set *host_set)
|
||||
kfree(hpriv);
|
||||
}
|
||||
|
||||
static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
|
||||
unsigned long host_flags,
|
||||
void __iomem *host_base,
|
||||
void __iomem *port_base)
|
||||
{
|
||||
u32 tmp;
|
||||
int i;
|
||||
|
||||
/* GPIO off */
|
||||
writel(0, host_base + HOST_FLASH_CMD);
|
||||
|
||||
/* clear global reset & mask interrupts during initialization */
|
||||
writel(0, host_base + HOST_CTRL);
|
||||
|
||||
/* init ports */
|
||||
for (i = 0; i < n_ports; i++) {
|
||||
void __iomem *port = port_base + i * PORT_REGS_SIZE;
|
||||
|
||||
/* Initial PHY setting */
|
||||
writel(0x20c, port + PORT_PHY_CFG);
|
||||
|
||||
/* Clear port RST */
|
||||
tmp = readl(port + PORT_CTRL_STAT);
|
||||
if (tmp & PORT_CS_PORT_RST) {
|
||||
writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
|
||||
tmp = ata_wait_register(port + PORT_CTRL_STAT,
|
||||
PORT_CS_PORT_RST,
|
||||
PORT_CS_PORT_RST, 10, 100);
|
||||
if (tmp & PORT_CS_PORT_RST)
|
||||
dev_printk(KERN_ERR, &pdev->dev,
|
||||
"failed to clear port RST\n");
|
||||
}
|
||||
|
||||
/* Configure IRQ WoC */
|
||||
if (host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
|
||||
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
|
||||
else
|
||||
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
|
||||
|
||||
/* Zero error counters. */
|
||||
writel(0x8000, port + PORT_DECODE_ERR_THRESH);
|
||||
writel(0x8000, port + PORT_CRC_ERR_THRESH);
|
||||
writel(0x8000, port + PORT_HSHK_ERR_THRESH);
|
||||
writel(0x0000, port + PORT_DECODE_ERR_CNT);
|
||||
writel(0x0000, port + PORT_CRC_ERR_CNT);
|
||||
writel(0x0000, port + PORT_HSHK_ERR_CNT);
|
||||
|
||||
/* Always use 64bit activation */
|
||||
writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
|
||||
|
||||
/* Clear port multiplier enable and resume bits */
|
||||
writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
|
||||
}
|
||||
|
||||
/* Turn on interrupts */
|
||||
writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
|
||||
}
|
||||
|
||||
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
static int printed_version = 0;
|
||||
@ -1076,9 +1140,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
}
|
||||
}
|
||||
|
||||
/* GPIO off */
|
||||
writel(0, host_base + HOST_FLASH_CMD);
|
||||
|
||||
/* Apply workaround for completion IRQ loss on PCI-X errata */
|
||||
if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
|
||||
tmp = readl(host_base + HOST_CTRL);
|
||||
@ -1090,56 +1151,18 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
|
||||
}
|
||||
|
||||
/* clear global reset & mask interrupts during initialization */
|
||||
writel(0, host_base + HOST_CTRL);
|
||||
|
||||
for (i = 0; i < probe_ent->n_ports; i++) {
|
||||
void __iomem *port = port_base + i * PORT_REGS_SIZE;
|
||||
unsigned long portu = (unsigned long)port;
|
||||
unsigned long portu =
|
||||
(unsigned long)port_base + i * PORT_REGS_SIZE;
|
||||
|
||||
probe_ent->port[i].cmd_addr = portu;
|
||||
probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
|
||||
|
||||
ata_std_ports(&probe_ent->port[i]);
|
||||
|
||||
/* Initial PHY setting */
|
||||
writel(0x20c, port + PORT_PHY_CFG);
|
||||
|
||||
/* Clear port RST */
|
||||
tmp = readl(port + PORT_CTRL_STAT);
|
||||
if (tmp & PORT_CS_PORT_RST) {
|
||||
writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
|
||||
tmp = ata_wait_register(port + PORT_CTRL_STAT,
|
||||
PORT_CS_PORT_RST,
|
||||
PORT_CS_PORT_RST, 10, 100);
|
||||
if (tmp & PORT_CS_PORT_RST)
|
||||
dev_printk(KERN_ERR, &pdev->dev,
|
||||
"failed to clear port RST\n");
|
||||
}
|
||||
|
||||
/* Configure IRQ WoC */
|
||||
if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
|
||||
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
|
||||
else
|
||||
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
|
||||
|
||||
/* Zero error counters. */
|
||||
writel(0x8000, port + PORT_DECODE_ERR_THRESH);
|
||||
writel(0x8000, port + PORT_CRC_ERR_THRESH);
|
||||
writel(0x8000, port + PORT_HSHK_ERR_THRESH);
|
||||
writel(0x0000, port + PORT_DECODE_ERR_CNT);
|
||||
writel(0x0000, port + PORT_CRC_ERR_CNT);
|
||||
writel(0x0000, port + PORT_HSHK_ERR_CNT);
|
||||
|
||||
/* Always use 64bit activation */
|
||||
writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
|
||||
|
||||
/* Clear port multiplier enable and resume bits */
|
||||
writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
|
||||
}
|
||||
|
||||
/* Turn on interrupts */
|
||||
writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
|
||||
sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
|
||||
host_base, port_base);
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
@ -1162,6 +1185,25 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sil24_pci_device_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
|
||||
struct sil24_host_priv *hpriv = host_set->private_data;
|
||||
|
||||
ata_pci_device_do_resume(pdev);
|
||||
|
||||
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
|
||||
writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
|
||||
|
||||
sil24_init_controller(pdev, host_set->n_ports,
|
||||
host_set->ports[0]->flags,
|
||||
hpriv->host_base, hpriv->port_base);
|
||||
|
||||
ata_host_set_resume(host_set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init sil24_init(void)
|
||||
{
|
||||
return pci_module_init(&sil24_pci_driver);
|
||||
|
@ -297,7 +297,7 @@ static const struct ata_port_operations vsc_sata_ops = {
|
||||
.bmdma_status = ata_bmdma_status,
|
||||
.qc_prep = ata_qc_prep,
|
||||
.qc_issue = ata_qc_issue_prot,
|
||||
.data_xfer = ata_pio_data_xfer,
|
||||
.data_xfer = ata_mmio_data_xfer,
|
||||
.freeze = ata_bmdma_freeze,
|
||||
.thaw = ata_bmdma_thaw,
|
||||
.error_handler = ata_bmdma_error_handler,
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <asm/mach/serial_at91.h>
|
||||
#include <asm/arch/board.h>
|
||||
#include <asm/arch/system.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
|
||||
#if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#define SUPPORT_SYSRQ
|
||||
@ -140,9 +141,9 @@ static void at91_set_mctrl(struct uart_port *port, u_int mctrl)
|
||||
*/
|
||||
if (port->mapbase == AT91_BASE_US0) {
|
||||
if (mctrl & TIOCM_RTS)
|
||||
at91_sys_write(AT91_PIOA + PIO_CODR, AT91_PA21_RTS0);
|
||||
at91_set_gpio_value(AT91_PIN_PA21, 0);
|
||||
else
|
||||
at91_sys_write(AT91_PIOA + PIO_SODR, AT91_PA21_RTS0);
|
||||
at91_set_gpio_value(AT91_PIN_PA21, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,7 +454,7 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho
|
||||
fl->fl_ops = &nlmclnt_lock_ops;
|
||||
}
|
||||
|
||||
static void do_vfs_lock(struct file_lock *fl)
|
||||
static int do_vfs_lock(struct file_lock *fl)
|
||||
{
|
||||
int res = 0;
|
||||
switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
|
||||
@ -467,9 +467,7 @@ static void do_vfs_lock(struct file_lock *fl)
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
if (res < 0)
|
||||
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
|
||||
__FUNCTION__);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -498,6 +496,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
|
||||
struct nlm_host *host = req->a_host;
|
||||
struct nlm_res *resp = &req->a_res;
|
||||
struct nlm_wait *block = NULL;
|
||||
unsigned char fl_flags = fl->fl_flags;
|
||||
int status = -ENOLCK;
|
||||
|
||||
if (!host->h_monitored && nsm_monitor(host) < 0) {
|
||||
@ -505,6 +504,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
|
||||
host->h_name);
|
||||
goto out;
|
||||
}
|
||||
fl->fl_flags |= FL_ACCESS;
|
||||
status = do_vfs_lock(fl);
|
||||
if (status < 0)
|
||||
goto out;
|
||||
|
||||
block = nlmclnt_prepare_block(host, fl);
|
||||
again:
|
||||
@ -539,9 +542,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
|
||||
up_read(&host->h_rwsem);
|
||||
goto again;
|
||||
}
|
||||
fl->fl_flags |= FL_SLEEP;
|
||||
/* Ensure the resulting lock will get added to granted list */
|
||||
do_vfs_lock(fl);
|
||||
fl->fl_flags = fl_flags | FL_SLEEP;
|
||||
if (do_vfs_lock(fl) < 0)
|
||||
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
|
||||
up_read(&host->h_rwsem);
|
||||
}
|
||||
status = nlm_stat_to_errno(resp->status);
|
||||
@ -552,6 +556,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
|
||||
nlmclnt_cancel(host, req->a_args.block, fl);
|
||||
out:
|
||||
nlm_release_call(req);
|
||||
fl->fl_flags = fl_flags;
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -606,15 +611,19 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
|
||||
{
|
||||
struct nlm_host *host = req->a_host;
|
||||
struct nlm_res *resp = &req->a_res;
|
||||
int status;
|
||||
int status = 0;
|
||||
|
||||
/*
|
||||
* Note: the server is supposed to either grant us the unlock
|
||||
* request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
|
||||
* case, we want to unlock.
|
||||
*/
|
||||
fl->fl_flags |= FL_EXISTS;
|
||||
down_read(&host->h_rwsem);
|
||||
do_vfs_lock(fl);
|
||||
if (do_vfs_lock(fl) == -ENOENT) {
|
||||
up_read(&host->h_rwsem);
|
||||
goto out;
|
||||
}
|
||||
up_read(&host->h_rwsem);
|
||||
|
||||
if (req->a_flags & RPC_TASK_ASYNC)
|
||||
@ -624,7 +633,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
|
||||
if (status < 0)
|
||||
goto out;
|
||||
|
||||
status = 0;
|
||||
if (resp->status == NLM_LCK_GRANTED)
|
||||
goto out;
|
||||
|
||||
|
23
fs/locks.c
23
fs/locks.c
@ -725,6 +725,10 @@ static int posix_locks_deadlock(struct file_lock *caller_fl,
|
||||
/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
|
||||
* at the head of the list, but that's secret knowledge known only to
|
||||
* flock_lock_file and posix_lock_file.
|
||||
*
|
||||
* Note that if called with an FL_EXISTS argument, the caller may determine
|
||||
* whether or not a lock was successfully freed by testing the return
|
||||
* value for -ENOENT.
|
||||
*/
|
||||
static int flock_lock_file(struct file *filp, struct file_lock *request)
|
||||
{
|
||||
@ -735,6 +739,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
|
||||
int found = 0;
|
||||
|
||||
lock_kernel();
|
||||
if (request->fl_flags & FL_ACCESS)
|
||||
goto find_conflict;
|
||||
for_each_lock(inode, before) {
|
||||
struct file_lock *fl = *before;
|
||||
if (IS_POSIX(fl))
|
||||
@ -750,8 +756,11 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
|
||||
break;
|
||||
}
|
||||
|
||||
if (request->fl_type == F_UNLCK)
|
||||
if (request->fl_type == F_UNLCK) {
|
||||
if ((request->fl_flags & FL_EXISTS) && !found)
|
||||
error = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = -ENOMEM;
|
||||
new_fl = locks_alloc_lock();
|
||||
@ -764,6 +773,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
|
||||
if (found)
|
||||
cond_resched();
|
||||
|
||||
find_conflict:
|
||||
for_each_lock(inode, before) {
|
||||
struct file_lock *fl = *before;
|
||||
if (IS_POSIX(fl))
|
||||
@ -777,6 +787,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
|
||||
locks_insert_block(fl, request);
|
||||
goto out;
|
||||
}
|
||||
if (request->fl_flags & FL_ACCESS)
|
||||
goto out;
|
||||
locks_copy_lock(new_fl, request);
|
||||
locks_insert_lock(&inode->i_flock, new_fl);
|
||||
new_fl = NULL;
|
||||
@ -948,8 +960,11 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
|
||||
|
||||
error = 0;
|
||||
if (!added) {
|
||||
if (request->fl_type == F_UNLCK)
|
||||
if (request->fl_type == F_UNLCK) {
|
||||
if (request->fl_flags & FL_EXISTS)
|
||||
error = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!new_fl) {
|
||||
error = -ENOLCK;
|
||||
@ -996,6 +1011,10 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
|
||||
* Add a POSIX style lock to a file.
|
||||
* We merge adjacent & overlapping locks whenever possible.
|
||||
* POSIX locks are sorted by owner task, then by starting address
|
||||
*
|
||||
* Note that if called with an FL_EXISTS argument, the caller may determine
|
||||
* whether or not a lock was successfully freed by testing the return
|
||||
* value for -ENOENT.
|
||||
*/
|
||||
int posix_lock_file(struct file *filp, struct file_lock *fl)
|
||||
{
|
||||
|
@ -690,7 +690,9 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
|
||||
goto out_force;
|
||||
/* This is an open(2) */
|
||||
if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 &&
|
||||
!(server->flags & NFS_MOUNT_NOCTO))
|
||||
!(server->flags & NFS_MOUNT_NOCTO) &&
|
||||
(S_ISREG(inode->i_mode) ||
|
||||
S_ISDIR(inode->i_mode)))
|
||||
goto out_force;
|
||||
}
|
||||
return nfs_revalidate_inode(server, inode);
|
||||
|
435
fs/nfs/direct.c
435
fs/nfs/direct.c
@ -67,25 +67,19 @@ struct nfs_direct_req {
|
||||
struct kref kref; /* release manager */
|
||||
|
||||
/* I/O parameters */
|
||||
struct list_head list, /* nfs_read/write_data structs */
|
||||
rewrite_list; /* saved nfs_write_data structs */
|
||||
struct nfs_open_context *ctx; /* file open context info */
|
||||
struct kiocb * iocb; /* controlling i/o request */
|
||||
struct inode * inode; /* target file of i/o */
|
||||
unsigned long user_addr; /* location of user's buffer */
|
||||
size_t user_count; /* total bytes to move */
|
||||
loff_t pos; /* starting offset in file */
|
||||
struct page ** pages; /* pages in our buffer */
|
||||
unsigned int npages; /* count of pages */
|
||||
|
||||
/* completion state */
|
||||
atomic_t io_count; /* i/os we're waiting for */
|
||||
spinlock_t lock; /* protect completion state */
|
||||
int outstanding; /* i/os we're waiting for */
|
||||
ssize_t count, /* bytes actually processed */
|
||||
error; /* any reported error */
|
||||
struct completion completion; /* wait for i/o completion */
|
||||
|
||||
/* commit state */
|
||||
struct list_head rewrite_list; /* saved nfs_write_data structs */
|
||||
struct nfs_write_data * commit_data; /* special write_data for commits */
|
||||
int flags;
|
||||
#define NFS_ODIRECT_DO_COMMIT (1) /* an unstable reply was received */
|
||||
@ -93,8 +87,37 @@ struct nfs_direct_req {
|
||||
struct nfs_writeverf verf; /* unstable write verifier */
|
||||
};
|
||||
|
||||
static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync);
|
||||
static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode);
|
||||
static const struct rpc_call_ops nfs_write_direct_ops;
|
||||
|
||||
static inline void get_dreq(struct nfs_direct_req *dreq)
|
||||
{
|
||||
atomic_inc(&dreq->io_count);
|
||||
}
|
||||
|
||||
static inline int put_dreq(struct nfs_direct_req *dreq)
|
||||
{
|
||||
return atomic_dec_and_test(&dreq->io_count);
|
||||
}
|
||||
|
||||
/*
|
||||
* "size" is never larger than rsize or wsize.
|
||||
*/
|
||||
static inline int nfs_direct_count_pages(unsigned long user_addr, size_t size)
|
||||
{
|
||||
int page_count;
|
||||
|
||||
page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
page_count -= user_addr >> PAGE_SHIFT;
|
||||
BUG_ON(page_count < 0);
|
||||
|
||||
return page_count;
|
||||
}
|
||||
|
||||
static inline unsigned int nfs_max_pages(unsigned int size)
|
||||
{
|
||||
return (size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_direct_IO - NFS address space operation for direct I/O
|
||||
@ -118,50 +141,21 @@ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty)
|
||||
static void nfs_direct_dirty_pages(struct page **pages, int npages)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < npages; i++) {
|
||||
struct page *page = pages[i];
|
||||
if (do_dirty && !PageCompound(page))
|
||||
if (!PageCompound(page))
|
||||
set_page_dirty_lock(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
kfree(pages);
|
||||
}
|
||||
|
||||
static inline int nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, struct page ***pages)
|
||||
static void nfs_direct_release_pages(struct page **pages, int npages)
|
||||
{
|
||||
int result = -ENOMEM;
|
||||
unsigned long page_count;
|
||||
size_t array_size;
|
||||
|
||||
page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
page_count -= user_addr >> PAGE_SHIFT;
|
||||
|
||||
array_size = (page_count * sizeof(struct page *));
|
||||
*pages = kmalloc(array_size, GFP_KERNEL);
|
||||
if (*pages) {
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
result = get_user_pages(current, current->mm, user_addr,
|
||||
page_count, (rw == READ), 0,
|
||||
*pages, NULL);
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
if (result != page_count) {
|
||||
/*
|
||||
* If we got fewer pages than expected from
|
||||
* get_user_pages(), the user buffer runs off the
|
||||
* end of a mapping; return EFAULT.
|
||||
*/
|
||||
if (result >= 0) {
|
||||
nfs_free_user_pages(*pages, result, 0);
|
||||
result = -EFAULT;
|
||||
} else
|
||||
kfree(*pages);
|
||||
*pages = NULL;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
int i;
|
||||
for (i = 0; i < npages; i++)
|
||||
page_cache_release(pages[i]);
|
||||
}
|
||||
|
||||
static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
|
||||
@ -173,13 +167,13 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
|
||||
return NULL;
|
||||
|
||||
kref_init(&dreq->kref);
|
||||
kref_get(&dreq->kref);
|
||||
init_completion(&dreq->completion);
|
||||
INIT_LIST_HEAD(&dreq->list);
|
||||
INIT_LIST_HEAD(&dreq->rewrite_list);
|
||||
dreq->iocb = NULL;
|
||||
dreq->ctx = NULL;
|
||||
spin_lock_init(&dreq->lock);
|
||||
dreq->outstanding = 0;
|
||||
atomic_set(&dreq->io_count, 0);
|
||||
dreq->count = 0;
|
||||
dreq->error = 0;
|
||||
dreq->flags = 0;
|
||||
@ -220,18 +214,11 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq)
|
||||
}
|
||||
|
||||
/*
|
||||
* We must hold a reference to all the pages in this direct read request
|
||||
* until the RPCs complete. This could be long *after* we are woken up in
|
||||
* nfs_direct_wait (for instance, if someone hits ^C on a slow server).
|
||||
*
|
||||
* In addition, synchronous I/O uses a stack-allocated iocb. Thus we
|
||||
* can't trust the iocb is still valid here if this is a synchronous
|
||||
* request. If the waiter is woken prematurely, the iocb is long gone.
|
||||
* Synchronous I/O uses a stack-allocated iocb. Thus we can't trust
|
||||
* the iocb is still valid here if this is a synchronous request.
|
||||
*/
|
||||
static void nfs_direct_complete(struct nfs_direct_req *dreq)
|
||||
{
|
||||
nfs_free_user_pages(dreq->pages, dreq->npages, 1);
|
||||
|
||||
if (dreq->iocb) {
|
||||
long res = (long) dreq->error;
|
||||
if (!res)
|
||||
@ -244,48 +231,10 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
|
||||
}
|
||||
|
||||
/*
|
||||
* Note we also set the number of requests we have in the dreq when we are
|
||||
* done. This prevents races with I/O completion so we will always wait
|
||||
* until all requests have been dispatched and completed.
|
||||
* We must hold a reference to all the pages in this direct read request
|
||||
* until the RPCs complete. This could be long *after* we are woken up in
|
||||
* nfs_direct_wait (for instance, if someone hits ^C on a slow server).
|
||||
*/
|
||||
static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, size_t rsize)
|
||||
{
|
||||
struct list_head *list;
|
||||
struct nfs_direct_req *dreq;
|
||||
unsigned int rpages = (rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
||||
|
||||
dreq = nfs_direct_req_alloc();
|
||||
if (!dreq)
|
||||
return NULL;
|
||||
|
||||
list = &dreq->list;
|
||||
for(;;) {
|
||||
struct nfs_read_data *data = nfs_readdata_alloc(rpages);
|
||||
|
||||
if (unlikely(!data)) {
|
||||
while (!list_empty(list)) {
|
||||
data = list_entry(list->next,
|
||||
struct nfs_read_data, pages);
|
||||
list_del(&data->pages);
|
||||
nfs_readdata_free(data);
|
||||
}
|
||||
kref_put(&dreq->kref, nfs_direct_req_release);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&data->pages);
|
||||
list_add(&data->pages, list);
|
||||
|
||||
data->req = (struct nfs_page *) dreq;
|
||||
dreq->outstanding++;
|
||||
if (nbytes <= rsize)
|
||||
break;
|
||||
nbytes -= rsize;
|
||||
}
|
||||
kref_get(&dreq->kref);
|
||||
return dreq;
|
||||
}
|
||||
|
||||
static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_read_data *data = calldata;
|
||||
@ -294,6 +243,9 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
|
||||
if (nfs_readpage_result(task, data) != 0)
|
||||
return;
|
||||
|
||||
nfs_direct_dirty_pages(data->pagevec, data->npages);
|
||||
nfs_direct_release_pages(data->pagevec, data->npages);
|
||||
|
||||
spin_lock(&dreq->lock);
|
||||
|
||||
if (likely(task->tk_status >= 0))
|
||||
@ -301,13 +253,10 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
|
||||
else
|
||||
dreq->error = task->tk_status;
|
||||
|
||||
if (--dreq->outstanding) {
|
||||
spin_unlock(&dreq->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_unlock(&dreq->lock);
|
||||
nfs_direct_complete(dreq);
|
||||
|
||||
if (put_dreq(dreq))
|
||||
nfs_direct_complete(dreq);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs_read_direct_ops = {
|
||||
@ -316,41 +265,60 @@ static const struct rpc_call_ops nfs_read_direct_ops = {
|
||||
};
|
||||
|
||||
/*
|
||||
* For each nfs_read_data struct that was allocated on the list, dispatch
|
||||
* an NFS READ operation
|
||||
* For each rsize'd chunk of the user's buffer, dispatch an NFS READ
|
||||
* operation. If nfs_readdata_alloc() or get_user_pages() fails,
|
||||
* bail and stop sending more reads. Read length accounting is
|
||||
* handled automatically by nfs_direct_read_result(). Otherwise, if
|
||||
* no requests have been sent, just return an error.
|
||||
*/
|
||||
static void nfs_direct_read_schedule(struct nfs_direct_req *dreq)
|
||||
static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos)
|
||||
{
|
||||
struct nfs_open_context *ctx = dreq->ctx;
|
||||
struct inode *inode = ctx->dentry->d_inode;
|
||||
struct list_head *list = &dreq->list;
|
||||
struct page **pages = dreq->pages;
|
||||
size_t count = dreq->user_count;
|
||||
loff_t pos = dreq->pos;
|
||||
size_t rsize = NFS_SERVER(inode)->rsize;
|
||||
unsigned int curpage, pgbase;
|
||||
unsigned int rpages = nfs_max_pages(rsize);
|
||||
unsigned int pgbase;
|
||||
int result;
|
||||
ssize_t started = 0;
|
||||
|
||||
curpage = 0;
|
||||
pgbase = dreq->user_addr & ~PAGE_MASK;
|
||||
get_dreq(dreq);
|
||||
|
||||
pgbase = user_addr & ~PAGE_MASK;
|
||||
do {
|
||||
struct nfs_read_data *data;
|
||||
size_t bytes;
|
||||
|
||||
result = -ENOMEM;
|
||||
data = nfs_readdata_alloc(rpages);
|
||||
if (unlikely(!data))
|
||||
break;
|
||||
|
||||
bytes = rsize;
|
||||
if (count < rsize)
|
||||
bytes = count;
|
||||
|
||||
BUG_ON(list_empty(list));
|
||||
data = list_entry(list->next, struct nfs_read_data, pages);
|
||||
list_del_init(&data->pages);
|
||||
data->npages = nfs_direct_count_pages(user_addr, bytes);
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
result = get_user_pages(current, current->mm, user_addr,
|
||||
data->npages, 1, 0, data->pagevec, NULL);
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
if (unlikely(result < data->npages)) {
|
||||
if (result > 0)
|
||||
nfs_direct_release_pages(data->pagevec, result);
|
||||
nfs_readdata_release(data);
|
||||
break;
|
||||
}
|
||||
|
||||
get_dreq(dreq);
|
||||
|
||||
data->req = (struct nfs_page *) dreq;
|
||||
data->inode = inode;
|
||||
data->cred = ctx->cred;
|
||||
data->args.fh = NFS_FH(inode);
|
||||
data->args.context = ctx;
|
||||
data->args.offset = pos;
|
||||
data->args.pgbase = pgbase;
|
||||
data->args.pages = &pages[curpage];
|
||||
data->args.pages = data->pagevec;
|
||||
data->args.count = bytes;
|
||||
data->res.fattr = &data->fattr;
|
||||
data->res.eof = 0;
|
||||
@ -373,33 +341,35 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq)
|
||||
bytes,
|
||||
(unsigned long long)data->args.offset);
|
||||
|
||||
started += bytes;
|
||||
user_addr += bytes;
|
||||
pos += bytes;
|
||||
pgbase += bytes;
|
||||
curpage += pgbase >> PAGE_SHIFT;
|
||||
pgbase &= ~PAGE_MASK;
|
||||
|
||||
count -= bytes;
|
||||
} while (count != 0);
|
||||
BUG_ON(!list_empty(list));
|
||||
|
||||
if (put_dreq(dreq))
|
||||
nfs_direct_complete(dreq);
|
||||
|
||||
if (started)
|
||||
return 0;
|
||||
return result < 0 ? (ssize_t) result : -EFAULT;
|
||||
}
|
||||
|
||||
static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos, struct page **pages, unsigned int nr_pages)
|
||||
static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
|
||||
{
|
||||
ssize_t result;
|
||||
ssize_t result = 0;
|
||||
sigset_t oldset;
|
||||
struct inode *inode = iocb->ki_filp->f_mapping->host;
|
||||
struct rpc_clnt *clnt = NFS_CLIENT(inode);
|
||||
struct nfs_direct_req *dreq;
|
||||
|
||||
dreq = nfs_direct_read_alloc(count, NFS_SERVER(inode)->rsize);
|
||||
dreq = nfs_direct_req_alloc();
|
||||
if (!dreq)
|
||||
return -ENOMEM;
|
||||
|
||||
dreq->user_addr = user_addr;
|
||||
dreq->user_count = count;
|
||||
dreq->pos = pos;
|
||||
dreq->pages = pages;
|
||||
dreq->npages = nr_pages;
|
||||
dreq->inode = inode;
|
||||
dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
|
||||
if (!is_sync_kiocb(iocb))
|
||||
@ -407,8 +377,9 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
|
||||
|
||||
nfs_add_stats(inode, NFSIOS_DIRECTREADBYTES, count);
|
||||
rpc_clnt_sigmask(clnt, &oldset);
|
||||
nfs_direct_read_schedule(dreq);
|
||||
result = nfs_direct_wait(dreq);
|
||||
result = nfs_direct_read_schedule(dreq, user_addr, count, pos);
|
||||
if (!result)
|
||||
result = nfs_direct_wait(dreq);
|
||||
rpc_clnt_sigunmask(clnt, &oldset);
|
||||
|
||||
return result;
|
||||
@ -416,10 +387,10 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
|
||||
|
||||
static void nfs_direct_free_writedata(struct nfs_direct_req *dreq)
|
||||
{
|
||||
list_splice_init(&dreq->rewrite_list, &dreq->list);
|
||||
while (!list_empty(&dreq->list)) {
|
||||
struct nfs_write_data *data = list_entry(dreq->list.next, struct nfs_write_data, pages);
|
||||
while (!list_empty(&dreq->rewrite_list)) {
|
||||
struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages);
|
||||
list_del(&data->pages);
|
||||
nfs_direct_release_pages(data->pagevec, data->npages);
|
||||
nfs_writedata_release(data);
|
||||
}
|
||||
}
|
||||
@ -427,14 +398,51 @@ static void nfs_direct_free_writedata(struct nfs_direct_req *dreq)
|
||||
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
|
||||
static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
|
||||
{
|
||||
struct list_head *pos;
|
||||
struct inode *inode = dreq->inode;
|
||||
struct list_head *p;
|
||||
struct nfs_write_data *data;
|
||||
|
||||
list_splice_init(&dreq->rewrite_list, &dreq->list);
|
||||
list_for_each(pos, &dreq->list)
|
||||
dreq->outstanding++;
|
||||
dreq->count = 0;
|
||||
get_dreq(dreq);
|
||||
|
||||
nfs_direct_write_schedule(dreq, FLUSH_STABLE);
|
||||
list_for_each(p, &dreq->rewrite_list) {
|
||||
data = list_entry(p, struct nfs_write_data, pages);
|
||||
|
||||
get_dreq(dreq);
|
||||
|
||||
/*
|
||||
* Reset data->res.
|
||||
*/
|
||||
nfs_fattr_init(&data->fattr);
|
||||
data->res.count = data->args.count;
|
||||
memset(&data->verf, 0, sizeof(data->verf));
|
||||
|
||||
/*
|
||||
* Reuse data->task; data->args should not have changed
|
||||
* since the original request was sent.
|
||||
*/
|
||||
rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC,
|
||||
&nfs_write_direct_ops, data);
|
||||
NFS_PROTO(inode)->write_setup(data, FLUSH_STABLE);
|
||||
|
||||
data->task.tk_priority = RPC_PRIORITY_NORMAL;
|
||||
data->task.tk_cookie = (unsigned long) inode;
|
||||
|
||||
/*
|
||||
* We're called via an RPC callback, so BKL is already held.
|
||||
*/
|
||||
rpc_execute(&data->task);
|
||||
|
||||
dprintk("NFS: %5u rescheduled direct write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
|
||||
data->task.tk_pid,
|
||||
inode->i_sb->s_id,
|
||||
(long long)NFS_FILEID(inode),
|
||||
data->args.count,
|
||||
(unsigned long long)data->args.offset);
|
||||
}
|
||||
|
||||
if (put_dreq(dreq))
|
||||
nfs_direct_write_complete(dreq, inode);
|
||||
}
|
||||
|
||||
static void nfs_direct_commit_result(struct rpc_task *task, void *calldata)
|
||||
@ -471,8 +479,8 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
|
||||
data->cred = dreq->ctx->cred;
|
||||
|
||||
data->args.fh = NFS_FH(data->inode);
|
||||
data->args.offset = dreq->pos;
|
||||
data->args.count = dreq->user_count;
|
||||
data->args.offset = 0;
|
||||
data->args.count = 0;
|
||||
data->res.count = 0;
|
||||
data->res.fattr = &data->fattr;
|
||||
data->res.verf = &data->verf;
|
||||
@ -534,47 +542,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct nfs_direct_req *nfs_direct_write_alloc(size_t nbytes, size_t wsize)
|
||||
{
|
||||
struct list_head *list;
|
||||
struct nfs_direct_req *dreq;
|
||||
unsigned int wpages = (wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
||||
|
||||
dreq = nfs_direct_req_alloc();
|
||||
if (!dreq)
|
||||
return NULL;
|
||||
|
||||
list = &dreq->list;
|
||||
for(;;) {
|
||||
struct nfs_write_data *data = nfs_writedata_alloc(wpages);
|
||||
|
||||
if (unlikely(!data)) {
|
||||
while (!list_empty(list)) {
|
||||
data = list_entry(list->next,
|
||||
struct nfs_write_data, pages);
|
||||
list_del(&data->pages);
|
||||
nfs_writedata_free(data);
|
||||
}
|
||||
kref_put(&dreq->kref, nfs_direct_req_release);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&data->pages);
|
||||
list_add(&data->pages, list);
|
||||
|
||||
data->req = (struct nfs_page *) dreq;
|
||||
dreq->outstanding++;
|
||||
if (nbytes <= wsize)
|
||||
break;
|
||||
nbytes -= wsize;
|
||||
}
|
||||
|
||||
nfs_alloc_commit_data(dreq);
|
||||
|
||||
kref_get(&dreq->kref);
|
||||
return dreq;
|
||||
}
|
||||
|
||||
static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_write_data *data = calldata;
|
||||
@ -604,8 +571,6 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
|
||||
}
|
||||
}
|
||||
}
|
||||
/* In case we have to resend */
|
||||
data->args.stable = NFS_FILE_SYNC;
|
||||
|
||||
spin_unlock(&dreq->lock);
|
||||
}
|
||||
@ -619,14 +584,8 @@ static void nfs_direct_write_release(void *calldata)
|
||||
struct nfs_write_data *data = calldata;
|
||||
struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req;
|
||||
|
||||
spin_lock(&dreq->lock);
|
||||
if (--dreq->outstanding) {
|
||||
spin_unlock(&dreq->lock);
|
||||
return;
|
||||
}
|
||||
spin_unlock(&dreq->lock);
|
||||
|
||||
nfs_direct_write_complete(dreq, data->inode);
|
||||
if (put_dreq(dreq))
|
||||
nfs_direct_write_complete(dreq, data->inode);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs_write_direct_ops = {
|
||||
@ -635,41 +594,62 @@ static const struct rpc_call_ops nfs_write_direct_ops = {
|
||||
};
|
||||
|
||||
/*
|
||||
* For each nfs_write_data struct that was allocated on the list, dispatch
|
||||
* an NFS WRITE operation
|
||||
* For each wsize'd chunk of the user's buffer, dispatch an NFS WRITE
|
||||
* operation. If nfs_writedata_alloc() or get_user_pages() fails,
|
||||
* bail and stop sending more writes. Write length accounting is
|
||||
* handled automatically by nfs_direct_write_result(). Otherwise, if
|
||||
* no requests have been sent, just return an error.
|
||||
*/
|
||||
static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync)
|
||||
static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync)
|
||||
{
|
||||
struct nfs_open_context *ctx = dreq->ctx;
|
||||
struct inode *inode = ctx->dentry->d_inode;
|
||||
struct list_head *list = &dreq->list;
|
||||
struct page **pages = dreq->pages;
|
||||
size_t count = dreq->user_count;
|
||||
loff_t pos = dreq->pos;
|
||||
size_t wsize = NFS_SERVER(inode)->wsize;
|
||||
unsigned int curpage, pgbase;
|
||||
unsigned int wpages = nfs_max_pages(wsize);
|
||||
unsigned int pgbase;
|
||||
int result;
|
||||
ssize_t started = 0;
|
||||
|
||||
curpage = 0;
|
||||
pgbase = dreq->user_addr & ~PAGE_MASK;
|
||||
get_dreq(dreq);
|
||||
|
||||
pgbase = user_addr & ~PAGE_MASK;
|
||||
do {
|
||||
struct nfs_write_data *data;
|
||||
size_t bytes;
|
||||
|
||||
result = -ENOMEM;
|
||||
data = nfs_writedata_alloc(wpages);
|
||||
if (unlikely(!data))
|
||||
break;
|
||||
|
||||
bytes = wsize;
|
||||
if (count < wsize)
|
||||
bytes = count;
|
||||
|
||||
BUG_ON(list_empty(list));
|
||||
data = list_entry(list->next, struct nfs_write_data, pages);
|
||||
data->npages = nfs_direct_count_pages(user_addr, bytes);
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
result = get_user_pages(current, current->mm, user_addr,
|
||||
data->npages, 0, 0, data->pagevec, NULL);
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
if (unlikely(result < data->npages)) {
|
||||
if (result > 0)
|
||||
nfs_direct_release_pages(data->pagevec, result);
|
||||
nfs_writedata_release(data);
|
||||
break;
|
||||
}
|
||||
|
||||
get_dreq(dreq);
|
||||
|
||||
list_move_tail(&data->pages, &dreq->rewrite_list);
|
||||
|
||||
data->req = (struct nfs_page *) dreq;
|
||||
data->inode = inode;
|
||||
data->cred = ctx->cred;
|
||||
data->args.fh = NFS_FH(inode);
|
||||
data->args.context = ctx;
|
||||
data->args.offset = pos;
|
||||
data->args.pgbase = pgbase;
|
||||
data->args.pages = &pages[curpage];
|
||||
data->args.pages = data->pagevec;
|
||||
data->args.count = bytes;
|
||||
data->res.fattr = &data->fattr;
|
||||
data->res.count = bytes;
|
||||
@ -693,19 +673,26 @@ static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync)
|
||||
bytes,
|
||||
(unsigned long long)data->args.offset);
|
||||
|
||||
started += bytes;
|
||||
user_addr += bytes;
|
||||
pos += bytes;
|
||||
pgbase += bytes;
|
||||
curpage += pgbase >> PAGE_SHIFT;
|
||||
pgbase &= ~PAGE_MASK;
|
||||
|
||||
count -= bytes;
|
||||
} while (count != 0);
|
||||
BUG_ON(!list_empty(list));
|
||||
|
||||
if (put_dreq(dreq))
|
||||
nfs_direct_write_complete(dreq, inode);
|
||||
|
||||
if (started)
|
||||
return 0;
|
||||
return result < 0 ? (ssize_t) result : -EFAULT;
|
||||
}
|
||||
|
||||
static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos, struct page **pages, int nr_pages)
|
||||
static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
|
||||
{
|
||||
ssize_t result;
|
||||
ssize_t result = 0;
|
||||
sigset_t oldset;
|
||||
struct inode *inode = iocb->ki_filp->f_mapping->host;
|
||||
struct rpc_clnt *clnt = NFS_CLIENT(inode);
|
||||
@ -713,17 +700,14 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
|
||||
size_t wsize = NFS_SERVER(inode)->wsize;
|
||||
int sync = 0;
|
||||
|
||||
dreq = nfs_direct_write_alloc(count, wsize);
|
||||
dreq = nfs_direct_req_alloc();
|
||||
if (!dreq)
|
||||
return -ENOMEM;
|
||||
nfs_alloc_commit_data(dreq);
|
||||
|
||||
if (dreq->commit_data == NULL || count < wsize)
|
||||
sync = FLUSH_STABLE;
|
||||
|
||||
dreq->user_addr = user_addr;
|
||||
dreq->user_count = count;
|
||||
dreq->pos = pos;
|
||||
dreq->pages = pages;
|
||||
dreq->npages = nr_pages;
|
||||
dreq->inode = inode;
|
||||
dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
|
||||
if (!is_sync_kiocb(iocb))
|
||||
@ -734,8 +718,9 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
|
||||
nfs_begin_data_update(inode);
|
||||
|
||||
rpc_clnt_sigmask(clnt, &oldset);
|
||||
nfs_direct_write_schedule(dreq, sync);
|
||||
result = nfs_direct_wait(dreq);
|
||||
result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync);
|
||||
if (!result)
|
||||
result = nfs_direct_wait(dreq);
|
||||
rpc_clnt_sigunmask(clnt, &oldset);
|
||||
|
||||
return result;
|
||||
@ -765,8 +750,6 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
|
||||
ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
|
||||
{
|
||||
ssize_t retval = -EINVAL;
|
||||
int page_count;
|
||||
struct page **pages;
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
|
||||
@ -788,14 +771,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count,
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
retval = nfs_get_user_pages(READ, (unsigned long) buf,
|
||||
count, &pages);
|
||||
if (retval < 0)
|
||||
goto out;
|
||||
page_count = retval;
|
||||
|
||||
retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos,
|
||||
pages, page_count);
|
||||
retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos);
|
||||
if (retval > 0)
|
||||
iocb->ki_pos = pos + retval;
|
||||
|
||||
@ -831,8 +807,6 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count,
|
||||
ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
|
||||
{
|
||||
ssize_t retval;
|
||||
int page_count;
|
||||
struct page **pages;
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
|
||||
@ -860,14 +834,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
retval = nfs_get_user_pages(WRITE, (unsigned long) buf,
|
||||
count, &pages);
|
||||
if (retval < 0)
|
||||
goto out;
|
||||
page_count = retval;
|
||||
|
||||
retval = nfs_direct_write(iocb, (unsigned long) buf, count,
|
||||
pos, pages, page_count);
|
||||
retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos);
|
||||
|
||||
/*
|
||||
* XXX: nfs_end_data_update() already ensures this file's
|
||||
|
@ -3144,9 +3144,6 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
if (res < 0)
|
||||
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
|
||||
__FUNCTION__);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -3258,8 +3255,6 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/* Unlock _before_ we do the RPC call */
|
||||
do_vfs_lock(fl->fl_file, fl);
|
||||
return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data);
|
||||
}
|
||||
|
||||
@ -3270,30 +3265,28 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
|
||||
struct rpc_task *task;
|
||||
int status = 0;
|
||||
|
||||
status = nfs4_set_lock_state(state, request);
|
||||
/* Unlock _before_ we do the RPC call */
|
||||
request->fl_flags |= FL_EXISTS;
|
||||
if (do_vfs_lock(request->fl_file, request) == -ENOENT)
|
||||
goto out;
|
||||
if (status != 0)
|
||||
goto out;
|
||||
/* Is this a delegated lock? */
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags))
|
||||
goto out_unlock;
|
||||
/* Is this open_owner holding any locks on the server? */
|
||||
if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
|
||||
goto out_unlock;
|
||||
|
||||
status = nfs4_set_lock_state(state, request);
|
||||
if (status != 0)
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
lsp = request->fl_u.nfs4_fl.owner;
|
||||
status = -ENOMEM;
|
||||
seqid = nfs_alloc_seqid(&lsp->ls_seqid);
|
||||
status = -ENOMEM;
|
||||
if (seqid == NULL)
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid);
|
||||
status = PTR_ERR(task);
|
||||
if (IS_ERR(task))
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
status = nfs4_wait_for_completion_rpc_task(task);
|
||||
rpc_release_task(task);
|
||||
return status;
|
||||
out_unlock:
|
||||
do_vfs_lock(request->fl_file, request);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -3461,10 +3454,10 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
|
||||
struct nfs4_exception exception = { };
|
||||
int err;
|
||||
|
||||
/* Cache the lock if possible... */
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags))
|
||||
return 0;
|
||||
do {
|
||||
/* Cache the lock if possible... */
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
|
||||
return 0;
|
||||
err = _nfs4_do_setlk(state, F_SETLK, request, 1);
|
||||
if (err != -NFS4ERR_DELAY)
|
||||
break;
|
||||
@ -3483,6 +3476,8 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
|
||||
if (err != 0)
|
||||
return err;
|
||||
do {
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
|
||||
return 0;
|
||||
err = _nfs4_do_setlk(state, F_SETLK, request, 0);
|
||||
if (err != -NFS4ERR_DELAY)
|
||||
break;
|
||||
@ -3494,29 +3489,42 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
|
||||
static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
|
||||
{
|
||||
struct nfs4_client *clp = state->owner->so_client;
|
||||
unsigned char fl_flags = request->fl_flags;
|
||||
int status;
|
||||
|
||||
/* Is this a delegated open? */
|
||||
if (NFS_I(state->inode)->delegation_state != 0) {
|
||||
/* Yes: cache locks! */
|
||||
status = do_vfs_lock(request->fl_file, request);
|
||||
/* ...but avoid races with delegation recall... */
|
||||
if (status < 0 || test_bit(NFS_DELEGATED_STATE, &state->flags))
|
||||
return status;
|
||||
}
|
||||
down_read(&clp->cl_sem);
|
||||
status = nfs4_set_lock_state(state, request);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
request->fl_flags |= FL_ACCESS;
|
||||
status = do_vfs_lock(request->fl_file, request);
|
||||
if (status < 0)
|
||||
goto out;
|
||||
down_read(&clp->cl_sem);
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
|
||||
struct nfs_inode *nfsi = NFS_I(state->inode);
|
||||
/* Yes: cache locks! */
|
||||
down_read(&nfsi->rwsem);
|
||||
/* ...but avoid races with delegation recall... */
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
|
||||
request->fl_flags = fl_flags & ~FL_SLEEP;
|
||||
status = do_vfs_lock(request->fl_file, request);
|
||||
up_read(&nfsi->rwsem);
|
||||
goto out_unlock;
|
||||
}
|
||||
up_read(&nfsi->rwsem);
|
||||
}
|
||||
status = _nfs4_do_setlk(state, cmd, request, 0);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
/* Note: we always want to sleep here! */
|
||||
request->fl_flags |= FL_SLEEP;
|
||||
request->fl_flags = fl_flags | FL_SLEEP;
|
||||
if (do_vfs_lock(request->fl_file, request) < 0)
|
||||
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
|
||||
out:
|
||||
out_unlock:
|
||||
up_read(&clp->cl_sem);
|
||||
out:
|
||||
request->fl_flags = fl_flags;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -578,7 +578,7 @@ static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, un
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void nfs_cancel_requests(struct list_head *head)
|
||||
static void nfs_cancel_dirty_list(struct list_head *head)
|
||||
{
|
||||
struct nfs_page *req;
|
||||
while(!list_empty(head)) {
|
||||
@ -589,6 +589,19 @@ static void nfs_cancel_requests(struct list_head *head)
|
||||
}
|
||||
}
|
||||
|
||||
static void nfs_cancel_commit_list(struct list_head *head)
|
||||
{
|
||||
struct nfs_page *req;
|
||||
|
||||
while(!list_empty(head)) {
|
||||
req = nfs_list_entry(head->next);
|
||||
nfs_list_remove_request(req);
|
||||
nfs_inode_remove_request(req);
|
||||
nfs_clear_page_writeback(req);
|
||||
dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* nfs_scan_dirty - Scan an inode for dirty requests
|
||||
* @inode: NFS inode to scan
|
||||
@ -1381,6 +1394,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
|
||||
nfs_list_remove_request(req);
|
||||
nfs_mark_request_commit(req);
|
||||
nfs_clear_page_writeback(req);
|
||||
dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -1499,7 +1513,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
|
||||
if (pages != 0) {
|
||||
spin_unlock(&nfsi->req_lock);
|
||||
if (how & FLUSH_INVALIDATE)
|
||||
nfs_cancel_requests(&head);
|
||||
nfs_cancel_dirty_list(&head);
|
||||
else
|
||||
ret = nfs_flush_list(inode, &head, pages, how);
|
||||
spin_lock(&nfsi->req_lock);
|
||||
@ -1512,7 +1526,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
|
||||
break;
|
||||
if (how & FLUSH_INVALIDATE) {
|
||||
spin_unlock(&nfsi->req_lock);
|
||||
nfs_cancel_requests(&head);
|
||||
nfs_cancel_commit_list(&head);
|
||||
spin_lock(&nfsi->req_lock);
|
||||
continue;
|
||||
}
|
||||
|
@ -39,12 +39,4 @@
|
||||
*/
|
||||
#define NR_IRQS (NR_AIC_IRQS + (4 * 32))
|
||||
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/*
|
||||
* Initialize the IRQ controller.
|
||||
*/
|
||||
extern void at91rm9200_init_irq(unsigned int priority[]);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -43,6 +43,7 @@ typedef u64 cputime64_t;
|
||||
|
||||
#define cputime64_zero ((cputime64_t)0)
|
||||
#define cputime64_add(__a, __b) ((__a) + (__b))
|
||||
#define cputime64_sub(__a, __b) ((__a) - (__b))
|
||||
#define cputime_to_cputime64(__ct) (__ct)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
@ -74,6 +75,23 @@ static inline cputime_t jiffies_to_cputime(const unsigned long jif)
|
||||
return ct;
|
||||
}
|
||||
|
||||
static inline cputime64_t jiffies64_to_cputime64(const u64 jif)
|
||||
{
|
||||
cputime_t ct;
|
||||
u64 sec;
|
||||
|
||||
/* have to be a little careful about overflow */
|
||||
ct = jif % HZ;
|
||||
sec = jif / HZ;
|
||||
if (ct) {
|
||||
ct *= tb_ticks_per_sec;
|
||||
do_div(ct, HZ);
|
||||
}
|
||||
if (sec)
|
||||
ct += (cputime_t) sec * tb_ticks_per_sec;
|
||||
return ct;
|
||||
}
|
||||
|
||||
static inline u64 cputime64_to_jiffies64(const cputime_t ct)
|
||||
{
|
||||
return mulhdu(ct, __cputime_jiffies_factor);
|
||||
|
@ -160,6 +160,20 @@ static inline void dma_free_coherent(struct device *dev, size_t size,
|
||||
BUG();
|
||||
}
|
||||
|
||||
static inline void
|
||||
dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
BUG();
|
||||
}
|
||||
|
||||
static inline void
|
||||
dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
BUG();
|
||||
}
|
||||
|
||||
#endif /* PCI */
|
||||
|
||||
|
||||
|
@ -716,6 +716,7 @@ extern spinlock_t files_lock;
|
||||
#define FL_POSIX 1
|
||||
#define FL_FLOCK 2
|
||||
#define FL_ACCESS 8 /* not trying to lock, just looking */
|
||||
#define FL_EXISTS 16 /* when unlocking, test for existence */
|
||||
#define FL_LEASE 32 /* lease held on this file */
|
||||
#define FL_CLOSE 64 /* unlock on close */
|
||||
#define FL_SLEEP 128 /* A blocking lock */
|
||||
|
@ -131,6 +131,7 @@ enum {
|
||||
ATA_DFLAG_CFG_MASK = (1 << 8) - 1,
|
||||
|
||||
ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */
|
||||
ATA_DFLAG_SUSPENDED = (1 << 9), /* device suspended */
|
||||
ATA_DFLAG_INIT_MASK = (1 << 16) - 1,
|
||||
|
||||
ATA_DFLAG_DETACH = (1 << 16),
|
||||
@ -160,22 +161,28 @@ enum {
|
||||
ATA_FLAG_HRST_TO_RESUME = (1 << 11), /* hardreset to resume phy */
|
||||
ATA_FLAG_SKIP_D2H_BSY = (1 << 12), /* can't wait for the first D2H
|
||||
* Register FIS clearing BSY */
|
||||
|
||||
ATA_FLAG_DEBUGMSG = (1 << 13),
|
||||
ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */
|
||||
|
||||
ATA_FLAG_EH_PENDING = (1 << 15), /* EH pending */
|
||||
ATA_FLAG_EH_IN_PROGRESS = (1 << 16), /* EH in progress */
|
||||
ATA_FLAG_FROZEN = (1 << 17), /* port is frozen */
|
||||
ATA_FLAG_RECOVERED = (1 << 18), /* recovery action performed */
|
||||
ATA_FLAG_LOADING = (1 << 19), /* boot/loading probe */
|
||||
ATA_FLAG_UNLOADING = (1 << 20), /* module is unloading */
|
||||
ATA_FLAG_SCSI_HOTPLUG = (1 << 21), /* SCSI hotplug scheduled */
|
||||
/* The following flag belongs to ap->pflags but is kept in
|
||||
* ap->flags because it's referenced in many LLDs and will be
|
||||
* removed in not-too-distant future.
|
||||
*/
|
||||
ATA_FLAG_DISABLED = (1 << 23), /* port is disabled, ignore it */
|
||||
|
||||
ATA_FLAG_DISABLED = (1 << 22), /* port is disabled, ignore it */
|
||||
ATA_FLAG_SUSPENDED = (1 << 23), /* port is suspended (power) */
|
||||
/* bits 24:31 of ap->flags are reserved for LLD specific flags */
|
||||
|
||||
/* bits 24:31 of ap->flags are reserved for LLDD specific flags */
|
||||
/* struct ata_port pflags */
|
||||
ATA_PFLAG_EH_PENDING = (1 << 0), /* EH pending */
|
||||
ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), /* EH in progress */
|
||||
ATA_PFLAG_FROZEN = (1 << 2), /* port is frozen */
|
||||
ATA_PFLAG_RECOVERED = (1 << 3), /* recovery action performed */
|
||||
ATA_PFLAG_LOADING = (1 << 4), /* boot/loading probe */
|
||||
ATA_PFLAG_UNLOADING = (1 << 5), /* module is unloading */
|
||||
ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */
|
||||
|
||||
ATA_PFLAG_FLUSH_PORT_TASK = (1 << 16), /* flush port task */
|
||||
ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */
|
||||
ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */
|
||||
|
||||
/* struct ata_queued_cmd flags */
|
||||
ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */
|
||||
@ -248,12 +255,19 @@ enum {
|
||||
ATA_EH_REVALIDATE = (1 << 0),
|
||||
ATA_EH_SOFTRESET = (1 << 1),
|
||||
ATA_EH_HARDRESET = (1 << 2),
|
||||
ATA_EH_SUSPEND = (1 << 3),
|
||||
ATA_EH_RESUME = (1 << 4),
|
||||
ATA_EH_PM_FREEZE = (1 << 5),
|
||||
|
||||
ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
|
||||
ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE,
|
||||
ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_SUSPEND |
|
||||
ATA_EH_RESUME | ATA_EH_PM_FREEZE,
|
||||
|
||||
/* ata_eh_info->flags */
|
||||
ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */
|
||||
ATA_EHI_RESUME_LINK = (1 << 1), /* need to resume link */
|
||||
ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */
|
||||
ATA_EHI_QUIET = (1 << 3), /* be quiet */
|
||||
|
||||
ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */
|
||||
|
||||
@ -486,6 +500,7 @@ struct ata_port {
|
||||
const struct ata_port_operations *ops;
|
||||
spinlock_t *lock;
|
||||
unsigned long flags; /* ATA_FLAG_xxx */
|
||||
unsigned int pflags; /* ATA_PFLAG_xxx */
|
||||
unsigned int id; /* unique id req'd by scsi midlyr */
|
||||
unsigned int port_no; /* unique port #; from zero */
|
||||
unsigned int hard_port_no; /* hardware port #; from zero */
|
||||
@ -535,6 +550,9 @@ struct ata_port {
|
||||
struct list_head eh_done_q;
|
||||
wait_queue_head_t eh_wait_q;
|
||||
|
||||
pm_message_t pm_mesg;
|
||||
int *pm_result;
|
||||
|
||||
void *private_data;
|
||||
|
||||
u8 sector_buf[ATA_SECT_SIZE]; /* owned by EH */
|
||||
@ -589,6 +607,9 @@ struct ata_port_operations {
|
||||
void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
|
||||
u32 val);
|
||||
|
||||
int (*port_suspend) (struct ata_port *ap, pm_message_t mesg);
|
||||
int (*port_resume) (struct ata_port *ap);
|
||||
|
||||
int (*port_start) (struct ata_port *ap);
|
||||
void (*port_stop) (struct ata_port *ap);
|
||||
|
||||
@ -622,9 +643,18 @@ struct ata_timing {
|
||||
|
||||
#define FIT(v,vmin,vmax) max_t(short,min_t(short,v,vmax),vmin)
|
||||
|
||||
extern const unsigned long sata_deb_timing_boot[];
|
||||
extern const unsigned long sata_deb_timing_eh[];
|
||||
extern const unsigned long sata_deb_timing_before_fsrst[];
|
||||
extern const unsigned long sata_deb_timing_normal[];
|
||||
extern const unsigned long sata_deb_timing_hotplug[];
|
||||
extern const unsigned long sata_deb_timing_long[];
|
||||
|
||||
static inline const unsigned long *
|
||||
sata_ehc_deb_timing(struct ata_eh_context *ehc)
|
||||
{
|
||||
if (ehc->i.flags & ATA_EHI_HOTPLUGGED)
|
||||
return sata_deb_timing_hotplug;
|
||||
else
|
||||
return sata_deb_timing_normal;
|
||||
}
|
||||
|
||||
extern void ata_port_probe(struct ata_port *);
|
||||
extern void __sata_phy_reset(struct ata_port *ap);
|
||||
@ -644,6 +674,8 @@ extern void ata_std_ports(struct ata_ioports *ioaddr);
|
||||
extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
|
||||
unsigned int n_ports);
|
||||
extern void ata_pci_remove_one (struct pci_dev *pdev);
|
||||
extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t state);
|
||||
extern void ata_pci_device_do_resume(struct pci_dev *pdev);
|
||||
extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state);
|
||||
extern int ata_pci_device_resume(struct pci_dev *pdev);
|
||||
extern int ata_pci_clear_simplex(struct pci_dev *pdev);
|
||||
@ -664,8 +696,9 @@ extern int ata_port_online(struct ata_port *ap);
|
||||
extern int ata_port_offline(struct ata_port *ap);
|
||||
extern int ata_scsi_device_resume(struct scsi_device *);
|
||||
extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
|
||||
extern int ata_device_resume(struct ata_device *);
|
||||
extern int ata_device_suspend(struct ata_device *, pm_message_t state);
|
||||
extern int ata_host_set_suspend(struct ata_host_set *host_set,
|
||||
pm_message_t mesg);
|
||||
extern void ata_host_set_resume(struct ata_host_set *host_set);
|
||||
extern int ata_ratelimit(void);
|
||||
extern unsigned int ata_busy_sleep(struct ata_port *ap,
|
||||
unsigned long timeout_pat,
|
||||
@ -825,19 +858,24 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
|
||||
(ehi)->desc_len = 0; \
|
||||
} while (0)
|
||||
|
||||
static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
|
||||
static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi)
|
||||
{
|
||||
if (ehi->flags & ATA_EHI_HOTPLUGGED)
|
||||
return;
|
||||
|
||||
ehi->flags |= ATA_EHI_HOTPLUGGED;
|
||||
ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK;
|
||||
ehi->hotplug_timestamp = jiffies;
|
||||
|
||||
ehi->err_mask |= AC_ERR_ATA_BUS;
|
||||
ehi->action |= ATA_EH_SOFTRESET;
|
||||
ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
|
||||
}
|
||||
|
||||
static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
|
||||
{
|
||||
__ata_ehi_hotplugged(ehi);
|
||||
ehi->err_mask |= AC_ERR_ATA_BUS;
|
||||
}
|
||||
|
||||
/*
|
||||
* qc helpers
|
||||
*/
|
||||
@ -921,6 +959,11 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev)
|
||||
return ata_class_absent(dev->class);
|
||||
}
|
||||
|
||||
static inline unsigned int ata_dev_ready(const struct ata_device *dev)
|
||||
{
|
||||
return ata_dev_enabled(dev) && !(dev->flags & ATA_DFLAG_SUSPENDED);
|
||||
}
|
||||
|
||||
/*
|
||||
* port helpers
|
||||
*/
|
||||
|
@ -729,6 +729,7 @@ struct nfs_read_data {
|
||||
struct list_head pages; /* Coalesced read requests */
|
||||
struct nfs_page *req; /* multi ops per nfs_page */
|
||||
struct page **pagevec;
|
||||
unsigned int npages; /* active pages in pagevec */
|
||||
struct nfs_readargs args;
|
||||
struct nfs_readres res;
|
||||
#ifdef CONFIG_NFS_V4
|
||||
@ -747,6 +748,7 @@ struct nfs_write_data {
|
||||
struct list_head pages; /* Coalesced requests we wish to flush */
|
||||
struct nfs_page *req; /* multi ops per nfs_page */
|
||||
struct page **pagevec;
|
||||
unsigned int npages; /* active pages in pagevec */
|
||||
struct nfs_writeargs args; /* argument struct */
|
||||
struct nfs_writeres res; /* result struct */
|
||||
#ifdef CONFIG_NFS_V4
|
||||
|
@ -2019,6 +2019,13 @@
|
||||
#define PCI_VENDOR_ID_TDI 0x192E
|
||||
#define PCI_DEVICE_ID_TDI_EHCI 0x0101
|
||||
|
||||
#define PCI_VENDOR_ID_JMICRON 0x197B
|
||||
#define PCI_DEVICE_ID_JMICRON_JMB360 0x2360
|
||||
#define PCI_DEVICE_ID_JMICRON_JMB361 0x2361
|
||||
#define PCI_DEVICE_ID_JMICRON_JMB363 0x2363
|
||||
#define PCI_DEVICE_ID_JMICRON_JMB365 0x2365
|
||||
#define PCI_DEVICE_ID_JMICRON_JMB366 0x2366
|
||||
#define PCI_DEVICE_ID_JMICRON_JMB368 0x2368
|
||||
|
||||
#define PCI_VENDOR_ID_TEKRAM 0x1de1
|
||||
#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29
|
||||
|
@ -104,6 +104,7 @@ struct ieee80211softmac_assoc_info {
|
||||
*/
|
||||
u8 static_essid:1,
|
||||
associating:1,
|
||||
assoc_wait:1,
|
||||
bssvalid:1,
|
||||
bssfixed:1;
|
||||
|
||||
|
@ -368,6 +368,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
|
||||
/* Put this code here so that we avoid duplicating it in all
|
||||
* Rx paths. - Jean II */
|
||||
#ifdef CONFIG_WIRELESS_EXT
|
||||
#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
|
||||
/* If spy monitoring on */
|
||||
if (ieee->spy_data.spy_number > 0) {
|
||||
@ -396,15 +397,16 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
|
||||
wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
|
||||
}
|
||||
#endif /* IW_WIRELESS_SPY */
|
||||
#endif /* CONFIG_WIRELESS_EXT */
|
||||
|
||||
#ifdef NOT_YET
|
||||
hostap_update_rx_stats(local->ap, hdr, rx_stats);
|
||||
#endif
|
||||
|
||||
if (ieee->iw_mode == IW_MODE_MONITOR) {
|
||||
ieee80211_monitor_rx(ieee, skb, rx_stats);
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += skb->len;
|
||||
ieee80211_monitor_rx(ieee, skb, rx_stats);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -562,10 +562,13 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee,
|
||||
struct net_device_stats *stats = &ieee->stats;
|
||||
struct sk_buff *skb_frag;
|
||||
int priority = -1;
|
||||
int fraglen = total_len;
|
||||
int headroom = ieee->tx_headroom;
|
||||
struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
|
||||
|
||||
spin_lock_irqsave(&ieee->lock, flags);
|
||||
|
||||
if (encrypt_mpdu && !ieee->sec.encrypt)
|
||||
if (encrypt_mpdu && (!ieee->sec.encrypt || !crypt))
|
||||
encrypt_mpdu = 0;
|
||||
|
||||
/* If there is no driver handler to take the TXB, dont' bother
|
||||
@ -581,20 +584,24 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee,
|
||||
goto success;
|
||||
}
|
||||
|
||||
if (encrypt_mpdu)
|
||||
if (encrypt_mpdu) {
|
||||
frame->frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
fraglen += crypt->ops->extra_mpdu_prefix_len +
|
||||
crypt->ops->extra_mpdu_postfix_len;
|
||||
headroom += crypt->ops->extra_mpdu_prefix_len;
|
||||
}
|
||||
|
||||
/* When we allocate the TXB we allocate enough space for the reserve
|
||||
* and full fragment bytes (bytes_per_frag doesn't include prefix,
|
||||
* postfix, header, FCS, etc.) */
|
||||
txb = ieee80211_alloc_txb(1, total_len, ieee->tx_headroom, GFP_ATOMIC);
|
||||
txb = ieee80211_alloc_txb(1, fraglen, headroom, GFP_ATOMIC);
|
||||
if (unlikely(!txb)) {
|
||||
printk(KERN_WARNING "%s: Could not allocate TXB\n",
|
||||
ieee->dev->name);
|
||||
goto failed;
|
||||
}
|
||||
txb->encrypted = 0;
|
||||
txb->payload_size = total_len;
|
||||
txb->payload_size = fraglen;
|
||||
|
||||
skb_frag = txb->fragments[0];
|
||||
|
||||
|
@ -47,9 +47,7 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft
|
||||
|
||||
dprintk(KERN_INFO PFX "sent association request!\n");
|
||||
|
||||
/* Change the state to associating */
|
||||
spin_lock_irqsave(&mac->lock, flags);
|
||||
mac->associnfo.associating = 1;
|
||||
mac->associated = 0; /* just to make sure */
|
||||
|
||||
/* Set a timer for timeout */
|
||||
@ -63,6 +61,7 @@ void
|
||||
ieee80211softmac_assoc_timeout(void *d)
|
||||
{
|
||||
struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
|
||||
struct ieee80211softmac_network *n;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mac->lock, flags);
|
||||
@ -75,11 +74,12 @@ ieee80211softmac_assoc_timeout(void *d)
|
||||
mac->associnfo.associating = 0;
|
||||
mac->associnfo.bssvalid = 0;
|
||||
mac->associated = 0;
|
||||
|
||||
n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
|
||||
spin_unlock_irqrestore(&mac->lock, flags);
|
||||
|
||||
dprintk(KERN_INFO PFX "assoc request timed out!\n");
|
||||
/* FIXME: we need to know the network here. that requires a bit of restructuring */
|
||||
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL);
|
||||
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
|
||||
}
|
||||
|
||||
void
|
||||
@ -203,6 +203,10 @@ ieee80211softmac_assoc_work(void *d)
|
||||
if (mac->associated)
|
||||
ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
|
||||
|
||||
spin_lock_irqsave(&mac->lock, flags);
|
||||
mac->associnfo.associating = 1;
|
||||
spin_unlock_irqrestore(&mac->lock, flags);
|
||||
|
||||
/* try to find the requested network in our list, if we found one already */
|
||||
if (bssvalid || mac->associnfo.bssfixed)
|
||||
found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
|
||||
@ -295,19 +299,32 @@ ieee80211softmac_assoc_work(void *d)
|
||||
memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
|
||||
|
||||
/* we found a network! authenticate (if necessary) and associate to it. */
|
||||
if (!found->authenticated) {
|
||||
if (found->authenticating) {
|
||||
dprintk(KERN_INFO PFX "Already requested authentication, waiting...\n");
|
||||
if(!mac->associnfo.assoc_wait) {
|
||||
mac->associnfo.assoc_wait = 1;
|
||||
ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!found->authenticated && !found->authenticating) {
|
||||
/* This relies on the fact that _auth_req only queues the work,
|
||||
* otherwise adding the notification would be racy. */
|
||||
if (!ieee80211softmac_auth_req(mac, found)) {
|
||||
dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n");
|
||||
ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
|
||||
if(!mac->associnfo.assoc_wait) {
|
||||
dprintk(KERN_INFO PFX "Cannot associate without being authenticated, requested authentication\n");
|
||||
mac->associnfo.assoc_wait = 1;
|
||||
ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
|
||||
}
|
||||
} else {
|
||||
printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
|
||||
mac->associnfo.assoc_wait = 0;
|
||||
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* finally! now we can start associating */
|
||||
mac->associnfo.assoc_wait = 0;
|
||||
ieee80211softmac_assoc(mac, found);
|
||||
}
|
||||
|
||||
|
@ -36,8 +36,9 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
|
||||
struct ieee80211softmac_auth_queue_item *auth;
|
||||
unsigned long flags;
|
||||
|
||||
if (net->authenticating)
|
||||
if (net->authenticating || net->authenticated)
|
||||
return 0;
|
||||
net->authenticating = 1;
|
||||
|
||||
/* Add the network if it's not already added */
|
||||
ieee80211softmac_add_network(mac, net);
|
||||
@ -92,7 +93,6 @@ ieee80211softmac_auth_queue(void *data)
|
||||
return;
|
||||
}
|
||||
net->authenticated = 0;
|
||||
net->authenticating = 1;
|
||||
/* add a timeout call so we eventually give up waiting for an auth reply */
|
||||
schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
|
||||
auth->retry--;
|
||||
|
@ -229,6 +229,9 @@ ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
|
||||
return 0;
|
||||
ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
|
||||
|
||||
/* Fill in the capabilities */
|
||||
(*pkt)->capability = ieee80211softmac_capabilities(mac, net);
|
||||
|
||||
/* Fill in Listen Interval (?) */
|
||||
(*pkt)->listen_interval = cpu_to_le16(10);
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user