diff options
333 files changed, 11165 insertions, 5549 deletions
@@ -2423,8 +2423,7 @@ S: Toronto, Ontario S: Canada N: Zwane Mwaikambo -E: zwane@linuxpower.ca -W: http://function.linuxpower.ca +E: zwane@arm.linux.org.uk D: Various driver hacking D: Lowlevel x86 kernel hacking D: General debugging diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt new file mode 100644 index 00000000000..29ccae40903 --- /dev/null +++ b/Documentation/networking/phy.txt @@ -0,0 +1,288 @@ + +------- +PHY Abstraction Layer +(Updated 2005-07-21) + +Purpose + + Most network devices consist of set of registers which provide an interface + to a MAC layer, which communicates with the physical connection through a + PHY. The PHY concerns itself with negotiating link parameters with the link + partner on the other side of the network connection (typically, an ethernet + cable), and provides a register interface to allow drivers to determine what + settings were chosen, and to configure what settings are allowed. + + While these devices are distinct from the network devices, and conform to a + standard layout for the registers, it has been common practice to integrate + the PHY management code with the network driver. This has resulted in large + amounts of redundant code. Also, on embedded systems with multiple (and + sometimes quite different) ethernet controllers connected to the same + management bus, it is difficult to ensure safe use of the bus. + + Since the PHYs are devices, and the management busses through which they are + accessed are, in fact, busses, the PHY Abstraction Layer treats them as such. + In doing so, it has these goals: + + 1) Increase code-reuse + 2) Increase overall code-maintainability + 3) Speed development time for new network drivers, and for new systems + + Basically, this layer is meant to provide an interface to PHY devices which + allows network driver writers to write as little code as possible, while + still providing a full feature set. + +The MDIO bus + + Most network devices are connected to a PHY by means of a management bus. + Different devices use different busses (though some share common interfaces). + In order to take advantage of the PAL, each bus interface needs to be + registered as a distinct device. + + 1) read and write functions must be implemented. Their prototypes are: + + int write(struct mii_bus *bus, int mii_id, int regnum, u16 value); + int read(struct mii_bus *bus, int mii_id, int regnum); + + mii_id is the address on the bus for the PHY, and regnum is the register + number. These functions are guaranteed not to be called from interrupt + time, so it is safe for them to block, waiting for an interrupt to signal + the operation is complete + + 2) A reset function is necessary. This is used to return the bus to an + initialized state. + + 3) A probe function is needed. This function should set up anything the bus + driver needs, setup the mii_bus structure, and register with the PAL using + mdiobus_register. Similarly, there's a remove function to undo all of + that (use mdiobus_unregister). + + 4) Like any driver, the device_driver structure must be configured, and init + exit functions are used to register the driver. + + 5) The bus must also be declared somewhere as a device, and registered. + + As an example for how one driver implemented an mdio bus driver, see + drivers/net/gianfar_mii.c and arch/ppc/syslib/mpc85xx_devices.c + +Connecting to a PHY + + Sometime during startup, the network driver needs to establish a connection + between the PHY device, and the network device. At this time, the PHY's bus + and drivers need to all have been loaded, so it is ready for the connection. + At this point, there are several ways to connect to the PHY: + + 1) The PAL handles everything, and only calls the network driver when + the link state changes, so it can react. + + 2) The PAL handles everything except interrupts (usually because the + controller has the interrupt registers). + + 3) The PAL handles everything, but checks in with the driver every second, + allowing the network driver to react first to any changes before the PAL + does. + + 4) The PAL serves only as a library of functions, with the network device + manually calling functions to update status, and configure the PHY + + +Letting the PHY Abstraction Layer do Everything + + If you choose option 1 (The hope is that every driver can, but to still be + useful to drivers that can't), connecting to the PHY is simple: + + First, you need a function to react to changes in the link state. This + function follows this protocol: + + static void adjust_link(struct net_device *dev); + + Next, you need to know the device name of the PHY connected to this device. + The name will look something like, "phy0:0", where the first number is the + bus id, and the second is the PHY's address on that bus. + + Now, to connect, just call this function: + + phydev = phy_connect(dev, phy_name, &adjust_link, flags); + + phydev is a pointer to the phy_device structure which represents the PHY. If + phy_connect is successful, it will return the pointer. dev, here, is the + pointer to your net_device. Once done, this function will have started the + PHY's software state machine, and registered for the PHY's interrupt, if it + has one. The phydev structure will be populated with information about the + current state, though the PHY will not yet be truly operational at this + point. + + flags is a u32 which can optionally contain phy-specific flags. + This is useful if the system has put hardware restrictions on + the PHY/controller, of which the PHY needs to be aware. + + Now just make sure that phydev->supported and phydev->advertising have any + values pruned from them which don't make sense for your controller (a 10/100 + controller may be connected to a gigabit capable PHY, so you would need to + mask off SUPPORTED_1000baseT*). See include/linux/ethtool.h for definitions + for these bitfields. Note that you should not SET any bits, or the PHY may + get put into an unsupported state. + + Lastly, once the controller is ready to handle network traffic, you call + phy_start(phydev). This tells the PAL that you are ready, and configures the + PHY to connect to the network. If you want to handle your own interrupts, + just set phydev->irq to PHY_IGNORE_INTERRUPT before you call phy_start. + Similarly, if you don't want to use interrupts, set phydev->irq to PHY_POLL. + + When you want to disconnect from the network (even if just briefly), you call + phy_stop(phydev). + +Keeping Close Tabs on the PAL + + It is possible that the PAL's built-in state machine needs a little help to + keep your network device and the PHY properly in sync. If so, you can + register a helper function when connecting to the PHY, which will be called + every second before the state machine reacts to any changes. To do this, you + need to manually call phy_attach() and phy_prepare_link(), and then call + phy_start_machine() with the second argument set to point to your special + handler. + + Currently there are no examples of how to use this functionality, and testing + on it has been limited because the author does not have any drivers which use + it (they all use option 1). So Caveat Emptor. + +Doing it all yourself + + There's a remote chance that the PAL's built-in state machine cannot track + the complex interactions between the PHY and your network device. If this is + so, you can simply call phy_attach(), and not call phy_start_machine or + phy_prepare_link(). This will mean that phydev->state is entirely yours to + handle (phy_start and phy_stop toggle between some of the states, so you + might need to avoid them). + + An effort has been made to make sure that useful functionality can be + accessed without the state-machine running, and most of these functions are + descended from functions which did not interact with a complex state-machine. + However, again, no effort has been made so far to test running without the + state machine, so tryer beware. + + Here is a brief rundown of the functions: + + int phy_read(struct phy_device *phydev, u16 regnum); + int phy_write(struct phy_device *phydev, u16 regnum, u16 val); + + Simple read/write primitives. They invoke the bus's read/write function + pointers. + + void phy_print_status(struct phy_device *phydev); + + A convenience function to print out the PHY status neatly. + + int phy_clear_interrupt(struct phy_device *phydev); + int phy_config_interrupt(struct phy_device *phydev, u32 interrupts); + + Clear the PHY's interrupt, and configure which ones are allowed, + respectively. Currently only supports all on, or all off. + + int phy_enable_interrupts(struct phy_device *phydev); + int phy_disable_interrupts(struct phy_device *phydev); + + Functions which enable/disable PHY interrupts, clearing them + before and after, respectively. + + int phy_start_interrupts(struct phy_device *phydev); + int phy_stop_interrupts(struct phy_device *phydev); + + Requests the IRQ for the PHY interrupts, then enables them for + start, or disables then frees them for stop. + + struct phy_device * phy_attach(struct net_device *dev, const char *phy_id, + u32 flags); + + Attaches a network device to a particular PHY, binding the PHY to a generic + driver if none was found during bus initialization. Passes in + any phy-specific flags as needed. + + int phy_start_aneg(struct phy_device *phydev); + + Using variables inside the phydev structure, either configures advertising + and resets autonegotiation, or disables autonegotiation, and configures + forced settings. + + static inline int phy_read_status(struct phy_device *phydev); + + Fills the phydev structure with up-to-date information about the current + settings in the PHY. + + void phy_sanitize_settings(struct phy_device *phydev) + + Resolves differences between currently desired settings, and + supported settings for the given PHY device. Does not make + the changes in the hardware, though. + + int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd); + int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd); + + Ethtool convenience functions. + + int phy_mii_ioctl(struct phy_device *phydev, + struct mii_ioctl_data *mii_data, int cmd); + + The MII ioctl. Note that this function will completely screw up the state + machine if you write registers like BMCR, BMSR, ADVERTISE, etc. Best to + use this only to write registers which are not standard, and don't set off + a renegotiation. + + +PHY Device Drivers + + With the PHY Abstraction Layer, adding support for new PHYs is + quite easy. In some cases, no work is required at all! However, + many PHYs require a little hand-holding to get up-and-running. + +Generic PHY driver + + If the desired PHY doesn't have any errata, quirks, or special + features you want to support, then it may be best to not add + support, and let the PHY Abstraction Layer's Generic PHY Driver + do all of the work. + +Writing a PHY driver + + If you do need to write a PHY driver, the first thing to do is + make sure it can be matched with an appropriate PHY device. + This is done during bus initialization by reading the device's + UID (stored in registers 2 and 3), then comparing it to each + driver's phy_id field by ANDing it with each driver's + phy_id_mask field. Also, it needs a name. Here's an example: + + static struct phy_driver dm9161_driver = { + .phy_id = 0x0181b880, + .name = "Davicom DM9161E", + .phy_id_mask = 0x0ffffff0, + ... + } + + Next, you need to specify what features (speed, duplex, autoneg, + etc) your PHY device and driver support. Most PHYs support + PHY_BASIC_FEATURES, but you can look in include/mii.h for other + features. + + Each driver consists of a number of function pointers: + + config_init: configures PHY into a sane state after a reset. + For instance, a Davicom PHY requires descrambling disabled. + probe: Does any setup needed by the driver + suspend/resume: power management + config_aneg: Changes the speed/duplex/negotiation settings + read_status: Reads the current speed/duplex/negotiation settings + ack_interrupt: Clear a pending interrupt + config_intr: Enable or disable interrupts + remove: Does any driver take-down + + Of these, only config_aneg and read_status are required to be + assigned by the driver code. The rest are optional. Also, it is + preferred to use the generic phy driver's versions of these two + functions if at all possible: genphy_read_status and + genphy_config_aneg. If this is not possible, it is likely that + you only need to perform some actions before and after invoking + these functions, and so your functions will wrap the generic + ones. + + Feel free to look at the Marvell, Cicada, and Davicom drivers in + drivers/net/phy/ for examples (the lxt and qsemi drivers have + not been tested as of this writing) diff --git a/MAINTAINERS b/MAINTAINERS index 33122b1519c..564a03e61a0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1739,7 +1739,7 @@ S: Maintained OPL3-SA2, SA3, and SAx DRIVER P: Zwane Mwaikambo -M: zwane@commfireservices.com +M: zwane@arm.linux.org.uk L: linux-sound@vger.kernel.org S: Maintained @@ -1995,7 +1995,7 @@ S: Maintained SC1200 WDT DRIVER P: Zwane Mwaikambo -M: zwane@commfireservices.com +M: zwane@arm.linux.org.uk S: Maintained SCHEDULER @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 13 -EXTRAVERSION =-rc6 +EXTRAVERSION = NAME=Woozy Numbat # *DOCUMENTATION* diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 083c5df42d3..189d5eababa 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -522,7 +522,7 @@ source "mm/Kconfig" config NUMA bool "NUMA Support (EXPERIMENTAL)" - depends on DISCONTIGMEM + depends on DISCONTIGMEM && BROKEN help Say Y to compile the kernel to support NUMA (Non-Uniform Memory Access). This option is for configuring high-end multiprocessor diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 08fe8071a7f..2e45e8604e3 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -566,13 +566,12 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, if (ka->sa.sa_flags & SA_RESETHAND) ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } static inline void diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 8f1e78551b1..e211aa7404e 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -1036,7 +1036,7 @@ debug_spin_lock(spinlock_t * lock, const char *base_file, int line_no) " br 1b\n" ".previous" : "=r" (tmp), "=m" (lock->lock), "=r" (stuck) - : "1" (lock->lock), "2" (stuck) : "memory"); + : "m" (lock->lock), "2" (stuck) : "memory"); if (stuck < 0) { printk(KERN_WARNING @@ -1115,7 +1115,7 @@ void _raw_write_lock(rwlock_t * lock) ".previous" : "=m" (*(volatile int *)lock), "=&r" (regx), "=&r" (regy), "=&r" (stuck_lock), "=&r" (stuck_reader) - : "0" (*(volatile int *)lock), "3" (stuck_lock), "4" (stuck_reader) : "memory"); + : "m" (*(volatile int *)lock), "3" (stuck_lock), "4" (stuck_reader) : "memory"); if (stuck_lock < 0) { printk(KERN_WARNING "write_lock stuck at %p\n", inline_pc); @@ -1153,7 +1153,7 @@ void _raw_read_lock(rwlock_t * lock) " br 1b\n" ".previous" : "=m" (*(volatile int *)lock), "=&r" (regx), "=&r" (stuck_lock) - : "0" (*(volatile int *)lock), "2" (stuck_lock) : "memory"); + : "m" (*(volatile int *)lock), "2" (stuck_lock) : "memory"); if (stuck_lock < 0) { printk(KERN_WARNING "read_lock stuck at %p\n", inline_pc); diff --git a/arch/alpha/oprofile/common.c b/arch/alpha/oprofile/common.c index 908eb4af8de..ba788cfdc3c 100644 --- a/arch/alpha/oprofile/common.c +++ b/arch/alpha/oprofile/common.c @@ -65,7 +65,7 @@ op_axp_setup(void) model->reg_setup(®, ctr, &sys); /* Configure the registers on all cpus. */ - smp_call_function(model->cpu_setup, ®, 0, 1); + (void)smp_call_function(model->cpu_setup, ®, 0, 1); model->cpu_setup(®); return 0; } @@ -86,7 +86,7 @@ op_axp_cpu_start(void *dummy) static int op_axp_start(void) { - smp_call_function(op_axp_cpu_start, NULL, 0, 1); + (void)smp_call_function(op_axp_cpu_start, NULL, 0, 1); op_axp_cpu_start(NULL); return 0; } @@ -101,7 +101,7 @@ op_axp_cpu_stop(void *dummy) static void op_axp_stop(void) { - smp_call_function(op_axp_cpu_stop, NULL, 0, 1); + (void)smp_call_function(op_axp_cpu_stop, NULL, 0, 1); op_axp_cpu_stop(NULL); } diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index f91c8d982ef..4bf0e8737e1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -310,7 +310,7 @@ menu "Kernel Features" config SMP bool "Symmetric Multi-Processing (EXPERIMENTAL)" - depends on EXPERIMENTAL #&& n + depends on EXPERIMENTAL && BROKEN #&& n help This enables support for systems with more than one CPU. If you have a system with only one CPU, like most personal computers, say N. If @@ -715,6 +715,8 @@ source "drivers/hwmon/Kconfig" source "drivers/misc/Kconfig" +source "drivers/mfd/Kconfig" + source "drivers/media/Kconfig" source "drivers/video/Kconfig" diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 5e435e42dac..a94d75fef59 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -658,11 +658,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, /* * Block the signal if we were unsuccessful. */ - if (ret != 0 || !(ka->sa.sa_flags & SA_NODEFER)) { + if (ret != 0) { spin_lock_irq(&tsk->sighand->siglock); sigorsets(&tsk->blocked, &tsk->blocked, &ka->sa.sa_mask); - sigaddset(&tsk->blocked, sig); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(&tsk->blocked, sig); recalc_sigpending(); spin_unlock_irq(&tsk->sighand->siglock); } diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index d571c37ac30..4554c961251 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -617,7 +617,7 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs) notify_die("unknown data abort code", regs, &info, instr, 0); } -volatile void __bug(const char *file, int line, void *data) +void __attribute__((noreturn)) __bug(const char *file, int line, void *data) { printk(KERN_CRIT"kernel BUG at %s:%d!", file, line); if (data) diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c index 7f58afb27e7..411ea999619 100644 --- a/arch/arm/mach-ixp4xx/coyote-setup.c +++ b/arch/arm/mach-ixp4xx/coyote-setup.c @@ -36,7 +36,7 @@ static struct flash_platform_data coyote_flash_data = { static struct resource coyote_flash_resource = { .start = COYOTE_FLASH_BASE, - .end = COYOTE_FLASH_BASE + COYOTE_FLASH_SIZE, + .end = COYOTE_FLASH_BASE + COYOTE_FLASH_SIZE - 1, .flags = IORESOURCE_MEM, }; diff --git a/arch/arm/mach-ixp4xx/gtwx5715-setup.c b/arch/arm/mach-ixp4xx/gtwx5715-setup.c index 65e356bd10d..333459d6aa4 100644 --- a/arch/arm/mach-ixp4xx/gtwx5715-setup.c +++ b/arch/arm/mach-ixp4xx/gtwx5715-setup.c @@ -114,7 +114,7 @@ static struct flash_platform_data gtwx5715_flash_data = { static struct resource gtwx5715_flash_resource = { .start = GTWX5715_FLASH_BASE, - .end = GTWX5715_FLASH_BASE + GTWX5715_FLASH_SIZE, + .end = GTWX5715_FLASH_BASE + GTWX5715_FLASH_SIZE - 1, .flags = IORESOURCE_MEM, }; diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index 4633470a6a3..fa0646c8693 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -36,7 +36,7 @@ static struct flash_platform_data ixdp425_flash_data = { static struct resource ixdp425_flash_resource = { .start = IXDP425_FLASH_BASE, - .end = IXDP425_FLASH_BASE + IXDP425_FLASH_SIZE, + .end = IXDP425_FLASH_BASE + IXDP425_FLASH_SIZE - 1, .flags = IORESOURCE_MEM, }; diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index 4d4d303ee3a..24687f511bf 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -35,6 +35,7 @@ #include <asm/mach/map.h> #include <asm/mach/serial_sa1100.h> #include <asm/arch/assabet.h> +#include <asm/arch/mcp.h> #include "generic.h" @@ -198,6 +199,11 @@ static struct irda_platform_data assabet_irda_data = { .set_speed = assabet_irda_set_speed, }; +static struct mcp_plat_data assabet_mcp_data = { + .mccr0 = MCCR0_ADM, + .sclk_rate = 11981000, +}; + static void __init assabet_init(void) { /* @@ -246,6 +252,7 @@ static void __init assabet_init(void) sa11x0_set_flash_data(&assabet_flash_data, assabet_flash_resources, ARRAY_SIZE(assabet_flash_resources)); sa11x0_set_irda_data(&assabet_irda_data); + sa11x0_set_mcp_data(&assabet_mcp_data); } /* diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c index 0aa918e24c3..9484be7dc67 100644 --- a/arch/arm/mach-sa1100/cerf.c +++ b/arch/arm/mach-sa1100/cerf.c @@ -29,6 +29,7 @@ #include <asm/mach/serial_sa1100.h> #include <asm/arch/cerf.h> +#include <asm/arch/mcp.h> #include "generic.h" static struct resource cerfuart2_resources[] = { @@ -116,10 +117,16 @@ static void __init cerf_map_io(void) GPDR |= CERF_GPIO_CF_RESET; } +static struct mcp_plat_data cerf_mcp_data = { + .mccr0 = MCCR0_ADM, + .sclk_rate = 11981000, +}; + static void __init cerf_init(void) { platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices)); sa11x0_set_flash_data(&cerf_flash_data, &cerf_flash_resource, 1); + sa11x0_set_mcp_data(&cerf_mcp_data); } MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube") diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 95ae217be1b..3f1e358455e 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -221,6 +221,11 @@ static struct platform_device sa11x0mcp_device = { .resource = sa11x0mcp_resources, }; +void sa11x0_set_mcp_data(struct mcp_plat_data *data) +{ + sa11x0mcp_device.dev.platform_data = data; +} + static struct resource sa11x0ssp_resources[] = { [0] = { .start = 0x80070000, diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h index bfe41da9923..279e3afa3c3 100644 --- a/arch/arm/mach-sa1100/generic.h +++ b/arch/arm/mach-sa1100/generic.h @@ -34,5 +34,8 @@ struct resource; extern void sa11x0_set_flash_data(struct flash_platform_data *flash, struct resource *res, int nr); +struct sa11x0_ssp_plat_ops; +extern void sa11x0_set_ssp_data(struct sa11x0_ssp_plat_ops *ops); + struct irda_platform_data; void sa11x0_set_irda_data(struct irda_platform_data *irda); diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c index 870b488aeda..ed6744d480a 100644 --- a/arch/arm/mach-sa1100/lart.c +++ b/arch/arm/mach-sa1100/lart.c @@ -13,12 +13,23 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/serial_sa1100.h> +#include <asm/arch/mcp.h> #include "generic.h" #warning "include/asm/arch-sa1100/ide.h needs fixing for lart" +static struct mcp_plat_data lart_mcp_data = { + .mccr0 = MCCR0_ADM, + .sclk_rate = 11981000, +}; + +static void __init lart_init(void) +{ + sa11x0_set_mcp_data(&lart_mcp_data); +} + static struct map_desc lart_io_desc[] __initdata = { /* virtual physical length type */ { 0xe8000000, 0x00000000, 0x00400000, MT_DEVICE }, /* main flash memory */ @@ -47,5 +58,6 @@ MACHINE_START(LART, "LART") .boot_params = 0xc0000100, .map_io = lart_map_io, .init_irq = sa1100_init_irq, + .init_machine = lart_init, .timer = &sa1100_timer, MACHINE_END diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c index 43a00359fcd..7482288278d 100644 --- a/arch/arm/mach-sa1100/shannon.c +++ b/arch/arm/mach-sa1100/shannon.c @@ -18,6 +18,7 @@ #include <asm/mach/flash.h> #include <asm/mach/map.h> #include <asm/mach/serial_sa1100.h> +#include <asm/arch/mcp.h> #include <asm/arch/shannon.h> #include "generic.h" @@ -52,9 +53,15 @@ static struct resource shannon_flash_resource = { .flags = IORESOURCE_MEM, }; +static struct mcp_plat_data shannon_mcp_data = { + .mccr0 = MCCR0_ADM, + .sclk_rate = 11981000, +}; + static void __init shannon_init(void) { sa11x0_set_flash_data(&shannon_flash_data, &shannon_flash_resource, 1); + sa11x0_set_mcp_data(&shannon_mcp_data); } static void __init shannon_map_io(void) diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c index 77978586b12..07f6d5fd7bb 100644 --- a/arch/arm/mach-sa1100/simpad.c +++ b/arch/arm/mach-sa1100/simpad.c @@ -23,6 +23,7 @@ #include <asm/mach/flash.h> #include <asm/mach/map.h> #include <asm/mach/serial_sa1100.h> +#include <asm/arch/mcp.h> #include <asm/arch/simpad.h> #include <linux/serial_core.h> @@ -123,6 +124,11 @@ static struct resource simpad_flash_resources [] = { } }; +static struct mcp_plat_data simpad_mcp_data = { + .mccr0 = MCCR0_ADM, + .sclk_rate = 11981000, +}; + static void __init simpad_map_io(void) @@ -157,6 +163,7 @@ static void __init simpad_map_io(void) sa11x0_set_flash_data(&simpad_flash_data, simpad_flash_resources, ARRAY_SIZE(simpad_flash_resources)); + sa11x0_set_mcp_data(&simpad_mcp_data); } static void simpad_power_off(void) diff --git a/arch/arm/nwfpe/fpopcode.h b/arch/arm/nwfpe/fpopcode.h index 8035f4faafb..1777e92a88e 100644 --- a/arch/arm/nwfpe/fpopcode.h +++ b/arch/arm/nwfpe/fpopcode.h @@ -370,20 +370,20 @@ TABLE 5 #define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5) #ifdef CONFIG_FPE_NWFPE_XP -static inline const floatx80 getExtendedConstant(const unsigned int nIndex) +static inline __attribute_pure__ floatx80 getExtendedConstant(const unsigned int nIndex) { extern const floatx80 floatx80Constant[]; return floatx80Constant[nIndex]; } #endif -static inline const float64 getDoubleConstant(const unsigned int nIndex) +static inline __attribute_pure__ float64 getDoubleConstant(const unsigned int nIndex) { extern const float64 float64Constant[]; return float64Constant[nIndex]; } -static inline const float32 getSingleConstant(const unsigned int nIndex) +static inline __attribute_pure__ float32 getSingleConstant(const unsigned int nIndex) { extern const float32 float32Constant[]; return float32Constant[nIndex]; diff --git a/arch/arm26/kernel/signal.c b/arch/arm26/kernel/signal.c index 356d9809cc0..ce2055bdc9e 100644 --- a/arch/arm26/kernel/signal.c +++ b/arch/arm26/kernel/signal.c @@ -454,14 +454,13 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(&tsk->sighand->siglock); - sigorsets(&tsk->blocked, &tsk->blocked, - &ka->sa.sa_mask); + spin_lock_irq(&tsk->sighand->siglock); + sigorsets(&tsk->blocked, &tsk->blocked, + &ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(&tsk->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(&tsk->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(&tsk->sighand->siglock); return; } diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c index 85e0032e664..693771961f8 100644 --- a/arch/cris/arch-v10/kernel/signal.c +++ b/arch/cris/arch-v10/kernel/signal.c @@ -517,13 +517,12 @@ handle_signal(int canrestart, unsigned long sig, if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } /* diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index fb4c79d5b76..0a3614dab88 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c @@ -568,13 +568,12 @@ handle_signal(int canrestart, unsigned long sig, if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } /* diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 36a2dffc8eb..d4ccc0728df 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -506,13 +506,12 @@ static void handle_signal(unsigned long sig, siginfo_t *info, else setup_frame(sig, ka, oldset, regs); - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } /* end handle_signal() */ /*****************************************************************************/ diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index 5aab87eae1f..f13d5e82d4b 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -488,13 +488,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, else setup_frame(sig, ka, oldset, regs); - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } /* diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index bd1dbf3bd22..a22a866de8f 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -726,15 +726,11 @@ __setup("apic=", apic_set_verbosity); static int __init detect_init_APIC (void) { u32 h, l, features; - extern void get_cpu_vendor(struct cpuinfo_x86*); /* Disabled by kernel option? */ if (enable_local_apic < 0) return -1; - /* Workaround for us being called before identify_cpu(). */ - get_cpu_vendor(&boot_cpu_data); - switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: if ((boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1) || diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index da6c46d667c..8c242bb1ef4 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -195,7 +195,7 @@ static void disable_lapic_nmi_watchdog(void) wrmsr(MSR_P6_EVNTSEL0, 0, 0); break; case 15: - if (boot_cpu_data.x86_model > 0x3) + if (boot_cpu_data.x86_model > 0x4) break; wrmsr(MSR_P4_IQ_CCCR0, 0, 0); @@ -432,7 +432,7 @@ void setup_apic_nmi_watchdog (void) setup_p6_watchdog(); break; case 15: - if (boot_cpu_data.x86_model > 0x3) + if (boot_cpu_data.x86_model > 0x4) return; if (!setup_p4_watchdog()) diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index 89ef7adc63a..140e340569c 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -577,10 +577,11 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, else ret = setup_frame(sig, ka, oldset, regs); - if (ret && !(ka->sa.sa_flags & SA_NODEFER)) { + if (ret) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); - sigaddset(¤t->blocked,sig); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); } diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index a61f33d06ea..cd2d5d5514f 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -803,15 +803,17 @@ void math_error(void __user *eip) */ cwd = get_fpu_cwd(task); swd = get_fpu_swd(task); - switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) { + switch (swd & ~cwd & 0x3f) { case 0x000: default: break; case 0x001: /* Invalid Op */ - case 0x041: /* Stack Fault */ - case 0x241: /* Stack Fault | Direction */ + /* + * swd & 0x240 == 0x040: Stack Underflow + * swd & 0x240 == 0x240: Stack Overflow + * User must clear the SF bit (0x40) if set + */ info.si_code = FPE_FLTINV; - /* Should we clear the SF or let user space do it ???? */ break; case 0x002: /* Denormalize */ case 0x010: /* Underflow */ diff --git a/arch/ia64/hp/sim/boot/boot_head.S b/arch/ia64/hp/sim/boot/boot_head.S index 9364199e563..1c8c7e6a9a5 100644 --- a/arch/ia64/hp/sim/boot/boot_head.S +++ b/arch/ia64/hp/sim/boot/boot_head.S @@ -22,7 +22,7 @@ GLOBAL_ENTRY(_start) .save rp, r0 .body movl gp = __gp - movl sp = stack_mem + movl sp = stack_mem+16384-16 bsw.1 br.call.sptk.many rp=start_bootloader END(_start) diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index b8a0a7d257a..774f34b675c 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -467,15 +467,12 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse if (!setup_frame(sig, ka, info, oldset, scr)) return 0; - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - { - sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - } - spin_unlock_irq(¤t->sighand->siglock); - } + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked, sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); return 1; } diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 54d9ed444e4..f9472c50ab4 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -380,6 +380,7 @@ void pcibios_bus_to_resource(struct pci_dev *dev, res->start = region->start + offset; res->end = region->end + offset; } +EXPORT_SYMBOL(pcibios_bus_to_resource); static int __devinit is_valid_resource(struct pci_dev *dev, int idx) { diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 37e10e010a2..414cdf2e3c9 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -323,7 +323,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) struct pci_controller *controller; struct pcibus_bussoft *prom_bussoft_ptr; struct hubdev_info *hubdev_info; - void *provider_soft; + void *provider_soft = NULL; struct sn_pcibus_provider *provider; status = sal_get_pcibus_info((u64) segment, (u64) busnum, @@ -339,7 +339,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) if (bus == NULL) { bus = pci_scan_bus(busnum, &pci_root_ops, controller); if (bus == NULL) - return; /* error, or bus already scanned */ + goto error_return; /* error, or bus already scanned */ bus->sysdata = NULL; } @@ -352,28 +352,30 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) */ if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) - return; /* unsupported asic type */ + goto error_return; /* unsupported asic type */ if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB) goto error_return; /* no further fixup necessary */ provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type]; if (provider == NULL) - return; /* no provider registerd for this asic */ + goto error_return; /* no provider registerd for this asic */ - provider_soft = NULL; + bus->sysdata = controller; if (provider->bus_fixup) provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr, controller); - if (provider_soft == NULL) - return; /* fixup failed or not applicable */ + if (provider_soft == NULL) { + /* fixup failed or not applicable */ + bus->sysdata = NULL; + goto error_return; + } /* * Generic bus fixup goes here. Don't reference prom_bussoft_ptr * after this point. */ - bus->sysdata = controller; PCI_CONTROLLER(bus)->platform_data = provider_soft; nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base); cnode = nasid_to_cnodeid(nasid); diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index 7772951df31..7622d4ec5f0 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig @@ -269,7 +269,7 @@ config NR_CPUS # Common NUMA Features config NUMA bool "Numa Memory Allocation Support" - depends on SMP + depends on SMP && BROKEN default n # turning this on wastes a bunch of space. @@ -286,6 +286,7 @@ menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" config PCI bool "PCI support" + depends on BROKEN default n help Find out whether you have a PCI motherboard. PCI is the name of a diff --git a/arch/m32r/Kconfig.debug b/arch/m32r/Kconfig.debug index 31039723804..bbf711bab69 100644 --- a/arch/m32r/Kconfig.debug +++ b/arch/m32r/Kconfig.debug @@ -20,7 +20,7 @@ config DEBUG_STACK_USAGE config DEBUG_PAGEALLOC bool "Page alloc debugging" - depends on DEBUG_KERNEL + depends on DEBUG_KERNEL && BROKEN help Unmap pages from the kernel linear mapping after free_pages(). This results in a large slowdown, but helps to find certain types diff --git a/arch/m32r/kernel/setup_m32700ut.c b/arch/m32r/kernel/setup_m32700ut.c index a146b24a556..708634b685e 100644 --- a/arch/m32r/kernel/setup_m32700ut.c +++ b/arch/m32r/kernel/setup_m32700ut.c @@ -30,9 +30,11 @@ typedef struct { unsigned long icucr; /* ICU Control Register */ } icu_data_t; +static icu_data_t icu_data[M32700UT_NUM_CPU_IRQ]; +#else +icu_data_t icu_data[M32700UT_NUM_CPU_IRQ]; #endif /* CONFIG_SMP */ -static icu_data_t icu_data[M32700UT_NUM_CPU_IRQ]; static void disable_m32700ut_irq(unsigned int irq) { diff --git a/arch/m32r/kernel/setup_opsput.c b/arch/m32r/kernel/setup_opsput.c index f0301f58bcc..d7b7ec6d30f 100644 --- a/arch/m32r/kernel/setup_opsput.c +++ b/arch/m32r/kernel/setup_opsput.c @@ -31,9 +31,11 @@ typedef struct { unsigned long icucr; /* ICU Control Register */ } icu_data_t; +static icu_data_t icu_data[OPSPUT_NUM_CPU_IRQ]; +#else +icu_data_t icu_data[OPSPUT_NUM_CPU_IRQ]; #endif /* CONFIG_SMP */ -static icu_data_t icu_data[OPSPUT_NUM_CPU_IRQ]; static void disable_opsput_irq(unsigned int irq) { diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index 5aef7e406ef..71763f7a1d1 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -341,13 +341,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, /* Set up the stack frame */ setup_rt_frame(sig, ka, info, oldset, regs); - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } /* diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c index f9a0e723478..640d592ea07 100644 --- a/arch/m32r/kernel/smpboot.c +++ b/arch/m32r/kernel/smpboot.c @@ -91,6 +91,7 @@ extern struct { /* which physical physical ID maps to which logical CPU number */ static volatile int physid_2_cpu[NR_CPUS]; +#define physid_to_cpu(physid) physid_2_cpu[physid] /* which logical CPU number maps to which physical ID */ volatile int cpu_2_physid[NR_CPUS]; diff --git a/arch/m32r/lib/csum_partial_copy.c b/arch/m32r/lib/csum_partial_copy.c index c871b4606b0..ddb16a83a8c 100644 --- a/arch/m32r/lib/csum_partial_copy.c +++ b/arch/m32r/lib/csum_partial_copy.c @@ -58,3 +58,4 @@ csum_partial_copy_from_user (const unsigned char __user *src, return csum_partial(dst, len-missing, sum); } EXPORT_SYMBOL(csum_partial_copy_from_user); +EXPORT_SYMBOL(csum_partial); diff --git a/arch/m32r/mm/discontig.c b/arch/m32r/mm/discontig.c index 1d1a01e54b3..08e72795555 100644 --- a/arch/m32r/mm/discontig.c +++ b/arch/m32r/mm/discontig.c @@ -12,12 +12,14 @@ #include <linux/mmzone.h> #include <linux/initrd.h> #include <linux/nodemask.h> +#include <linux/module.h> #include <asm/setup.h> extern char _end[]; struct pglist_data *node_data[MAX_NUMNODES]; +EXPORT_SYMBOL(node_data); static bootmem_data_t node_bdata[MAX_NUMNODES] __initdata; pg_data_t m32r_node_data[MAX_NUMNODES]; diff --git a/arch/m68knommu/kernel/signal.c b/arch/m68knommu/kernel/signal.c index 30dceb59a46..43a2726c0d0 100644 --- a/arch/m68knommu/kernel/signal.c +++ b/arch/m68knommu/kernel/signal.c @@ -732,13 +732,12 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } /* diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index 40244782a8e..4c114ae2179 100644 --- a/arch/mips/kernel/irixsig.c +++ b/arch/mips/kernel/irixsig.c @@ -155,13 +155,12 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, else setup_irix_frame(ka, regs, sig, oldset); - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs) diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 65ee15396ff..0209c1dd142 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -425,13 +425,12 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, setup_frame(ka, regs, sig, oldset); #endif - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index c1a69cf232f..f6875f023a2 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -751,13 +751,12 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, else setup_frame(ka, regs, sig, oldset); - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } int do_signal32(sigset_t *oldset, struct pt_regs *regs) diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 9421bb98ea6..55d71c15e1f 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -517,13 +517,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall)) return 0; - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); return 1; } diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index f6db3b385fe..e6fa1d1cc03 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -911,6 +911,7 @@ config PPCBUG_NVRAM default y if PPC_PREP config SMP + depends on PPC_STD_MMU bool "Symmetric multi-processing support" ---help--- This enables support for systems with more than one CPU. If you have @@ -930,7 +931,7 @@ config SMP config IRQ_ALL_CPUS bool "Distribute interrupts on all CPUs by default" - depends on SMP + depends on SMP && !MV64360 help This option gives the kernel permission to distribute IRQs across multiple CPUs. Saying N here will route all IRQs to the first @@ -1121,7 +1122,9 @@ config PROC_HARDWARE source "drivers/zorro/Kconfig" +if !44x || BROKEN source kernel/power/Kconfig +endif config SECCOMP bool "Enable seccomp to safely compute untrusted bytecode" diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 8aaeb6f4e75..2244bf91e59 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -759,13 +759,12 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) else handle_signal(signr, &ka, &info, oldset, regs, newsp); - if (!(ka.sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka.sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka.sa.sa_mask); + if (!(ka.sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked, signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); return 1; } diff --git a/arch/ppc/platforms/4xx/Kconfig b/arch/ppc/platforms/4xx/Kconfig index f7c045764e0..805dd98908a 100644 --- a/arch/ppc/platforms/4xx/Kconfig +++ b/arch/ppc/platforms/4xx/Kconfig @@ -3,6 +3,11 @@ config 4xx depends on 40x || 44x default y +config WANT_EARLY_SERIAL + bool + select SERIAL_8250 + default n + menu "IBM 4xx options" depends on 4xx @@ -18,6 +23,7 @@ config ASH config BUBINGA bool "Bubinga" + select WANT_EARLY_SERIAL help This option enables support for the IBM 405EP evaluation board. @@ -70,21 +76,25 @@ choice config BAMBOO bool "Bamboo" + select WANT_EARLY_SERIAL help This option enables support for the IBM PPC440EP evaluation board. config EBONY bool "Ebony" + select WANT_EARLY_SERIAL help This option enables support for the IBM PPC440GP evaluation board. config LUAN bool "Luan" + select WANT_EARLY_SERIAL help This option enables support for the IBM PPC440SP evaluation board. config OCOTEA bool "Ocotea" + select WANT_EARLY_SERIAL help This option enables support for the IBM PPC440GX evaluation board. @@ -230,10 +240,6 @@ config PPC_GEN550 depends on 4xx default y -config PM - bool "Power Management support (EXPERIMENTAL)" - depends on 4xx && EXPERIMENTAL - choice prompt "TTYS0 device and default console" depends on 40x diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c index 55a381af4e3..a3702cfe8f7 100644 --- a/arch/ppc/syslib/m8xx_setup.c +++ b/arch/ppc/syslib/m8xx_setup.c @@ -423,7 +423,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.find_end_of_memory = m8xx_find_end_of_memory; ppc_md.setup_io_mappings = m8xx_map_io; -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +#if defined(CONFIG_BLK_DEV_MPC8xx_IDE) m8xx_ide_init(); #endif } diff --git a/arch/ppc/syslib/ppc4xx_dma.c b/arch/ppc/syslib/ppc4xx_dma.c index 5015ab99afd..f15e64285f9 100644 --- a/arch/ppc/syslib/ppc4xx_dma.c +++ b/arch/ppc/syslib/ppc4xx_dma.c @@ -620,6 +620,7 @@ ppc4xx_clr_dma_status(unsigned int dmanr) return DMA_STATUS_GOOD; } +#ifdef CONFIG_PPC4xx_EDMA /* * Enables the burst on the channel (BTEN bit in the control/count register) * Note: @@ -685,6 +686,11 @@ ppc4xx_set_burst_size(unsigned int dmanr, unsigned int bsize) return DMA_STATUS_GOOD; } +EXPORT_SYMBOL(ppc4xx_enable_burst); +EXPORT_SYMBOL(ppc4xx_disable_burst); +EXPORT_SYMBOL(ppc4xx_set_burst_size); +#endif /* CONFIG_PPC4xx_EDMA */ + EXPORT_SYMBOL(ppc4xx_init_dma_channel); EXPORT_SYMBOL(ppc4xx_get_channel_config); EXPORT_SYMBOL(ppc4xx_set_channel_priority); @@ -703,6 +709,4 @@ EXPORT_SYMBOL(ppc4xx_enable_dma_interrupt); EXPORT_SYMBOL(ppc4xx_disable_dma_interrupt); EXPORT_SYMBOL(ppc4xx_get_dma_status); EXPORT_SYMBOL(ppc4xx_clr_dma_status); -EXPORT_SYMBOL(ppc4xx_enable_burst); -EXPORT_SYMBOL(ppc4xx_disable_burst); -EXPORT_SYMBOL(ppc4xx_set_burst_size); + diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index 687e8559520..e9c24d2dbd9 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -706,6 +706,8 @@ void machine_power_off(void) local_irq_disable(); while (1) ; } +/* Used by the G5 thermal driver */ +EXPORT_SYMBOL_GPL(machine_power_off); void machine_halt(void) { diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c index bf782276984..49a79a55c32 100644 --- a/arch/ppc64/kernel/signal.c +++ b/arch/ppc64/kernel/signal.c @@ -481,10 +481,11 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, /* Set up Signal Frame */ ret = setup_rt_frame(sig, ka, info, oldset, regs); - if (ret && !(ka->sa.sa_flags & SA_NODEFER)) { + if (ret) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); - sigaddset(¤t->blocked,sig); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); } diff --git a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c index 3c2fa5c284c..46f4d6cc7fc 100644 --- a/arch/ppc64/kernel/signal32.c +++ b/arch/ppc64/kernel/signal32.c @@ -976,11 +976,12 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs) else ret = handle_signal32(signr, &ka, &info, oldset, regs, newsp); - if (ret && !(ka.sa.sa_flags & SA_NODEFER)) { + if (ret) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked, ¤t->blocked, &ka.sa.sa_mask); - sigaddset(¤t->blocked, signr); + if (!(ka.sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked, signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); } diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index d05d65ac969..7358cdb8441 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -637,12 +637,11 @@ handle_signal32(unsigned long sig, struct k_sigaction *ka, else setup_frame32(sig, ka, oldset, regs); - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 20062145e84..d47fecb42cc 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -46,9 +46,9 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) "lra 3,0(%4)\n" "lr 5,%5\n" "diag 2,4,0x8\n" - "brc 8, .Litfits\n" + "brc 8, 1f\n" "ar 5, %5\n" - ".Litfits: \n" + "1: \n" "lr %0,4\n" "lr %1,5\n" : "=d" (return_code), "=d" (return_len) @@ -64,9 +64,9 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) "sam31\n" "diag 2,4,0x8\n" "sam64\n" - "brc 8, .Litfits\n" + "brc 8, 1f\n" "agr 5, %5\n" - ".Litfits: \n" + "1: \n" "lgr %0,4\n" "lgr %1,5\n" : "=d" (return_code), "=d" (return_len) diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 610c1d03e97..6a3f5b7473a 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -429,13 +429,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, else setup_frame(sig, ka, oldset, regs); - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } /* diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S index 6615e4838ee..fb6368159dd 100644 --- a/arch/sh/kernel/entry.S +++ b/arch/sh/kernel/entry.S @@ -1145,5 +1145,10 @@ ENTRY(sys_call_table) .long sys_add_key /* 285 */ .long sys_request_key .long sys_keyctl + .long sys_ioprio_set + .long sys_ioprio_get + .long sys_inotify_init /* 290 */ + .long sys_inotify_add_watch + .long sys_inotify_rm_watch /* End of entry.S */ diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index 8022243f017..b475c4d2405 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c @@ -546,13 +546,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } /* diff --git a/arch/sh64/kernel/signal.c b/arch/sh64/kernel/signal.c index c6a14a87c59..3ea8929e483 100644 --- a/arch/sh64/kernel/signal.c +++ b/arch/sh64/kernel/signal.c @@ -664,13 +664,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, else setup_frame(sig, ka, oldset, regs); - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } /* diff --git a/arch/sh64/kernel/syscalls.S b/arch/sh64/kernel/syscalls.S index 6aabc63e451..a3d037805f1 100644 --- a/arch/sh64/kernel/syscalls.S +++ b/arch/sh64/kernel/syscalls.S @@ -342,4 +342,9 @@ sys_call_table: .long sys_add_key .long sys_request_key .long sys_keyctl /* 315 */ + .long sys_ioprio_set + .long sys_ioprio_get + .long sys_inotify_init + .long sys_inotify_add_watch + .long sys_inotify_rm_watch /* 320 */ diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 011ff35057a..5f34d7dc2b8 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c @@ -1034,13 +1034,12 @@ handle_signal(unsigned long signr, struct k_sigaction *ka, else setup_frame(&ka->sa, regs, signr, oldset, info); } - if (!(ka->sa.sa_flags & SA_NOMASK)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NOMASK)) sigaddset(¤t->blocked, signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 1bd430d0ca0..8faa8dc4de4 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -98,8 +98,9 @@ extern void ___rw_write_enter(void); * The module references will be fixed up by module_frob_arch_sections. */ #define DOT_ALIAS2(__ret, __x, __arg1, __arg2) \ - extern __ret __x(__arg1, __arg2) \ - __attribute__((weak, alias("." # __x))); + extern __ret __x(__arg1, __arg2); \ + asm(".weak " #__x);\ + asm(#__x "=." #__x); DOT_ALIAS2(int, div, int, int) DOT_ALIAS2(int, mul, int, int) diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 093281bdf85..6f00ab8b9d2 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -8,7 +8,7 @@ EXTRA_CFLAGS := -Werror extra-y := head.o init_task.o vmlinux.lds obj-y := process.o setup.o cpu.o idprom.o \ - traps.o devices.o auxio.o \ + traps.o devices.o auxio.o una_asm.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o central.o pci.o starfire.o semaphore.o \ power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index bba140d98b1..f21c993f885 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -540,6 +540,7 @@ void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res, pbm->parent->resource_adjust(pdev, res, root); } +EXPORT_SYMBOL(pcibios_bus_to_resource); char * __init pcibios_setup(char *str) { diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index b27934671c3..60f5dfabb1e 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -574,13 +574,12 @@ static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, { setup_rt_frame(ka, regs, signr, oldset, (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL); - if (!(ka->sa.sa_flags & SA_NOMASK)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NOMASK)) sigaddset(¤t->blocked,signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index f28428f4170..b1ed23091fb 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -1325,13 +1325,12 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, else setup_frame32(&ka->sa, regs, signr, oldset, info); } - if (!(ka->sa.sa_flags & SA_NOMASK)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NOMASK)) sigaddset(¤t->blocked,signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs, diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 100b0107c4b..0c9e54b2f0c 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -2127,6 +2127,9 @@ void __init trap_init(void) TI_PRE_COUNT != offsetof(struct thread_info, preempt_count) || TI_NEW_CHILD != offsetof(struct thread_info, new_child) || TI_SYS_NOERROR != offsetof(struct thread_info, syscall_noerror) || + TI_RESTART_BLOCK != offsetof(struct thread_info, restart_block) || + TI_KUNA_REGS != offsetof(struct thread_info, kern_una_regs) || + TI_KUNA_INSN != offsetof(struct thread_info, kern_una_insn) || TI_FPREGS != offsetof(struct thread_info, fpregs) || (TI_FPREGS & (64 - 1))) thread_info_offsets_are_bolixed_dave(); diff --git a/arch/sparc64/kernel/una_asm.S b/arch/sparc64/kernel/una_asm.S new file mode 100644 index 00000000000..cbb40585253 --- /dev/null +++ b/arch/sparc64/kernel/una_asm.S @@ -0,0 +1,153 @@ +/* una_asm.S: Kernel unaligned trap assembler helpers. + * + * Copyright (C) 1996,2005 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + + .text + +kernel_unaligned_trap_fault: + call kernel_mna_trap_fault + nop + retl + nop + .size kern_unaligned_trap_fault, .-kern_unaligned_trap_fault + + .globl __do_int_store +__do_int_store: + rd %asi, %o4 + wr %o3, 0, %asi + ldx [%o2], %g3 + cmp %o1, 2 + be,pn %icc, 2f + cmp %o1, 4 + be,pt %icc, 1f + srlx %g3, 24, %g2 + srlx %g3, 56, %g1 + srlx %g3, 48, %g7 +4: stba %g1, [%o0] %asi + srlx %g3, 40, %g1 +5: stba %g7, [%o0 + 1] %asi + srlx %g3, 32, %g7 +6: stba %g1, [%o0 + 2] %asi +7: stba %g7, [%o0 + 3] %asi + srlx %g3, 16, %g1 +8: stba %g2, [%o0 + 4] %asi + srlx %g3, 8, %g7 +9: stba %g1, [%o0 + 5] %asi +10: stba %g7, [%o0 + 6] %asi + ba,pt %xcc, 0f +11: stba %g3, [%o0 + 7] %asi +1: srl %g3, 16, %g7 +12: stba %g2, [%o0] %asi + srl %g3, 8, %g2 +13: stba %g7, [%o0 + 1] %asi +14: stba %g2, [%o0 + 2] %asi + ba,pt %xcc, 0f +15: stba %g3, [%o0 + 3] %asi +2: srl %g3, 8, %g2 +16: stba %g2, [%o0] %asi +17: stba %g3, [%o0 + 1] %asi +0: + wr %o4, 0x0, %asi + retl + nop + .size __do_int_store, .-__do_int_store + + .section __ex_table + .word 4b, kernel_unaligned_trap_fault + .word 5b, kernel_unaligned_trap_fault + .word 6b, kernel_unaligned_trap_fault + .word 7b, kernel_unaligned_trap_fault + .word 8b, kernel_unaligned_trap_fault + .word 9b, kernel_unaligned_trap_fault + .word 10b, kernel_unaligned_trap_fault + .word 11b, kernel_unaligned_trap_fault + .word 12b, kernel_unaligned_trap_fault + .word 13b, kernel_unaligned_trap_fault + .word 14b, kernel_unaligned_trap_fault + .word 15b, kernel_unaligned_trap_fault + .word 16b, kernel_unaligned_trap_fault + .word 17b, kernel_unaligned_trap_fault + .previous + + .globl do_int_load +do_int_load: + rd %asi, %o5 + wr %o4, 0, %asi + cmp %o1, 8 + bge,pn %icc, 9f + cmp %o1, 4 + be,pt %icc, 6f +4: lduba [%o2] %asi, %g2 +5: lduba [%o2 + 1] %asi, %g3 + sll %g2, 8, %g2 + brz,pt %o3, 3f + add %g2, %g3, %g2 + sllx %g2, 48, %g2 + srax %g2, 48, %g2 +3: ba,pt %xcc, 0f + stx %g2, [%o0] +6: lduba [%o2 + 1] %asi, %g3 + sll %g2, 24, %g2 +7: lduba [%o2 + 2] %asi, %g7 + sll %g3, 16, %g3 +8: lduba [%o2 + 3] %asi, %g1 + sll %g7, 8, %g7 + or %g2, %g3, %g2 + or %g7, %g1, %g7 + or %g2, %g7, %g2 + brnz,a,pt %o3, 3f + sra %g2, 0, %g2 +3: ba,pt %xcc, 0f + stx %g2, [%o0] +9: lduba [%o2] %asi, %g2 +10: lduba [%o2 + 1] %asi, %g3 + sllx %g2, 56, %g2 +11: lduba [%o2 + 2] %asi, %g7 + sllx %g3, 48, %g3 +12: lduba [%o2 + 3] %asi, %g1 + sllx %g7, 40, %g7 + sllx %g1, 32, %g1 + or %g2, %g3, %g2 + or %g7, %g1, %g7 +13: lduba [%o2 + 4] %asi, %g3 + or %g2, %g7, %g7 +14: lduba [%o2 + 5] %asi, %g1 + sllx %g3, 24, %g3 +15: lduba [%o2 + 6] %asi, %g2 + sllx %g1, 16, %g1 + or %g7, %g3, %g7 +16: lduba [%o2 + 7] %asi, %g3 + sllx %g2, 8, %g2 + or %g7, %g1, %g7 + or %g2, %g3, %g2 + or %g7, %g2, %g7 + cmp %o1, 8 + be,a,pt %icc, 0f + stx %g7, [%o0] + srlx %g7, 32, %g2 + sra %g7, 0, %g7 + stx %g2, [%o0] + stx %g7, [%o0 + 8] +0: + wr %o5, 0x0, %asi + retl + nop + .size __do_int_load, .-__do_int_load + + .section __ex_table + .word 4b, kernel_unaligned_trap_fault + .word 5b, kernel_unaligned_trap_fault + .word 6b, kernel_unaligned_trap_fault + .word 7b, kernel_unaligned_trap_fault + .word 8b, kernel_unaligned_trap_fault + .word 9b, kernel_unaligned_trap_fault + .word 10b, kernel_unaligned_trap_fault + .word 11b, kernel_unaligned_trap_fault + .word 12b, kernel_unaligned_trap_fault + .word 13b, kernel_unaligned_trap_fault + .word 14b, kernel_unaligned_trap_fault + .word 15b, kernel_unaligned_trap_fault + .word 16b, kernel_unaligned_trap_fault + .previous diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index 4372bf32ecf..11c3e88732e 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c @@ -180,169 +180,28 @@ static void __attribute_used__ unaligned_panic(char *str, struct pt_regs *regs) die_if_kernel(str, regs); } -#define do_integer_load(dest_reg, size, saddr, is_signed, asi, errh) ({ \ -__asm__ __volatile__ ( \ - "wr %4, 0, %%asi\n\t" \ - "cmp %1, 8\n\t" \ - "bge,pn %%icc, 9f\n\t" \ - " cmp %1, 4\n\t" \ - "be,pt %%icc, 6f\n" \ -"4:\t" " lduba [%2] %%asi, %%l1\n" \ -"5:\t" "lduba [%2 + 1] %%asi, %%l2\n\t" \ - "sll %%l1, 8, %%l1\n\t" \ - "brz,pt %3, 3f\n\t" \ - " add %%l1, %%l2, %%l1\n\t" \ - "sllx %%l1, 48, %%l1\n\t" \ - "srax %%l1, 48, %%l1\n" \ -"3:\t" "ba,pt %%xcc, 0f\n\t" \ - " stx %%l1, [%0]\n" \ -"6:\t" "lduba [%2 + 1] %%asi, %%l2\n\t" \ - "sll %%l1, 24, %%l1\n" \ -"7:\t" "lduba [%2 + 2] %%asi, %%g7\n\t" \ - "sll %%l2, 16, %%l2\n" \ -"8:\t" "lduba [%2 + 3] %%asi, %%g1\n\t" \ - "sll %%g7, 8, %%g7\n\t" \ - "or %%l1, %%l2, %%l1\n\t" \ - "or %%g7, %%g1, %%g7\n\t" \ - "or %%l1, %%g7, %%l1\n\t" \ - "brnz,a,pt %3, 3f\n\t" \ - " sra %%l1, 0, %%l1\n" \ -"3:\t" "ba,pt %%xcc, 0f\n\t" \ - " stx %%l1, [%0]\n" \ -"9:\t" "lduba [%2] %%asi, %%l1\n" \ -"10:\t" "lduba [%2 + 1] %%asi, %%l2\n\t" \ - "sllx %%l1, 56, %%l1\n" \ -"11:\t" "lduba [%2 + 2] %%asi, %%g7\n\t" \ - "sllx %%l2, 48, %%l2\n" \ -"12:\t" "lduba [%2 + 3] %%asi, %%g1\n\t" \ - "sllx %%g7, 40, %%g7\n\t" \ - "sllx %%g1, 32, %%g1\n\t" \ - "or %%l1, %%l2, %%l1\n\t" \ - "or %%g7, %%g1, %%g7\n" \ -"13:\t" "lduba [%2 + 4] %%asi, %%l2\n\t" \ - "or %%l1, %%g7, %%g7\n" \ -"14:\t" "lduba [%2 + 5] %%asi, %%g1\n\t" \ - "sllx %%l2, 24, %%l2\n" \ -"15:\t" "lduba [%2 + 6] %%asi, %%l1\n\t" \ - "sllx %%g1, 16, %%g1\n\t" \ - "or %%g7, %%l2, %%g7\n" \ -"16:\t" "lduba [%2 + 7] %%asi, %%l2\n\t" \ - "sllx %%l1, 8, %%l1\n\t" \ - "or %%g7, %%g1, %%g7\n\t" \ - "or %%l1, %%l2, %%l1\n\t" \ - "or %%g7, %%l1, %%g7\n\t" \ - "cmp %1, 8\n\t" \ - "be,a,pt %%icc, 0f\n\t" \ - " stx %%g7, [%0]\n\t" \ - "srlx %%g7, 32, %%l1\n\t" \ - "sra %%g7, 0, %%g7\n\t" \ - "stx %%l1, [%0]\n\t" \ - "stx %%g7, [%0 + 8]\n" \ -"0:\n\t" \ - "wr %%g0, %5, %%asi\n\n\t" \ - ".section __ex_table\n\t" \ - ".word 4b, " #errh "\n\t" \ - ".word 5b, " #errh "\n\t" \ - ".word 6b, " #errh "\n\t" \ - ".word 7b, " #errh "\n\t" \ - ".word 8b, " #errh "\n\t" \ - ".word 9b, " #errh "\n\t" \ - ".word 10b, " #errh "\n\t" \ - ".word 11b, " #errh "\n\t" \ - ".word 12b, " #errh "\n\t" \ - ".word 13b, " #errh "\n\t" \ - ".word 14b, " #errh "\n\t" \ - ".word 15b, " #errh "\n\t" \ - ".word 16b, " #errh "\n\n\t" \ - ".previous\n\t" \ - : : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed), \ - "r" (asi), "i" (ASI_AIUS) \ - : "l1", "l2", "g7", "g1", "cc"); \ -}) +extern void do_int_load(unsigned long *dest_reg, int size, + unsigned long *saddr, int is_signed, int asi); -#define store_common(dst_addr, size, src_val, asi, errh) ({ \ -__asm__ __volatile__ ( \ - "wr %3, 0, %%asi\n\t" \ - "ldx [%2], %%l1\n" \ - "cmp %1, 2\n\t" \ - "be,pn %%icc, 2f\n\t" \ - " cmp %1, 4\n\t" \ - "be,pt %%icc, 1f\n\t" \ - " srlx %%l1, 24, %%l2\n\t" \ - "srlx %%l1, 56, %%g1\n\t" \ - "srlx %%l1, 48, %%g7\n" \ -"4:\t" "stba %%g1, [%0] %%asi\n\t" \ - "srlx %%l1, 40, %%g1\n" \ -"5:\t" "stba %%g7, [%0 + 1] %%asi\n\t" \ - "srlx %%l1, 32, %%g7\n" \ -"6:\t" "stba %%g1, [%0 + 2] %%asi\n" \ -"7:\t" "stba %%g7, [%0 + 3] %%asi\n\t" \ - "srlx %%l1, 16, %%g1\n" \ -"8:\t" "stba %%l2, [%0 + 4] %%asi\n\t" \ - "srlx %%l1, 8, %%g7\n" \ -"9:\t" "stba %%g1, [%0 + 5] %%asi\n" \ -"10:\t" "stba %%g7, [%0 + 6] %%asi\n\t" \ - "ba,pt %%xcc, 0f\n" \ -"11:\t" " stba %%l1, [%0 + 7] %%asi\n" \ -"1:\t" "srl %%l1, 16, %%g7\n" \ -"12:\t" "stba %%l2, [%0] %%asi\n\t" \ - "srl %%l1, 8, %%l2\n" \ -"13:\t" "stba %%g7, [%0 + 1] %%asi\n" \ -"14:\t" "stba %%l2, [%0 + 2] %%asi\n\t" \ - "ba,pt %%xcc, 0f\n" \ -"15:\t" " stba %%l1, [%0 + 3] %%asi\n" \ -"2:\t" "srl %%l1, 8, %%l2\n" \ -"16:\t" "stba %%l2, [%0] %%asi\n" \ -"17:\t" "stba %%l1, [%0 + 1] %%asi\n" \ -"0:\n\t" \ - "wr %%g0, %4, %%asi\n\n\t" \ - ".section __ex_table\n\t" \ - ".word 4b, " #errh "\n\t" \ - ".word 5b, " #errh "\n\t" \ - ".word 6b, " #errh "\n\t" \ - ".word 7b, " #errh "\n\t" \ - ".word 8b, " #errh "\n\t" \ - ".word 9b, " #errh "\n\t" \ - ".word 10b, " #errh "\n\t" \ - ".word 11b, " #errh "\n\t" \ - ".word 12b, " #errh "\n\t" \ - ".word 13b, " #errh "\n\t" \ - ".word 14b, " #errh "\n\t" \ - ".word 15b, " #errh "\n\t" \ - ".word 16b, " #errh "\n\t" \ - ".word 17b, " #errh "\n\n\t" \ - ".previous\n\t" \ - : : "r" (dst_addr), "r" (size), "r" (src_val), "r" (asi), "i" (ASI_AIUS)\ - : "l1", "l2", "g7", "g1", "cc"); \ -}) - -#define do_integer_store(reg_num, size, dst_addr, regs, asi, errh) ({ \ - unsigned long zero = 0; \ - unsigned long *src_val = &zero; \ - \ - if (size == 16) { \ - size = 8; \ - zero = (((long)(reg_num ? \ - (unsigned)fetch_reg(reg_num, regs) : 0)) << 32) | \ - (unsigned)fetch_reg(reg_num + 1, regs); \ - } else if (reg_num) src_val = fetch_reg_addr(reg_num, regs); \ - store_common(dst_addr, size, src_val, asi, errh); \ -}) - -extern void smp_capture(void); -extern void smp_release(void); - -#define do_atomic(srcdest_reg, mem, errh) ({ \ - unsigned long flags, tmp; \ - \ - smp_capture(); \ - local_irq_save(flags); \ - tmp = *srcdest_reg; \ - do_integer_load(srcdest_reg, 4, mem, 0, errh); \ - store_common(mem, 4, &tmp, errh); \ - local_irq_restore(flags); \ - smp_release(); \ -}) +extern void __do_int_store(unsigned long *dst_addr, int size, + unsigned long *src_val, int asi); + +static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr, + struct pt_regs *regs, int asi) +{ + unsigned long zero = 0; + unsigned long *src_val = &zero; + + if (size == 16) { + size = 8; + zero = (((long)(reg_num ? + (unsigned)fetch_reg(reg_num, regs) : 0)) << 32) | + (unsigned)fetch_reg(reg_num + 1, regs); + } else if (reg_num) { + src_val = fetch_reg_addr(reg_num, regs); + } + __do_int_store(dst_addr, size, src_val, asi); +} static inline void advance(struct pt_regs *regs) { @@ -364,24 +223,29 @@ static inline int ok_for_kernel(unsigned int insn) return !floating_point_load_or_store_p(insn); } -void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("kernel_mna_trap_fault"); - -void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) +void kernel_mna_trap_fault(void) { - unsigned long g2 = regs->u_regs [UREG_G2]; + struct pt_regs *regs = current_thread_info()->kern_una_regs; + unsigned int insn = current_thread_info()->kern_una_insn; + unsigned long g2 = regs->u_regs[UREG_G2]; unsigned long fixup = search_extables_range(regs->tpc, &g2); if (!fixup) { - unsigned long address = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f)); + unsigned long address; + + address = compute_effective_address(regs, insn, + ((insn >> 25) & 0x1f)); if (address < PAGE_SIZE) { - printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler"); + printk(KERN_ALERT "Unable to handle kernel NULL " + "pointer dereference in mna handler"); } else - printk(KERN_ALERT "Unable to handle kernel paging request in mna handler"); + printk(KERN_ALERT "Unable to handle kernel paging " + "request in mna handler"); printk(KERN_ALERT " at virtual address %016lx\n",address); - printk(KERN_ALERT "current->{mm,active_mm}->context = %016lx\n", + printk(KERN_ALERT "current->{active_,}mm->context = %016lx\n", (current->mm ? CTX_HWBITS(current->mm->context) : CTX_HWBITS(current->active_mm->context))); - printk(KERN_ALERT "current->{mm,active_mm}->pgd = %016lx\n", + printk(KERN_ALERT "current->{active_,}mm->pgd = %016lx\n", (current->mm ? (unsigned long) current->mm->pgd : (unsigned long) current->active_mm->pgd)); die_if_kernel("Oops", regs); @@ -400,48 +264,41 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u enum direction dir = decode_direction(insn); int size = decode_access_size(insn); + current_thread_info()->kern_una_regs = regs; + current_thread_info()->kern_una_insn = insn; + if (!ok_for_kernel(insn) || dir == both) { - printk("Unsupported unaligned load/store trap for kernel at <%016lx>.\n", - regs->tpc); - unaligned_panic("Kernel does fpu/atomic unaligned load/store.", regs); - - __asm__ __volatile__ ("\n" -"kernel_unaligned_trap_fault:\n\t" - "mov %0, %%o0\n\t" - "call kernel_mna_trap_fault\n\t" - " mov %1, %%o1\n\t" - : - : "r" (regs), "r" (insn) - : "o0", "o1", "o2", "o3", "o4", "o5", "o7", - "g1", "g2", "g3", "g4", "g7", "cc"); + printk("Unsupported unaligned load/store trap for kernel " + "at <%016lx>.\n", regs->tpc); + unaligned_panic("Kernel does fpu/atomic " + "unaligned load/store.", regs); + + kernel_mna_trap_fault(); } else { - unsigned long addr = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f)); + unsigned long addr; + addr = compute_effective_address(regs, insn, + ((insn >> 25) & 0x1f)); #ifdef DEBUG_MNA - printk("KMNA: pc=%016lx [dir=%s addr=%016lx size=%d] retpc[%016lx]\n", - regs->tpc, dirstrings[dir], addr, size, regs->u_regs[UREG_RETPC]); + printk("KMNA: pc=%016lx [dir=%s addr=%016lx size=%d] " + "retpc[%016lx]\n", + regs->tpc, dirstrings[dir], addr, size, + regs->u_regs[UREG_RETPC]); #endif switch (dir) { case load: - do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs), - size, (unsigned long *) addr, - decode_signedness(insn), decode_asi(insn, regs), - kernel_unaligned_trap_fault); + do_int_load(fetch_reg_addr(((insn>>25)&0x1f), regs), + size, (unsigned long *) addr, + decode_signedness(insn), + decode_asi(insn, regs)); break; case store: - do_integer_store(((insn>>25)&0x1f), size, - (unsigned long *) addr, regs, - decode_asi(insn, regs), - kernel_unaligned_trap_fault); - break; -#if 0 /* unsupported */ - case both: - do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs), - (unsigned long *) addr, - kernel_unaligned_trap_fault); + do_int_store(((insn>>25)&0x1f), size, + (unsigned long *) addr, regs, + decode_asi(insn, regs)); break; -#endif + default: panic("Impossible kernel unaligned trap."); /* Not reached... */ diff --git a/arch/sparc64/kernel/us2e_cpufreq.c b/arch/sparc64/kernel/us2e_cpufreq.c index 7aae0a18aab..686e526bec0 100644 --- a/arch/sparc64/kernel/us2e_cpufreq.c +++ b/arch/sparc64/kernel/us2e_cpufreq.c @@ -88,7 +88,6 @@ static void frob_mem_refresh(int cpu_slowing_down, { unsigned long old_refr_count, refr_count, mctrl; - refr_count = (clock_tick * MCTRL0_REFR_INTERVAL); refr_count /= (MCTRL0_REFR_CLKS_P_CNT * divisor * 1000000000UL); @@ -230,6 +229,25 @@ static unsigned long estar_to_divisor(unsigned long estar) return ret; } +static unsigned int us2e_freq_get(unsigned int cpu) +{ + cpumask_t cpus_allowed; + unsigned long clock_tick, estar; + + if (!cpu_online(cpu)) + return 0; + + cpus_allowed = current->cpus_allowed; + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + + clock_tick = sparc64_get_clock_tick(cpu) / 1000; + estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR); + + set_cpus_allowed(current, cpus_allowed); + + return clock_tick / estar_to_divisor(estar); +} + static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index) { unsigned long new_bits, new_freq; @@ -243,7 +261,7 @@ static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index) cpus_allowed = current->cpus_allowed; set_cpus_allowed(current, cpumask_of_cpu(cpu)); - new_freq = clock_tick = sparc64_get_clock_tick(cpu); + new_freq = clock_tick = sparc64_get_clock_tick(cpu) / 1000; new_bits = index_to_estar_mode(index); divisor = index_to_divisor(index); new_freq /= divisor; @@ -258,7 +276,8 @@ static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index) cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); if (old_divisor != divisor) - us2e_transition(estar, new_bits, clock_tick, old_divisor, divisor); + us2e_transition(estar, new_bits, clock_tick * 1000, + old_divisor, divisor); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); @@ -272,10 +291,8 @@ static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int new_index = 0; if (cpufreq_frequency_table_target(policy, - &us2e_freq_table[policy->cpu].table[0], - target_freq, - relation, - &new_index)) + &us2e_freq_table[policy->cpu].table[0], + target_freq, relation, &new_index)) return -EINVAL; us2e_set_cpu_divider_index(policy->cpu, new_index); @@ -292,7 +309,7 @@ static int us2e_freq_verify(struct cpufreq_policy *policy) static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy) { unsigned int cpu = policy->cpu; - unsigned long clock_tick = sparc64_get_clock_tick(cpu); + unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000; struct cpufreq_frequency_table *table = &us2e_freq_table[cpu].table[0]; @@ -351,9 +368,10 @@ static int __init us2e_freq_init(void) memset(us2e_freq_table, 0, (NR_CPUS * sizeof(struct us2e_freq_percpu_info))); + driver->init = us2e_freq_cpu_init; driver->verify = us2e_freq_verify; driver->target = us2e_freq_target; - driver->init = us2e_freq_cpu_init; + driver->get = us2e_freq_get; driver->exit = us2e_freq_cpu_exit; driver->owner = THIS_MODULE, strcpy(driver->name, "UltraSPARC-IIe"); diff --git a/arch/sparc64/kernel/us3_cpufreq.c b/arch/sparc64/kernel/us3_cpufreq.c index 18fe54b8aa5..9080e7cd4bb 100644 --- a/arch/sparc64/kernel/us3_cpufreq.c +++ b/arch/sparc64/kernel/us3_cpufreq.c @@ -56,7 +56,7 @@ static void write_safari_cfg(unsigned long val) static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg) { - unsigned long clock_tick = sparc64_get_clock_tick(cpu); + unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000; unsigned long ret; switch (safari_cfg & SAFARI_CFG_DIV_MASK) { @@ -76,6 +76,26 @@ static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg return ret; } +static unsigned int us3_freq_get(unsigned int cpu) +{ + cpumask_t cpus_allowed; + unsigned long reg; + unsigned int ret; + + if (!cpu_online(cpu)) + return 0; + + cpus_allowed = current->cpus_allowed; + set_cpus_allowed(current, cpumask_of_cpu(cpu)); + + reg = read_safari_cfg(); + ret = get_current_freq(cpu, reg); + + set_cpus_allowed(current, cpus_allowed); + + return ret; +} + static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) { unsigned long new_bits, new_freq, reg; @@ -88,7 +108,7 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) cpus_allowed = current->cpus_allowed; set_cpus_allowed(current, cpumask_of_cpu(cpu)); - new_freq = sparc64_get_clock_tick(cpu); + new_freq = sparc64_get_clock_tick(cpu) / 1000; switch (index) { case 0: new_bits = SAFARI_CFG_DIV_1; @@ -150,7 +170,7 @@ static int us3_freq_verify(struct cpufreq_policy *policy) static int __init us3_freq_cpu_init(struct cpufreq_policy *policy) { unsigned int cpu = policy->cpu; - unsigned long clock_tick = sparc64_get_clock_tick(cpu); + unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000; struct cpufreq_frequency_table *table = &us3_freq_table[cpu].table[0]; @@ -206,9 +226,10 @@ static int __init us3_freq_init(void) memset(us3_freq_table, 0, (NR_CPUS * sizeof(struct us3_freq_percpu_info))); + driver->init = us3_freq_cpu_init; driver->verify = us3_freq_verify; driver->target = us3_freq_target; - driver->init = us3_freq_cpu_init; + driver->get = us3_freq_get; driver->exit = us3_freq_cpu_exit; driver->owner = THIS_MODULE, strcpy(driver->name, "UltraSPARC-III"); diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c index a37a5ac13c2..022f67bb687 100644 --- a/arch/um/drivers/mmapper_kern.c +++ b/arch/um/drivers/mmapper_kern.c @@ -9,19 +9,11 @@ * */ -#include <linux/types.h> -#include <linux/kdev_t.h> -#include <linux/time.h> -#include <linux/devfs_fs_kernel.h> +#include <linux/init.h> #include <linux/module.h> #include <linux/mm.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/smp_lock.h> #include <linux/miscdevice.h> #include <asm/uaccess.h> -#include <asm/irq.h> -#include <asm/pgtable.h> #include "mem_user.h" #include "user_util.h" @@ -31,35 +23,22 @@ static unsigned long p_buf = 0; static char *v_buf = NULL; static ssize_t -mmapper_read(struct file *file, char *buf, size_t count, loff_t *ppos) +mmapper_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - if(*ppos > mmapper_size) - return -EINVAL; - - if(count + *ppos > mmapper_size) - count = count + *ppos - mmapper_size; - - if(count < 0) - return -EINVAL; - - copy_to_user(buf,&v_buf[*ppos],count); - - return count; + return simple_read_from_buffer(buf, count, ppos, v_buf, mmapper_size); } static ssize_t -mmapper_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +mmapper_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - if(*ppos > mmapper_size) + if (*ppos > mmapper_size) return -EINVAL; - if(count + *ppos > mmapper_size) - count = count + *ppos - mmapper_size; - - if(count < 0) - return -EINVAL; + if (count > mmapper_size - *ppos) + count = mmapper_size - *ppos; - copy_from_user(&v_buf[*ppos],buf,count); + if (copy_from_user(&v_buf[*ppos], buf, count)) + return -EFAULT; return count; } @@ -77,7 +56,6 @@ mmapper_mmap(struct file *file, struct vm_area_struct * vma) int ret = -EINVAL; int size; - lock_kernel(); if (vma->vm_pgoff != 0) goto out; @@ -92,7 +70,6 @@ mmapper_mmap(struct file *file, struct vm_area_struct * vma) goto out; ret = 0; out: - unlock_kernel(); return ret; } diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index 7807a3e8c42..03618bd13d5 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c @@ -87,12 +87,12 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr, recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); force_sigsegv(signr, current); - } - else if(!(ka->sa.sa_flags & SA_NODEFER)){ + } else { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); - sigaddset(¤t->blocked, signr); + if(!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked, signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); } diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 6dd9e5bf18e..f228f8b5419 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -61,7 +61,11 @@ void wait_stub_done(int pid, int sig, char * fname) CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); } while((n >= 0) && WIFSTOPPED(status) && - (WSTOPSIG(status) == SIGVTALRM)); + ((WSTOPSIG(status) == SIGVTALRM) || + /* running UML inside a detached screen can cause + * SIGWINCHes + */ + (WSTOPSIG(status) == SIGWINCH))); if((n < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){ diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c index 9416e1c2992..4cca3e9c23f 100644 --- a/arch/um/os-Linux/elf_aux.c +++ b/arch/um/os-Linux/elf_aux.c @@ -9,7 +9,6 @@ */ #include <elf.h> #include <stddef.h> -#include <asm/elf.h> #include "init.h" #include "elf_user.h" #include "mem_user.h" diff --git a/arch/v850/kernel/signal.c b/arch/v850/kernel/signal.c index 37061e32e1a..633e4e1b825 100644 --- a/arch/v850/kernel/signal.c +++ b/arch/v850/kernel/signal.c @@ -462,13 +462,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, else setup_frame(sig, ka, oldset, regs); - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } /* diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig index 776f3c866b7..b97a61e1c71 100644 --- a/arch/x86_64/defconfig +++ b/arch/x86_64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.13-rc3 -# Fri Jul 22 16:47:31 2005 +# Linux kernel version: 2.6.13-rc6-git3 +# Fri Aug 12 16:40:34 2005 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -284,10 +284,6 @@ CONFIG_IPV6=y # Network testing # # CONFIG_NET_PKTGEN is not set -CONFIG_NETPOLL=y -# CONFIG_NETPOLL_RX is not set -# CONFIG_NETPOLL_TRAP is not set -CONFIG_NET_POLL_CONTROLLER=y # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set @@ -463,6 +459,7 @@ CONFIG_AIC79XX_DEBUG_MASK=0 # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set CONFIG_SCSI_SATA=y +# CONFIG_SCSI_SATA_AHCI is not set # CONFIG_SCSI_SATA_SVW is not set CONFIG_SCSI_ATA_PIIX=y # CONFIG_SCSI_SATA_NV is not set @@ -492,6 +489,7 @@ CONFIG_SCSI_QLA2XXX=y # CONFIG_SCSI_QLA2300 is not set # CONFIG_SCSI_QLA2322 is not set # CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA24XX is not set # CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set @@ -512,9 +510,11 @@ CONFIG_BLK_DEV_DM=y # # Fusion MPT device support # -# CONFIG_FUSION is not set -# CONFIG_FUSION_SPI is not set +CONFIG_FUSION=y +CONFIG_FUSION_SPI=y # CONFIG_FUSION_FC is not set +CONFIG_FUSION_MAX_SGE=128 +# CONFIG_FUSION_CTL is not set # # IEEE 1394 (FireWire) support @@ -585,6 +585,7 @@ CONFIG_8139TOO=y # CONFIG_ACENIC is not set # CONFIG_DL2K is not set CONFIG_E1000=y +# CONFIG_E1000_NAPI is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set @@ -624,6 +625,10 @@ CONFIG_S2IO=m # CONFIG_NET_FC is not set # CONFIG_SHAPER is not set CONFIG_NETCONSOLE=y +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y # # ISDN subsystem diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index 6ded3a50dfe..b548dea4e5b 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c @@ -185,6 +185,40 @@ unsigned long __init e820_end_of_ram(void) } /* + * Compute how much memory is missing in a range. + * Unlike the other functions in this file the arguments are in page numbers. + */ +unsigned long __init +e820_hole_size(unsigned long start_pfn, unsigned long end_pfn) +{ + unsigned long ram = 0; + unsigned long start = start_pfn << PAGE_SHIFT; + unsigned long end = end_pfn << PAGE_SHIFT; + int i; + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *ei = &e820.map[i]; + unsigned long last, addr; + + if (ei->type != E820_RAM || + ei->addr+ei->size <= start || + ei->addr >= end) + continue; + + addr = round_up(ei->addr, PAGE_SIZE); + if (addr < start) + addr = start; + + last = round_down(ei->addr + ei->size, PAGE_SIZE); + if (last >= end) + last = end; + + if (last > addr) + ram += last - addr; + } + return ((end - start) - ram) >> PAGE_SHIFT; +} + +/* * Mark e820 reserved areas as busy for the resource manager. */ void __init e820_reserve_resources(void) diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index 98590a989f3..d642fbf3da2 100644 --- a/arch/x86_64/kernel/signal.c +++ b/arch/x86_64/kernel/signal.c @@ -394,10 +394,11 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, #endif ret = setup_rt_frame(sig, ka, info, oldset, regs); - if (ret && !(ka->sa.sa_flags & SA_NODEFER)) { + if (ret) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); - sigaddset(¤t->blocked,sig); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); } diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index b15761ff410..fa25e39fe54 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -492,6 +492,14 @@ void __cpuinit start_secondary(void) */ set_cpu_sibling_map(smp_processor_id()); + /* + * Wait for TSC sync to not schedule things before. + * We still process interrupts, which could see an inconsistent + * time in that window unfortunately. + * Do this here because TSC sync has global unprotected state. + */ + tsc_sync_wait(); + /* * We need to hold call_lock, so there is no inconsistency * between the time smp_call_function() determines number of @@ -509,13 +517,6 @@ void __cpuinit start_secondary(void) per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE; unlock_ipi_call_lock(); - mb(); - - /* Wait for TSC sync to not schedule things before. - We still process interrupts, which could see an inconsistent - time in that window unfortunately. */ - tsc_sync_wait(); - cpu_idle(); } diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index 493819e543a..ca914c3bd49 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -211,9 +211,7 @@ int unhandled_signal(struct task_struct *tsk, int sig) { if (tsk->pid == 1) return 1; - /* Warn for strace, but not for gdb */ - if (!test_ti_thread_flag(tsk->thread_info, TIF_SYSCALL_TRACE) && - (tsk->ptrace & PT_PTRACED)) + if (tsk->ptrace & PT_PTRACED) return 0; return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) || (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL); diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index 72e4b364ed7..aa4a5189ece 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -322,18 +322,26 @@ void zap_low_mappings(void) void __init paging_init(void) { { - unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES]; + unsigned long holes[MAX_NR_ZONES]; unsigned int max_dma; + memset(zones_size, 0, sizeof(zones_size)); + memset(holes, 0, sizeof(holes)); + max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; - if (end_pfn < max_dma) + if (end_pfn < max_dma) { zones_size[ZONE_DMA] = end_pfn; - else { + holes[ZONE_DMA] = e820_hole_size(0, end_pfn); + } else { zones_size[ZONE_DMA] = max_dma; + holes[ZONE_DMA] = e820_hole_size(0, max_dma); zones_size[ZONE_NORMAL] = end_pfn - max_dma; + holes[ZONE_NORMAL] = e820_hole_size(max_dma, end_pfn); } - free_area_init(zones_size); + free_area_init_node(0, NODE_DATA(0), zones_size, + __pa(PAGE_OFFSET) >> PAGE_SHIFT, holes); } return; } diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index 70cb2904a90..6a156f5692a 100644 --- a/arch/x86_64/mm/numa.c +++ b/arch/x86_64/mm/numa.c @@ -126,9 +126,11 @@ void __init setup_node_zones(int nodeid) { unsigned long start_pfn, end_pfn; unsigned long zones[MAX_NR_ZONES]; + unsigned long holes[MAX_NR_ZONES]; unsigned long dma_end_pfn; memset(zones, 0, sizeof(unsigned long) * MAX_NR_ZONES); + memset(holes, 0, sizeof(unsigned long) * MAX_NR_ZONES); start_pfn = node_start_pfn(nodeid); end_pfn = node_end_pfn(nodeid); @@ -139,13 +141,17 @@ void __init setup_node_zones(int nodeid) dma_end_pfn = __pa(MAX_DMA_ADDRESS) >> PAGE_SHIFT; if (start_pfn < dma_end_pfn) { zones[ZONE_DMA] = dma_end_pfn - start_pfn; + holes[ZONE_DMA] = e820_hole_size(start_pfn, dma_end_pfn); zones[ZONE_NORMAL] = end_pfn - dma_end_pfn; + holes[ZONE_NORMAL] = e820_hole_size(dma_end_pfn, end_pfn); + } else { zones[ZONE_NORMAL] = end_pfn - start_pfn; + holes[ZONE_NORMAL] = e820_hole_size(start_pfn, end_pfn); } free_area_init_node(nodeid, NODE_DATA(nodeid), zones, - start_pfn, NULL); + start_pfn, holes); } void __init numa_init_array(void) diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus.c index c2c38b57993..d80c323669e 100644 --- a/arch/x86_64/pci/k8-bus.c +++ b/arch/x86_64/pci/k8-bus.c @@ -47,13 +47,22 @@ fill_mp_bus_to_cpumask(void) * if there are no busses hanging off of the current * ldt link then both the secondary and subordinate * bus number fields are set to 0. + * + * RED-PEN + * This is slightly broken because it assumes + * HT node IDs == Linux node ids, which is not always + * true. However it is probably mostly true. */ if (!(SECONDARY_LDT_BUS_NUMBER(ldtbus) == 0 && SUBORDINATE_LDT_BUS_NUMBER(ldtbus) == 0)) { for (j = SECONDARY_LDT_BUS_NUMBER(ldtbus); j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus); - j++) - pci_bus_to_node[j] = NODE_ID(nid); + j++) { + int node = NODE_ID(nid); + if (!node_online(node)) + node = 0; + pci_bus_to_node[j] = node; + } } } } diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index df6e1e17b09..dc42cede939 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -702,12 +702,11 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) if (ka.sa.sa_flags & SA_ONESHOT) ka.sa.sa_handler = SIG_DFL; - if (!(ka.sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka.sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, &ka.sa.sa_mask); + if (!(ka.sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked, signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); return 1; } diff --git a/drivers/Kconfig b/drivers/Kconfig index cecab0acc3f..46d655fab11 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -48,6 +48,8 @@ source "drivers/hwmon/Kconfig" source "drivers/misc/Kconfig" +source "drivers/mfd/Kconfig" + source "drivers/media/Kconfig" source "drivers/video/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 126a851d565..9663132ed82 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -26,7 +26,7 @@ obj-$(CONFIG_FB_INTEL) += video/intelfb/ obj-$(CONFIG_SERIO) += input/serio/ obj-y += serial/ obj-$(CONFIG_PARPORT) += parport/ -obj-y += base/ block/ misc/ net/ media/ +obj-y += base/ block/ misc/ mfd/ net/ media/ obj-$(CONFIG_NUBUS) += nubus/ obj-$(CONFIG_ATM) += atm/ obj-$(CONFIG_PPC_PMAC) += macintosh/ diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c index 186b182c582..f93d2ee5480 100644 --- a/drivers/acpi/sleep/poweroff.c +++ b/drivers/acpi/sleep/poweroff.c @@ -55,7 +55,11 @@ void acpi_power_off(void) static int acpi_shutdown(struct sys_device *x) { - return acpi_sleep_prepare(ACPI_STATE_S5); + if (system_state == SYSTEM_POWER_OFF) { + /* Prepare if we are going to power off the system */ + return acpi_sleep_prepare(ACPI_STATE_S5); + } + return 0; } static struct sysdev_class acpi_sysclass = { diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 96fe2f95675..ab53832d57e 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -180,7 +180,9 @@ static ssize_t driver_bind(struct device_driver *drv, up(&dev->sem); put_device(dev); } - return err; + if (err) + return err; + return count; } static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c index 2435a7c99b2..cd056e7e64e 100644 --- a/drivers/block/cfq-iosched.c +++ b/drivers/block/cfq-iosched.c @@ -47,7 +47,7 @@ static int cfq_slice_idle = HZ / 100; /* * disable queueing at the driver/hardware level */ -static int cfq_max_depth = 1; +static int cfq_max_depth = 2; /* * for the hash of cfqq inside the cfqd @@ -385,9 +385,15 @@ cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2) return crq2; if (crq2 == NULL) return crq1; - if (cfq_crq_requeued(crq1)) + + if (cfq_crq_requeued(crq1) && !cfq_crq_requeued(crq2)) return crq1; - if (cfq_crq_requeued(crq2)) + else if (cfq_crq_requeued(crq2) && !cfq_crq_requeued(crq1)) + return crq2; + + if (cfq_crq_is_sync(crq1) && !cfq_crq_is_sync(crq2)) + return crq1; + else if (cfq_crq_is_sync(crq2) && !cfq_crq_is_sync(crq1)) return crq2; s1 = crq1->request->sector; @@ -1769,18 +1775,23 @@ static void cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, struct cfq_rq *crq) { - const int sync = cfq_crq_is_sync(crq); + struct cfq_io_context *cic; cfqq->next_crq = cfq_choose_req(cfqd, cfqq->next_crq, crq); - if (sync) { - struct cfq_io_context *cic = crq->io_context; + /* + * we never wait for an async request and we don't allow preemption + * of an async request. so just return early + */ + if (!cfq_crq_is_sync(crq)) + return; - cfq_update_io_thinktime(cfqd, cic); - cfq_update_idle_window(cfqd, cfqq, cic); + cic = crq->io_context; - cic->last_queue = jiffies; - } + cfq_update_io_thinktime(cfqd, cic); + cfq_update_idle_window(cfqd, cfqq, cic); + + cic->last_queue = jiffies; if (cfqq == cfqd->active_queue) { /* diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 4f27e551929..7333b41d422 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -80,7 +80,7 @@ config SERIAL_NONSTANDARD config COMPUTONE tristate "Computone IntelliPort Plus serial support" - depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP + depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP && (BROKEN || !SPARC32) ---help--- This driver supports the entire family of Intelliport II/Plus controllers with the exception of the MicroChannel controllers and @@ -138,7 +138,7 @@ config CYZ_INTR config DIGIEPCA tristate "Digiboard Intelligent Async Support" - depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP + depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP && (!64BIT || BROKEN) ---help--- This is a driver for Digi International's Xx, Xeve, and Xem series of cards which provide multiple serial ports. You would need @@ -208,7 +208,7 @@ config SYNCLINK config SYNCLINKMP tristate "SyncLink Multiport support" - depends on SERIAL_NONSTANDARD + depends on SERIAL_NONSTANDARD && (BROKEN || !SPARC32) help Enable support for the SyncLink Multiport (2 or 4 ports) serial adapter, running asynchronous and HDLC communications up @@ -735,7 +735,7 @@ config SGI_IP27_RTC config GEN_RTC tristate "Generic /dev/rtc emulation" - depends on RTC!=y && !IA64 && !ARM && !PPC64 + depends on RTC!=y && !IA64 && !ARM && !PPC64 && !M32R && !SPARC32 ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 30d96739fb2..665103ccaee 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -2433,7 +2433,7 @@ static int con_open(struct tty_struct *tty, struct file *filp) int ret = 0; acquire_console_sem(); - if (tty->count == 1) { + if (tty->driver_data == NULL) { ret = vc_allocate(currcons); if (ret == 0) { struct vc_data *vc = vc_cons[currcons].d; diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 4fa17c76eea..c8a7f47911f 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -325,7 +325,7 @@ int adm1026_attach_adapter(struct i2c_adapter *adapter) int adm1026_detach_client(struct i2c_client *client) { i2c_detach_client(client); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } @@ -1691,7 +1691,7 @@ int adm1026_detect(struct i2c_adapter *adapter, int address, /* Error out and cleanup code */ exitfree: - kfree(new_client); + kfree(data); exit: return err; } diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 9168e983ca1..93625095727 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -834,7 +834,7 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_free: - kfree(new_client); + kfree(data); exit: return err; } @@ -845,7 +845,7 @@ static int adm1031_detach_client(struct i2c_client *client) if ((ret = i2c_detach_client(client)) != 0) { return ret; } - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 5c68e9c311a..ce2a6eb93f6 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -616,7 +616,7 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_free: - kfree(new_client); + kfree(data); exit: return err; } diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c index 270015b626a..301ae98bd0a 100644 --- a/drivers/hwmon/fscpos.c +++ b/drivers/hwmon/fscpos.c @@ -167,7 +167,7 @@ static ssize_t set_temp_reset(struct i2c_client *client, struct fscpos_data "experience to the module author.\n"); /* Supported value: 2 (clears the status) */ - fscpos_write_value(client, FSCPOS_REG_TEMP_STATE[nr], 2); + fscpos_write_value(client, FSCPOS_REG_TEMP_STATE[nr - 1], 2); return count; } diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index 251ac265955..fdeeb3ab6f2 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -298,7 +298,7 @@ static int smsc47b397_detect(struct i2c_adapter *adapter, int addr, int kind) return 0; error_free: - kfree(new_client); + kfree(data); error_release: release_region(addr, SMSC_EXTENT); return err; diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 897117a7213..7166ad0b2fd 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -495,7 +495,7 @@ static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind) return 0; error_free: - kfree(new_client); + kfree(data); error_release: release_region(address, SMSC_EXTENT); return err; diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 5f33df47aa7..1cadd2c3cad 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -764,6 +764,7 @@ config BLK_DEV_IDE_PMAC_ATA100FIRST config BLK_DEV_IDEDMA_PMAC bool "PowerMac IDE DMA support" depends on BLK_DEV_IDE_PMAC + select BLK_DEV_IDEDMA_PCI help This option allows the driver for the built-in IDE controller on Power Macintoshes and PowerBooks to use DMA (direct memory access) diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 9eab6426148..29c22fc278c 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -317,7 +317,7 @@ typedef struct ide_floppy_obj { unsigned long flags; } idefloppy_floppy_t; -#define IDEFLOPPY_TICKS_DELAY 3 /* default delay for ZIP 100 */ +#define IDEFLOPPY_TICKS_DELAY HZ/20 /* default delay for ZIP 100 (50ms) */ /* * Floppy flag bits values. diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c index da46577380f..6e3ab0c38c4 100644 --- a/drivers/ide/pci/generic.c +++ b/drivers/ide/pci/generic.c @@ -173,6 +173,12 @@ static ide_pci_device_t generic_chipsets[] __devinitdata = { .channels = 2, .autodma = NOAUTODMA, .bootable = ON_BOARD, + },{ /* 14 */ + .name = "Revolution", + .init_hwif = init_hwif_generic, + .channels = 2, + .autodma = AUTODMA, + .bootable = OFF_BOARD, } }; @@ -231,6 +237,7 @@ static struct pci_device_id generic_pci_tbl[] = { { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11}, { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12}, { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13}, + { PCI_VENDOR_ID_NETCELL,PCI_DEVICE_ID_REVOLUTION, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14}, /* Must come last. If you add entries adjust this table appropriately and the init_one code */ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0}, { 0, }, diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index c6f5fa4b4ca..ff2e217a8c8 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -21,6 +21,9 @@ * * CSB6: `Champion South Bridge' IDE Interface (optional: third channel) * + * HT1000: AKA BCM5785 - Hypertransport Southbridge for Opteron systems. IDE + * controller same as the CSB6. Single channel ATA100 only. + * * Documentation: * Available under NDA only. Errata info very hard to get. * @@ -71,6 +74,8 @@ static u8 svwks_ratemask (ide_drive_t *drive) if (!svwks_revision) pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision); + if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) + return 2; if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { u32 reg = 0; if (isa_dev) @@ -109,6 +114,7 @@ static u8 svwks_csb_check (struct pci_dev *dev) case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: + case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE: return 1; default: break; @@ -438,6 +444,13 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2; pci_write_config_byte(dev, 0x5A, btr); } + /* Setup HT1000 SouthBridge Controller - Single Channel Only */ + else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) { + pci_read_config_byte(dev, 0x5A, &btr); + btr &= ~0x40; + btr |= 0x3; + pci_write_config_byte(dev, 0x5A, btr); + } return (dev->irq) ? dev->irq : 0; } @@ -629,6 +642,15 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = { .channels = 1, /* 2 */ .autodma = AUTODMA, .bootable = ON_BOARD, + },{ /* 4 */ + .name = "SvrWks HT1000", + .init_setup = init_setup_svwks, + .init_chipset = init_chipset_svwks, + .init_hwif = init_hwif_svwks, + .init_dma = init_dma_svwks, + .channels = 1, /* 2 */ + .autodma = AUTODMA, + .bootable = ON_BOARD, } }; @@ -653,6 +675,7 @@ static struct pci_device_id svwks_pci_tbl[] = { { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, + { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, { 0, }, }; MODULE_DEVICE_TABLE(pci, svwks_pci_tbl); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index be0fcc8f4b1..ea65b070a36 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1664,7 +1664,7 @@ static struct macio_driver pmac_ide_macio_driver = }; static struct pci_device_id pmac_ide_pci_match[] = { - { PCI_VENDOR_ID_APPLE, PCI_DEVIEC_ID_APPLE_UNI_N_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_SH_ATA, diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 77da827b289..18ed7765417 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -229,6 +229,7 @@ second_chance_to_dma: case PCI_DEVICE_ID_AMD_VIPER_7409: case PCI_DEVICE_ID_CMD_643: case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: + case PCI_DEVICE_ID_REVOLUTION: simplex_stat = hwif->INB(dma_base + 2); hwif->OUTB((simplex_stat&0x60),(dma_base + 2)); simplex_stat = hwif->INB(dma_base + 2); diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index b12a970cc9a..27018c8efc2 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -478,7 +478,6 @@ static void ohci_initialize(struct ti_ohci *ohci) int num_ports, i; spin_lock_init(&ohci->phy_reg_lock); - spin_lock_init(&ohci->event_lock); /* Put some defaults to these undefined bus options */ buf = reg_read(ohci, OHCI1394_BusOptions); @@ -3402,7 +3401,14 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev, /* We hopefully don't have to pre-allocate IT DMA like we did * for IR DMA above. Allocate it on-demand and mark inactive. */ ohci->it_legacy_context.ohci = NULL; + spin_lock_init(&ohci->event_lock); + /* + * interrupts are disabled, all right, but... due to SA_SHIRQ we + * might get called anyway. We'll see no event, of course, but + * we need to get to that "no event", so enough should be initialized + * by that point. + */ if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, OHCI1394_DRIVER_NAME, ohci)) FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq); diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index 79c8e2dd9c3..32cdfb30e9b 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -1,6 +1,7 @@ menu "InfiniBand support" config INFINIBAND + depends on PCI || BROKEN tristate "InfiniBand support" ---help--- Core support for InfiniBand (IB). Make sure to also select diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index eb99e693dec..5f6e9ea29cd 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -130,13 +130,14 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) { struct ib_mr *mr = idr_find(&ib_uverbs_mr_idr, uobj->id); + struct ib_device *mrdev = mr->device; struct ib_umem_object *memobj; idr_remove(&ib_uverbs_mr_idr, uobj->id); ib_dereg_mr(mr); memobj = container_of(uobj, struct ib_umem_object, uobject); - ib_umem_release_on_close(mr->device, &memobj->umem); + ib_umem_release_on_close(mrdev, &memobj->umem); list_del(&uobj->list); kfree(memobj); diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c index f8570fd9d2a..3abd7fc6e5e 100644 --- a/drivers/isdn/capi/capifs.c +++ b/drivers/isdn/capi/capifs.c @@ -191,8 +191,10 @@ static int __init capifs_init(void) err = register_filesystem(&capifs_fs_type); if (!err) { capifs_mnt = kern_mount(&capifs_fs_type); - if (IS_ERR(capifs_mnt)) + if (IS_ERR(capifs_mnt)) { err = PTR_ERR(capifs_mnt); + unregister_filesystem(&capifs_fs_type); + } } if (!err) printk(KERN_NOTICE "capifs: Rev %s\n", rev); diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig index 6c7b8bffc6f..801c98f30e5 100644 --- a/drivers/isdn/hisax/Kconfig +++ b/drivers/isdn/hisax/Kconfig @@ -134,6 +134,7 @@ config HISAX_AVM_A1 config HISAX_FRITZPCI bool "AVM PnP/PCI (Fritz!PnP/PCI)" + depends on BROKEN || !PPC64 help This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI". See <file:Documentation/isdn/README.HiSax> on how to configure it. diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index 65ab64c43b3..bc3e096d84f 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -103,7 +103,7 @@ config PMAC_MEDIABAY # on non-powerbook machines (but only on PMU based ones AFAIK) config PMAC_BACKLIGHT bool "Backlight control for LCD screens" - depends on ADB_PMU + depends on ADB_PMU && (BROKEN || !PPC64) help Say Y here to build in code to manage the LCD backlight on a Macintosh PowerBook. With this code, the backlight will be turned diff --git a/drivers/md/md.c b/drivers/md/md.c index 480f658db6f..20ca80b7dc2 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -256,8 +256,7 @@ static inline void mddev_unlock(mddev_t * mddev) { up(&mddev->reconfig_sem); - if (mddev->thread) - md_wakeup_thread(mddev->thread); + md_wakeup_thread(mddev->thread); } mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr) @@ -623,6 +622,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->raid_disks = sb->raid_disks; mddev->size = sb->size; mddev->events = md_event(sb); + mddev->bitmap_offset = 0; if (sb->state & (1<<MD_SB_CLEAN)) mddev->recovery_cp = MaxSector; @@ -938,6 +938,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->raid_disks = le32_to_cpu(sb->raid_disks); mddev->size = le64_to_cpu(sb->size)/2; mddev->events = le64_to_cpu(sb->events); + mddev->bitmap_offset = 0; mddev->recovery_cp = le64_to_cpu(sb->resync_offset); memcpy(mddev->uuid, sb->set_uuid, 16); @@ -1688,6 +1689,7 @@ static int do_md_run(mddev_t * mddev) mddev->pers = pers[pnum]; spin_unlock(&pers_lock); + mddev->recovery = 0; mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */ /* before we start the array running, initialise the bitmap */ @@ -1712,6 +1714,7 @@ static int do_md_run(mddev_t * mddev) mddev->in_sync = 1; set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + md_wakeup_thread(mddev->thread); if (mddev->sb_dirty) md_update_sb(mddev); @@ -1824,6 +1827,7 @@ static int do_md_stop(mddev_t * mddev, int ro) fput(mddev->bitmap_file); mddev->bitmap_file = NULL; } + mddev->bitmap_offset = 0; /* * Free resources if final stop @@ -2233,8 +2237,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) export_rdev(rdev); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); - if (mddev->thread) - md_wakeup_thread(mddev->thread); + md_wakeup_thread(mddev->thread); return err; } @@ -4009,3 +4012,4 @@ EXPORT_SYMBOL(md_print_devices); EXPORT_SYMBOL(md_check_recovery); MODULE_LICENSE("GPL"); MODULE_ALIAS("md"); +MODULE_ALIAS_BLOCKDEV_MAJOR(MD_MAJOR); diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index 63b626f70c8..9b9d6f8ee74 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -70,13 +70,22 @@ EXPORT_SYMBOL(dibusb_power_ctrl); int dibusb2_0_streaming_ctrl(struct dvb_usb_device *d, int onoff) { - u8 b[2]; - b[0] = DIBUSB_REQ_SET_IOCTL; - b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM; + u8 b[3] = { 0 }; + int ret; + + if ((ret = dibusb_streaming_ctrl(d,onoff)) < 0) + return ret; - dvb_usb_generic_write(d,b,3); + if (onoff) { + b[0] = DIBUSB_REQ_SET_STREAMING_MODE; + b[1] = 0x00; + if ((ret = dvb_usb_generic_write(d,b,2)) < 0) + return ret; + } - return dibusb_streaming_ctrl(d,onoff); + b[0] = DIBUSB_REQ_SET_IOCTL; + b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM; + return dvb_usb_generic_write(d,b,3); } EXPORT_SYMBOL(dibusb2_0_streaming_ctrl); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index 3491ff40885..6fa92100248 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -23,12 +23,12 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) */ if (newfeedcount == 0) { deb_ts("stop feeding\n"); + dvb_usb_urb_kill(d); if (d->props.streaming_ctrl != NULL) if ((ret = d->props.streaming_ctrl(d,0))) err("error while stopping stream."); - dvb_usb_urb_kill(d); } d->feedcount = newfeedcount; @@ -44,6 +44,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) * for reception. */ if (d->feedcount == onoff && d->feedcount > 0) { + deb_ts("submitting all URBs\n"); + dvb_usb_urb_submit(d); deb_ts("controlling pid parser\n"); if (d->props.caps & DVB_USB_HAS_PID_FILTER && @@ -59,7 +61,6 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) return -ENODEV; } - dvb_usb_urb_submit(d); } return 0; } diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index ac81e5e01a9..3f574239609 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -356,7 +356,7 @@ config VIDEO_M32R_AR config VIDEO_M32R_AR_M64278 tristate "Use Colour AR module M64278(VGA)" - depends on VIDEO_M32R_AR + depends on VIDEO_M32R_AR && PLAT_M32700UT ---help--- Say Y here to use the Renesas M64278E-800 camera module, which supports VGA(640x480 pixcels) size of images. diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig new file mode 100644 index 00000000000..1588a59e376 --- /dev/null +++ b/drivers/mfd/Kconfig @@ -0,0 +1,16 @@ +# +# Multifunction miscellaneous devices +# + +menu "Multimedia Capabilities Port drivers" + +config MCP + tristate + +# Interface drivers +config MCP_SA11X0 + tristate "Support SA11x0 MCP interface" + depends on ARCH_SA1100 + select MCP + +endmenu diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile new file mode 100644 index 00000000000..98bdd6a4218 --- /dev/null +++ b/drivers/mfd/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for multifunction miscellaneous devices +# + +obj-$(CONFIG_MCP) += mcp-core.o +obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c new file mode 100644 index 00000000000..c75d713c01e --- /dev/null +++ b/drivers/mfd/mcp-core.c @@ -0,0 +1,255 @@ +/* + * linux/drivers/mfd/mcp-core.c + * + * Copyright (C) 2001 Russell King + * + * 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. + * + * Generic MCP (Multimedia Communications Port) layer. All MCP locking + * is solely held within this file. + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/smp.h> +#include <linux/device.h> + +#include <asm/dma.h> +#include <asm/system.h> + +#include "mcp.h" + +#define to_mcp(d) container_of(d, struct mcp, attached_device) +#define to_mcp_driver(d) container_of(d, struct mcp_driver, drv) + +static int mcp_bus_match(struct device *dev, struct device_driver *drv) +{ + return 1; +} + +static int mcp_bus_probe(struct device *dev) +{ + struct mcp *mcp = to_mcp(dev); + struct mcp_driver *drv = to_mcp_driver(dev->driver); + + return drv->probe(mcp); +} + +static int mcp_bus_remove(struct device *dev) +{ + struct mcp *mcp = to_mcp(dev); + struct mcp_driver *drv = to_mcp_driver(dev->driver); + + drv->remove(mcp); + return 0; +} + +static int mcp_bus_suspend(struct device *dev, pm_message_t state) +{ + struct mcp *mcp = to_mcp(dev); + int ret = 0; + + if (dev->driver) { + struct mcp_driver *drv = to_mcp_driver(dev->driver); + + ret = drv->suspend(mcp, state); + } + return ret; +} + +static int mcp_bus_resume(struct device *dev) +{ + struct mcp *mcp = to_mcp(dev); + int ret = 0; + + if (dev->driver) { + struct mcp_driver *drv = to_mcp_driver(dev->driver); + + ret = drv->resume(mcp); + } + return ret; +} + +static struct bus_type mcp_bus_type = { + .name = "mcp", + .match = mcp_bus_match, + .suspend = mcp_bus_suspend, + .resume = mcp_bus_resume, +}; + +/** + * mcp_set_telecom_divisor - set the telecom divisor + * @mcp: MCP interface structure + * @div: SIB clock divisor + * + * Set the telecom divisor on the MCP interface. The resulting + * sample rate is SIBCLOCK/div. + */ +void mcp_set_telecom_divisor(struct mcp *mcp, unsigned int div) +{ + spin_lock_irq(&mcp->lock); + mcp->ops->set_telecom_divisor(mcp, div); + spin_unlock_irq(&mcp->lock); +} +EXPORT_SYMBOL(mcp_set_telecom_divisor); + +/** + * mcp_set_audio_divisor - set the audio divisor + * @mcp: MCP interface structure + * @div: SIB clock divisor + * + * Set the audio divisor on the MCP interface. + */ +void mcp_set_audio_divisor(struct mcp *mcp, unsigned int div) +{ + spin_lock_irq(&mcp->lock); + mcp->ops->set_audio_divisor(mcp, div); + spin_unlock_irq(&mcp->lock); +} +EXPORT_SYMBOL(mcp_set_audio_divisor); + +/** + * mcp_reg_write - write a device register + * @mcp: MCP interface structure + * @reg: 4-bit register index + * @val: 16-bit data value + * + * Write a device register. The MCP interface must be enabled + * to prevent this function hanging. + */ +void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val) +{ + unsigned long flags; + + spin_lock_irqsave(&mcp->lock, flags); + mcp->ops->reg_write(mcp, reg, val); + spin_unlock_irqrestore(&mcp->lock, flags); +} +EXPORT_SYMBOL(mcp_reg_write); + +/** + * mcp_reg_read - read a device register + * @mcp: MCP interface structure + * @reg: 4-bit register index + * + * Read a device register and return its value. The MCP interface + * must be enabled to prevent this function hanging. + */ +unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg) +{ + unsigned long flags; + unsigned int val; + + spin_lock_irqsave(&mcp->lock, flags); + val = mcp->ops->reg_read(mcp, reg); + spin_unlock_irqrestore(&mcp->lock, flags); + + return val; +} +EXPORT_SYMBOL(mcp_reg_read); + +/** + * mcp_enable - enable the MCP interface + * @mcp: MCP interface to enable + * + * Enable the MCP interface. Each call to mcp_enable will need + * a corresponding call to mcp_disable to disable the interface. + */ +void mcp_enable(struct mcp *mcp) +{ + spin_lock_irq(&mcp->lock); + if (mcp->use_count++ == 0) + mcp->ops->enable(mcp); + spin_unlock_irq(&mcp->lock); +} +EXPORT_SYMBOL(mcp_enable); + +/** + * mcp_disable - disable the MCP interface + * @mcp: MCP interface to disable + * + * Disable the MCP interface. The MCP interface will only be + * disabled once the number of calls to mcp_enable matches the + * number of calls to mcp_disable. + */ +void mcp_disable(struct mcp *mcp) +{ + unsigned long flags; + + spin_lock_irqsave(&mcp->lock, flags); + if (--mcp->use_count == 0) + mcp->ops->disable(mcp); + spin_unlock_irqrestore(&mcp->lock, flags); +} +EXPORT_SYMBOL(mcp_disable); + +static void mcp_release(struct device *dev) +{ + struct mcp *mcp = container_of(dev, struct mcp, attached_device); + + kfree(mcp); +} + +struct mcp *mcp_host_alloc(struct device *parent, size_t size) +{ + struct mcp *mcp; + + mcp = kmalloc(sizeof(struct mcp) + size, GFP_KERNEL); + if (mcp) { + memset(mcp, 0, sizeof(struct mcp) + size); + spin_lock_init(&mcp->lock); + mcp->attached_device.parent = parent; + mcp->attached_device.bus = &mcp_bus_type; + mcp->attached_device.dma_mask = parent->dma_mask; + mcp->attached_device.release = mcp_release; + } + return mcp; +} +EXPORT_SYMBOL(mcp_host_alloc); + +int mcp_host_register(struct mcp *mcp) +{ + strcpy(mcp->attached_device.bus_id, "mcp0"); + return device_register(&mcp->attached_device); +} +EXPORT_SYMBOL(mcp_host_register); + +void mcp_host_unregister(struct mcp *mcp) +{ + device_unregister(&mcp->attached_device); +} +EXPORT_SYMBOL(mcp_host_unregister); + +int mcp_driver_register(struct mcp_driver *mcpdrv) +{ + mcpdrv->drv.bus = &mcp_bus_type; + mcpdrv->drv.probe = mcp_bus_probe; + mcpdrv->drv.remove = mcp_bus_remove; + return driver_register(&mcpdrv->drv); +} +EXPORT_SYMBOL(mcp_driver_register); + +void mcp_driver_unregister(struct mcp_driver *mcpdrv) +{ + driver_unregister(&mcpdrv->drv); +} +EXPORT_SYMBOL(mcp_driver_unregister); + +static int __init mcp_init(void) +{ + return bus_register(&mcp_bus_type); +} + +static void __exit mcp_exit(void) +{ + bus_unregister(&mcp_bus_type); +} + +module_init(mcp_init); +module_exit(mcp_exit); + +MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); +MODULE_DESCRIPTION("Core multimedia communications port driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c new file mode 100644 index 00000000000..e9806fbbe69 --- /dev/null +++ b/drivers/mfd/mcp-sa11x0.c @@ -0,0 +1,275 @@ +/* + * linux/drivers/mfd/mcp-sa11x0.c + * + * Copyright (C) 2001-2005 Russell King + * + * 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. + * + * SA11x0 MCP (Multimedia Communications Port) driver. + * + * MCP read/write timeouts from Jordi Colomer, rehacked by rmk. + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/device.h> + +#include <asm/dma.h> +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/system.h> +#include <asm/arch/mcp.h> + +#include <asm/arch/assabet.h> + +#include "mcp.h" + +struct mcp_sa11x0 { + u32 mccr0; + u32 mccr1; +}; + +#define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp)) + +static void +mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor) +{ + unsigned int mccr0; + + divisor /= 32; + + mccr0 = Ser4MCCR0 & ~0x00007f00; + mccr0 |= divisor << 8; + Ser4MCCR0 = mccr0; +} + +static void +mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) +{ + unsigned int mccr0; + + divisor /= 32; + + mccr0 = Ser4MCCR0 & ~0x0000007f; + mccr0 |= divisor; + Ser4MCCR0 = mccr0; +} + +/* + * Write data to the device. The bit should be set after 3 subframe + * times (each frame is 64 clocks). We wait a maximum of 6 subframes. + * We really should try doing something more productive while we + * wait. + */ +static void +mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val) +{ + int ret = -ETIME; + int i; + + Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff); + + for (i = 0; i < 2; i++) { + udelay(mcp->rw_timeout); + if (Ser4MCSR & MCSR_CWC) { + ret = 0; + break; + } + } + + if (ret < 0) + printk(KERN_WARNING "mcp: write timed out\n"); +} + +/* + * Read data from the device. The bit should be set after 3 subframe + * times (each frame is 64 clocks). We wait a maximum of 6 subframes. + * We really should try doing something more productive while we + * wait. + */ +static unsigned int +mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) +{ + int ret = -ETIME; + int i; + + Ser4MCDR2 = reg << 17 | MCDR2_Rd; + + for (i = 0; i < 2; i++) { + udelay(mcp->rw_timeout); + if (Ser4MCSR & MCSR_CRC) { + ret = Ser4MCDR2 & 0xffff; + break; + } + } + + if (ret < 0) + printk(KERN_WARNING "mcp: read timed out\n"); + + return ret; +} + +static void mcp_sa11x0_enable(struct mcp *mcp) +{ + Ser4MCSR = -1; + Ser4MCCR0 |= MCCR0_MCE; +} + +static void mcp_sa11x0_disable(struct mcp *mcp) +{ + Ser4MCCR0 &= ~MCCR0_MCE; +} + +/* + * Our methods. + */ +static struct mcp_ops mcp_sa11x0 = { + .set_telecom_divisor = mcp_sa11x0_set_telecom_divisor, + .set_audio_divisor = mcp_sa11x0_set_audio_divisor, + .reg_write = mcp_sa11x0_write, + .reg_read = mcp_sa11x0_read, + .enable = mcp_sa11x0_enable, + .disable = mcp_sa11x0_disable, +}; + +static int mcp_sa11x0_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mcp_plat_data *data = pdev->dev.platform_data; + struct mcp *mcp; + int ret; + + if (!data) + return -ENODEV; + + if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp")) + return -EBUSY; + + mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0)); + if (!mcp) { + ret = -ENOMEM; + goto release; + } + + mcp->owner = THIS_MODULE; + mcp->ops = &mcp_sa11x0; + mcp->sclk_rate = data->sclk_rate; + mcp->dma_audio_rd = DMA_Ser4MCP0Rd; + mcp->dma_audio_wr = DMA_Ser4MCP0Wr; + mcp->dma_telco_rd = DMA_Ser4MCP1Rd; + mcp->dma_telco_wr = DMA_Ser4MCP1Wr; + + dev_set_drvdata(dev, mcp); + + if (machine_is_assabet()) { + ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); + } + + /* + * Setup the PPC unit correctly. + */ + PPDR &= ~PPC_RXD4; + PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; + PSDR |= PPC_RXD4; + PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); + + /* + * Initialise device. Note that we initially + * set the sampling rate to minimum. + */ + Ser4MCSR = -1; + Ser4MCCR1 = data->mccr1; + Ser4MCCR0 = data->mccr0 | 0x7f7f; + + /* + * Calculate the read/write timeout (us) from the bit clock + * rate. This is the period for 3 64-bit frames. Always + * round this time up. + */ + mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) / + mcp->sclk_rate; + + ret = mcp_host_register(mcp); + if (ret == 0) + goto out; + + release: + release_mem_region(0x80060000, 0x60); + dev_set_drvdata(dev, NULL); + + out: + return ret; +} + +static int mcp_sa11x0_remove(struct device *dev) +{ + struct mcp *mcp = dev_get_drvdata(dev); + + dev_set_drvdata(dev, NULL); + mcp_host_unregister(mcp); + release_mem_region(0x80060000, 0x60); + + return 0; +} + +static int mcp_sa11x0_suspend(struct device *dev, pm_message_t state, u32 level) +{ + struct mcp *mcp = dev_get_drvdata(dev); + + if (level == SUSPEND_DISABLE) { + priv(mcp)->mccr0 = Ser4MCCR0; + priv(mcp)->mccr1 = Ser4MCCR1; + Ser4MCCR0 &= ~MCCR0_MCE; + } + return 0; +} + +static int mcp_sa11x0_resume(struct device *dev, u32 level) +{ + struct mcp *mcp = dev_get_drvdata(dev); + + if (level == RESUME_RESTORE_STATE) { + Ser4MCCR1 = priv(mcp)->mccr1; + Ser4MCCR0 = priv(mcp)->mccr0; + } + return 0; +} + +/* + * The driver for the SA11x0 MCP port. + */ +static struct device_driver mcp_sa11x0_driver = { + .name = "sa11x0-mcp", + .bus = &platform_bus_type, + .probe = mcp_sa11x0_probe, + .remove = mcp_sa11x0_remove, + .suspend = mcp_sa11x0_suspend, + .resume = mcp_sa11x0_resume, +}; + +/* + * This needs re-working + */ +static int __init mcp_sa11x0_init(void) +{ + return driver_register(&mcp_sa11x0_driver); +} + +static void __exit mcp_sa11x0_exit(void) +{ + driver_unregister(&mcp_sa11x0_driver); +} + +module_init(mcp_sa11x0_init); +module_exit(mcp_sa11x0_exit); + +MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); +MODULE_DESCRIPTION("SA11x0 multimedia communications port driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/mcp.h b/drivers/mfd/mcp.h new file mode 100644 index 00000000000..c093a93b880 --- /dev/null +++ b/drivers/mfd/mcp.h @@ -0,0 +1,66 @@ +/* + * linux/drivers/mfd/mcp.h + * + * Copyright (C) 2001 Russell King, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + */ +#ifndef MCP_H +#define MCP_H + +struct mcp_ops; + +struct mcp { + struct module *owner; + struct mcp_ops *ops; + spinlock_t lock; + int use_count; + unsigned int sclk_rate; + unsigned int rw_timeout; + dma_device_t dma_audio_rd; + dma_device_t dma_audio_wr; + dma_device_t dma_telco_rd; + dma_device_t dma_telco_wr; + struct device attached_device; +}; + +struct mcp_ops { + void (*set_telecom_divisor)(struct mcp *, unsigned int); + void (*set_audio_divisor)(struct mcp *, unsigned int); + void (*reg_write)(struct mcp *, unsigned int, unsigned int); + unsigned int (*reg_read)(struct mcp *, unsigned int); + void (*enable)(struct mcp *); + void (*disable)(struct mcp *); +}; + +void mcp_set_telecom_divisor(struct mcp *, unsigned int); +void mcp_set_audio_divisor(struct mcp *, unsigned int); +void mcp_reg_write(struct mcp *, unsigned int, unsigned int); +unsigned int mcp_reg_read(struct mcp *, unsigned int); +void mcp_enable(struct mcp *); +void mcp_disable(struct mcp *); +#define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate) + +struct mcp *mcp_host_alloc(struct device *, size_t); +int mcp_host_register(struct mcp *); +void mcp_host_unregister(struct mcp *); + +struct mcp_driver { + struct device_driver drv; + int (*probe)(struct mcp *); + void (*remove)(struct mcp *); + int (*suspend)(struct mcp *, pm_message_t); + int (*resume)(struct mcp *); +}; + +int mcp_driver_register(struct mcp_driver *); +void mcp_driver_unregister(struct mcp_driver *); + +#define mcp_get_drvdata(mcp) dev_get_drvdata(&(mcp)->attached_device) +#define mcp_set_drvdata(mcp,d) dev_set_drvdata(&(mcp)->attached_device, d) + +#define mcp_priv(mcp) ((void *)((mcp)+1)) + +#endif diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index eeb9f6668e6..3c5904834fe 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -361,7 +361,7 @@ static void mmc_decode_cid(struct mmc_card *card) default: printk("%s: card has unknown MMCA version %d\n", - card->host->host_name, card->csd.mmca_vsn); + mmc_hostname(card->host), card->csd.mmca_vsn); mmc_card_set_bad(card); break; } @@ -383,7 +383,7 @@ static void mmc_decode_csd(struct mmc_card *card) csd_struct = UNSTUFF_BITS(resp, 126, 2); if (csd_struct != 1 && csd_struct != 2) { printk("%s: unrecognised CSD structure version %d\n", - card->host->host_name, csd_struct); + mmc_hostname(card->host), csd_struct); mmc_card_set_bad(card); return; } @@ -551,7 +551,7 @@ static void mmc_discover_cards(struct mmc_host *host) } if (err != MMC_ERR_NONE) { printk(KERN_ERR "%s: error requesting CID: %d\n", - host->host_name, err); + mmc_hostname(host), err); break; } @@ -796,17 +796,13 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) { struct mmc_host *host; - host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); + host = mmc_alloc_host_sysfs(extra, dev); if (host) { - memset(host, 0, sizeof(struct mmc_host) + extra); - spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_LIST_HEAD(&host->cards); INIT_WORK(&host->detect, mmc_rescan, host); - host->dev = dev; - /* * By default, hosts do not support SGIO or large requests. * They have to set these according to their abilities. @@ -828,15 +824,15 @@ EXPORT_SYMBOL(mmc_alloc_host); */ int mmc_add_host(struct mmc_host *host) { - static unsigned int host_num; + int ret; - snprintf(host->host_name, sizeof(host->host_name), - "mmc%d", host_num++); - - mmc_power_off(host); - mmc_detect_change(host); + ret = mmc_add_host_sysfs(host); + if (ret == 0) { + mmc_power_off(host); + mmc_detect_change(host); + } - return 0; + return ret; } EXPORT_SYMBOL(mmc_add_host); @@ -859,6 +855,7 @@ void mmc_remove_host(struct mmc_host *host) } mmc_power_off(host); + mmc_remove_host_sysfs(host); } EXPORT_SYMBOL(mmc_remove_host); @@ -872,7 +869,7 @@ EXPORT_SYMBOL(mmc_remove_host); void mmc_free_host(struct mmc_host *host) { flush_scheduled_work(); - kfree(host); + mmc_free_host_sysfs(host); } EXPORT_SYMBOL(mmc_free_host); diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h index b498dffe0b1..97bae00292f 100644 --- a/drivers/mmc/mmc.h +++ b/drivers/mmc/mmc.h @@ -13,4 +13,9 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host); int mmc_register_card(struct mmc_card *card); void mmc_remove_card(struct mmc_card *card); + +struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev); +int mmc_add_host_sysfs(struct mmc_host *host); +void mmc_remove_host_sysfs(struct mmc_host *host); +void mmc_free_host_sysfs(struct mmc_host *host); #endif diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c index 5556cd3b555..ad8949810fc 100644 --- a/drivers/mmc/mmc_sysfs.c +++ b/drivers/mmc/mmc_sysfs.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/device.h> +#include <linux/idr.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> @@ -20,6 +21,7 @@ #define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) +#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev) #define MMC_ATTR(name, fmt, args...) \ static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ @@ -206,7 +208,7 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host) int mmc_register_card(struct mmc_card *card) { snprintf(card->dev.bus_id, sizeof(card->dev.bus_id), - "%s:%04x", card->host->host_name, card->rca); + "%s:%04x", mmc_hostname(card->host), card->rca); return device_add(&card->dev); } @@ -224,13 +226,97 @@ void mmc_remove_card(struct mmc_card *card) } +static void mmc_host_classdev_release(struct class_device *dev) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + kfree(host); +} + +static struct class mmc_host_class = { + .name = "mmc_host", + .release = mmc_host_classdev_release, +}; + +static DEFINE_IDR(mmc_host_idr); +static DEFINE_SPINLOCK(mmc_host_lock); + +/* + * Internal function. Allocate a new MMC host. + */ +struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev) +{ + struct mmc_host *host; + + host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); + if (host) { + memset(host, 0, sizeof(struct mmc_host) + extra); + + host->dev = dev; + host->class_dev.dev = host->dev; + host->class_dev.class = &mmc_host_class; + class_device_initialize(&host->class_dev); + } + + return host; +} + +/* + * Internal function. Register a new MMC host with the MMC class. + */ +int mmc_add_host_sysfs(struct mmc_host *host) +{ + int err; + + if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL)) + return -ENOMEM; + + spin_lock(&mmc_host_lock); + err = idr_get_new(&mmc_host_idr, host, &host->index); + spin_unlock(&mmc_host_lock); + if (err) + return err; + + snprintf(host->class_dev.class_id, BUS_ID_SIZE, + "mmc%d", host->index); + + return class_device_add(&host->class_dev); +} + +/* + * Internal function. Unregister a MMC host with the MMC class. + */ +void mmc_remove_host_sysfs(struct mmc_host *host) +{ + class_device_del(&host->class_dev); + + spin_lock(&mmc_host_lock); + idr_remove(&mmc_host_idr, host->index); + spin_unlock(&mmc_host_lock); +} + +/* + * Internal function. Free a MMC host. + */ +void mmc_free_host_sysfs(struct mmc_host *host) +{ + class_device_put(&host->class_dev); +} + + static int __init mmc_init(void) { - return bus_register(&mmc_bus_type); + int ret = bus_register(&mmc_bus_type); + if (ret == 0) { + ret = class_register(&mmc_host_class); + if (ret) + bus_unregister(&mmc_bus_type); + } + return ret; } static void __exit mmc_exit(void) { + class_unregister(&mmc_host_class); bus_unregister(&mmc_bus_type); } diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 7a42966d755..716c4ef4faf 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -34,7 +34,7 @@ #ifdef CONFIG_MMC_DEBUG #define DBG(host,fmt,args...) \ - pr_debug("%s: %s: " fmt, host->mmc->host_name, __func__ , args) + pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args) #else #define DBG(host,fmt,args...) do { } while (0) #endif @@ -541,7 +541,7 @@ static int mmci_probe(struct amba_device *dev, void *id) mmc_add_host(mmc); printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%08lx irq %d,%d\n", - mmc->host_name, amba_rev(dev), amba_config(dev), + mmc_hostname(mmc), amba_rev(dev), amba_config(dev), dev->res.start, dev->irq[0], dev->irq[1]); init_timer(&host->timer); diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 974f2f36bdb..402c2d661fb 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1796,7 +1796,7 @@ static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, mmc_add_host(mmc); - printk(KERN_INFO "%s: W83L51xD", mmc->host_name); + printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc)); if (host->chip_id != 0) printk(" id %x", (int)host->chip_id); printk(" at 0x%x irq %d", (int)host->base, (int)host->irq); diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 7b293f01c9e..34b80de34fa 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1897,6 +1897,7 @@ static int cp_resume (struct pci_dev *pdev) { struct net_device *dev; struct cp_private *cp; + unsigned long flags; dev = pci_get_drvdata (pdev); cp = netdev_priv(dev); @@ -1910,6 +1911,12 @@ static int cp_resume (struct pci_dev *pdev) cp_init_hw (cp); netif_start_queue (dev); + + spin_lock_irqsave (&cp->lock, flags); + + mii_check_media(&cp->mii_if, netif_msg_link(cp), FALSE); + + spin_unlock_irqrestore (&cp->lock, flags); return 0; } diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8a835eb5880..79e8aa6f2b9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -131,6 +131,8 @@ config NET_SB1000 source "drivers/net/arcnet/Kconfig" +source "drivers/net/phy/Kconfig" + # # Ethernet # @@ -1145,7 +1147,7 @@ config IBMVETH be called ibmveth. config IBM_EMAC - tristate "IBM PPC4xx EMAC driver support" + bool "IBM PPC4xx EMAC driver support" depends on 4xx select CRC32 ---help--- @@ -1154,7 +1156,7 @@ config IBM_EMAC config IBM_EMAC_ERRMSG bool "Verbose error messages" - depends on IBM_EMAC + depends on IBM_EMAC && BROKEN config IBM_EMAC_RXB int "Number of receive buffers" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 63c6d1e6d4d..a369ae284a9 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o # obj-$(CONFIG_MII) += mii.o +obj-$(CONFIG_PHYLIB) += phy/ obj-$(CONFIG_SUNDANCE) += sundance.o obj-$(CONFIG_HAMACHI) += hamachi.o diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 3707df6b0cf..60304f7e7e5 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -87,7 +87,6 @@ extern struct net_device *mvme147lance_probe(int unit); extern struct net_device *tc515_probe(int unit); extern struct net_device *lance_probe(int unit); extern struct net_device *mace_probe(int unit); -extern struct net_device *macsonic_probe(int unit); extern struct net_device *mac8390_probe(int unit); extern struct net_device *mac89x0_probe(int unit); extern struct net_device *mc32_probe(int unit); @@ -284,9 +283,6 @@ static struct devprobe2 m68k_probes[] __initdata = { #ifdef CONFIG_MACMACE /* Mac 68k Quadra AV builtin Ethernet */ {mace_probe, 0}, #endif -#ifdef CONFIG_MACSONIC /* Mac SONIC-based Ethernet of all sorts */ - {macsonic_probe, 0}, -#endif #ifdef CONFIG_MAC8390 /* NuBus NS8390-based cards */ {mac8390_probe, 0}, #endif @@ -318,17 +314,9 @@ static void __init ethif_probe2(int unit) #ifdef CONFIG_TR /* Token-ring device probe */ extern int ibmtr_probe_card(struct net_device *); -extern struct net_device *sk_isa_probe(int unit); -extern struct net_device *proteon_probe(int unit); extern struct net_device *smctr_probe(int unit); static struct devprobe2 tr_probes2[] __initdata = { -#ifdef CONFIG_SKISA - {sk_isa_probe, 0}, -#endif -#ifdef CONFIG_PROTEON - {proteon_probe, 0}, -#endif #ifdef CONFIG_SMCTR {smctr_probe, 0}, #endif diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 5ce606d9dc0..19e829b567d 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1106,18 +1106,13 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav } } - if (found) { - /* a slave was found that is using the mac address - * of the new slave - */ - printk(KERN_ERR DRV_NAME - ": Error: the hw address of slave %s is not " - "unique - cannot enslave it!", - slave->dev->name); - return -EINVAL; - } + if (!found) + return 0; - return 0; + /* Try setting slave mac to bond address and fall-through + to code handling that situation below... */ + alb_set_slave_mac_addr(slave, bond->dev->dev_addr, + bond->alb_info.rlb_enabled); } /* The slave's address is equal to the address of the bond. diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2c930da90a8..94c9f68dd16 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1604,6 +1604,44 @@ static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_ return 0; } +#define BOND_INTERSECT_FEATURES \ + (NETIF_F_SG|NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM) + +/* + * Compute the features available to the bonding device by + * intersection of all of the slave devices' BOND_INTERSECT_FEATURES. + * Call this after attaching or detaching a slave to update the + * bond's features. + */ +static int bond_compute_features(struct bonding *bond) +{ + int i; + struct slave *slave; + struct net_device *bond_dev = bond->dev; + int features = bond->bond_features; + + bond_for_each_slave(bond, slave, i) { + struct net_device * slave_dev = slave->dev; + if (i == 0) { + features |= BOND_INTERSECT_FEATURES; + } + features &= + ~(~slave_dev->features & BOND_INTERSECT_FEATURES); + } + + /* turn off NETIF_F_SG if we need a csum and h/w can't do it */ + if ((features & NETIF_F_SG) && + !(features & (NETIF_F_IP_CSUM | + NETIF_F_NO_CSUM | + NETIF_F_HW_CSUM))) { + features &= ~NETIF_F_SG; + } + + bond_dev->features = features; + + return 0; +} + /* enslave device <slave> to bond device <master> */ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) { @@ -1811,6 +1849,8 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de new_slave->delay = 0; new_slave->link_failure_count = 0; + bond_compute_features(bond); + if (bond->params.miimon && !bond->params.use_carrier) { link_reporting = bond_check_dev_link(bond, slave_dev, 1); @@ -2015,7 +2055,7 @@ err_free: err_undo_flags: bond_dev->features = old_features; - + return res; } @@ -2100,6 +2140,8 @@ static int bond_release(struct net_device *bond_dev, struct net_device *slave_de /* release the slave from its bond */ bond_detach_slave(bond, slave); + bond_compute_features(bond); + if (bond->primary_slave == slave) { bond->primary_slave = NULL; } @@ -2243,6 +2285,8 @@ static int bond_release_all(struct net_device *bond_dev) bond_alb_deinit_slave(bond, slave); } + bond_compute_features(bond); + /* now that the slave is detached, unlock and perform * all the undo steps that should not be called from * within a lock. @@ -3588,6 +3632,7 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev) { struct net_device *bond_dev = slave_dev->master; + struct bonding *bond = bond_dev->priv; switch (event) { case NETDEV_UNREGISTER: @@ -3626,6 +3671,9 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave * TODO: handle changing the primary's name */ break; + case NETDEV_FEAT_CHANGE: + bond_compute_features(bond); + break; default: break; } @@ -4526,6 +4574,11 @@ static inline void bond_set_mode_ops(struct bonding *bond, int mode) } } +static struct ethtool_ops bond_ethtool_ops = { + .get_tx_csum = ethtool_op_get_tx_csum, + .get_sg = ethtool_op_get_sg, +}; + /* * Does not allocate but creates a /proc entry. * Allowed to fail. @@ -4555,6 +4608,7 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par bond_dev->stop = bond_close; bond_dev->get_stats = bond_get_stats; bond_dev->do_ioctl = bond_do_ioctl; + bond_dev->ethtool_ops = &bond_ethtool_ops; bond_dev->set_multicast_list = bond_set_multicast_list; bond_dev->change_mtu = bond_change_mtu; bond_dev->set_mac_address = bond_set_mac_address; @@ -4591,6 +4645,8 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER); + bond->bond_features = bond_dev->features; + #ifdef CONFIG_PROC_FS bond_create_proc_entry(bond); #endif diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index d27f377b3ee..38819698086 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -211,6 +211,9 @@ struct bonding { struct bond_params params; struct list_head vlan_list; struct vlan_group *vlgrp; + /* the features the bonding device supports, independently + * of any slaves */ + int bond_features; }; /** diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 5fddc0ff887..6440a892bb8 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -48,6 +48,10 @@ * net_device_stats * * introduced tx_timeout function * * reworked locking + * + * 01-Jul-2005 Ben Dooks <ben@simtec.co.uk> + * * fixed spinlock call without pointer + * * ensure spinlock is initialised */ #include <linux/module.h> @@ -148,7 +152,6 @@ static int dm9000_probe(struct device *); static int dm9000_open(struct net_device *); static int dm9000_start_xmit(struct sk_buff *, struct net_device *); static int dm9000_stop(struct net_device *); -static int dm9000_do_ioctl(struct net_device *, struct ifreq *, int); static void dm9000_timer(unsigned long); @@ -322,7 +325,7 @@ static void dm9000_timeout(struct net_device *dev) /* Save previous register address */ reg_save = readb(db->io_addr); - spin_lock_irqsave(db->lock,flags); + spin_lock_irqsave(&db->lock,flags); netif_stop_queue(dev); dm9000_reset(db); @@ -333,7 +336,7 @@ static void dm9000_timeout(struct net_device *dev) /* Restore previous register address */ writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(db->lock,flags); + spin_unlock_irqrestore(&db->lock,flags); } @@ -387,8 +390,6 @@ dm9000_probe(struct device *dev) int i; u32 id_val; - printk(KERN_INFO "%s Ethernet Driver\n", CARDNAME); - /* Init network device */ ndev = alloc_etherdev(sizeof (struct board_info)); if (!ndev) { @@ -405,6 +406,8 @@ dm9000_probe(struct device *dev) db = (struct board_info *) ndev->priv; memset(db, 0, sizeof (*db)); + spin_lock_init(&db->lock); + if (pdev->num_resources < 2) { ret = -ENODEV; goto out; @@ -541,7 +544,6 @@ dm9000_probe(struct device *dev) ndev->stop = &dm9000_stop; ndev->get_stats = &dm9000_get_stats; ndev->set_multicast_list = &dm9000_hash_table; - ndev->do_ioctl = &dm9000_do_ioctl; #ifdef DM9000_PROGRAM_EEPROM program_eeprom(db); @@ -612,7 +614,7 @@ dm9000_open(struct net_device *dev) /* set and active a timer process */ init_timer(&db->timer); - db->timer.expires = DM9000_TIMER_WUT * 2; + db->timer.expires = DM9000_TIMER_WUT; db->timer.data = (unsigned long) dev; db->timer.function = &dm9000_timer; add_timer(&db->timer); @@ -845,15 +847,6 @@ dm9000_get_stats(struct net_device *dev) return &db->stats; } -/* - * Process the upper socket ioctl command - */ -static int -dm9000_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - PRINTK1("entering %s\n",__FUNCTION__); - return 0; -} /* * A periodic timer routine @@ -864,21 +857,11 @@ dm9000_timer(unsigned long data) { struct net_device *dev = (struct net_device *) data; board_info_t *db = (board_info_t *) dev->priv; - u8 reg_save; - unsigned long flags; PRINTK3("dm9000_timer()\n"); - spin_lock_irqsave(db->lock,flags); - /* Save previous register address */ - reg_save = readb(db->io_addr); - mii_check_media(&db->mii, netif_msg_link(db), 0); - /* Restore previous register address */ - writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(db->lock,flags); - /* Set timer again */ db->timer.expires = DM9000_TIMER_WUT; add_timer(&db->timer); @@ -1098,9 +1081,14 @@ dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) { board_info_t *db = (board_info_t *) dev->priv; unsigned long flags; + unsigned int reg_save; int ret; spin_lock_irqsave(&db->lock,flags); + + /* Save previous register address */ + reg_save = readb(db->io_addr); + /* Fill the phyxcer register into REG_0C */ iow(db, DM9000_EPAR, DM9000_PHY | reg); @@ -1111,6 +1099,9 @@ dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) /* The read data keeps on REG_0D & REG_0E */ ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL); + /* restore the previous address */ + writeb(reg_save, db->io_addr); + spin_unlock_irqrestore(&db->lock,flags); return ret; @@ -1124,9 +1115,13 @@ dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value) { board_info_t *db = (board_info_t *) dev->priv; unsigned long flags; + unsigned long reg_save; spin_lock_irqsave(&db->lock,flags); + /* Save previous register address */ + reg_save = readb(db->io_addr); + /* Fill the phyxcer register into REG_0C */ iow(db, DM9000_EPAR, DM9000_PHY | reg); @@ -1138,6 +1133,9 @@ dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value) udelay(500); /* Wait write complete */ iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ + /* restore the previous address */ + writeb(reg_save, db->io_addr); + spin_unlock_irqrestore(&db->lock,flags); } @@ -1202,6 +1200,8 @@ static struct device_driver dm9000_driver = { static int __init dm9000_init(void) { + printk(KERN_INFO "%s Ethernet Driver\n", CARDNAME); + return driver_register(&dm9000_driver); /* search board and register */ } diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index b82fd15d089..9b596e0bbf9 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2767,7 +2767,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) " next_to_use <%x>\n" " next_to_clean <%x>\n" "buffer_info[next_to_clean]\n" - " dma <%zx>\n" + " dma <%llx>\n" " time_stamp <%lx>\n" " next_to_watch <%x>\n" " jiffies <%lx>\n" @@ -2776,7 +2776,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) E1000_READ_REG(&adapter->hw, TDT), tx_ring->next_to_use, i, - tx_ring->buffer_info[i].dma, + (unsigned long long)tx_ring->buffer_info[i].dma, tx_ring->buffer_info[i].time_stamp, eop, jiffies, diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 1795425f512..8c62ced2c9b 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -1263,8 +1263,8 @@ speedo_init_rx_ring(struct net_device *dev) for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); - /* XXX: do we really want to call this before the NULL check? --hch */ - rx_align(skb); /* Align IP on 16 byte boundary */ + if (skb) + rx_align(skb); /* Align IP on 16 byte boundary */ sp->rx_skbuff[i] = skb; if (skb == NULL) break; /* OK. Just initially short of Rx bufs. */ @@ -1654,8 +1654,8 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) struct sk_buff *skb; /* Get a fresh skbuff to replace the consumed one. */ skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); - /* XXX: do we really want to call this before the NULL check? --hch */ - rx_align(skb); /* Align IP on 16 byte boundary */ + if (skb) + rx_align(skb); /* Align IP on 16 byte boundary */ sp->rx_skbuff[entry] = skb; if (skb == NULL) { sp->rx_ringp[entry] = NULL; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 64f0f697c95..7d93948aec8 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -85,6 +85,16 @@ * 0.33: 16 May 2005: Support for MCP51 added. * 0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics. * 0.35: 26 Jun 2005: Support for MCP55 added. + * 0.36: 28 Jun 2005: Add jumbo frame support. + * 0.37: 10 Jul 2005: Additional ethtool support, cleanup of pci id list + * 0.38: 16 Jul 2005: tx irq rewrite: Use global flags instead of + * per-packet flags. + * 0.39: 18 Jul 2005: Add 64bit descriptor support. + * 0.40: 19 Jul 2005: Add support for mac address change. + * 0.41: 30 Jul 2005: Write back original MAC in nv_close instead + * of nv_remove + * 0.42: 06 Aug 2005: Fix lack of link speed initialization + * in the second (and later) nv_open call * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -96,7 +106,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.35" +#define FORCEDETH_VERSION "0.41" #define DRV_NAME "forcedeth" #include <linux/module.h> @@ -131,11 +141,10 @@ * Hardware access: */ -#define DEV_NEED_LASTPACKET1 0x0001 /* set LASTPACKET1 in tx flags */ -#define DEV_IRQMASK_1 0x0002 /* use NVREG_IRQMASK_WANTED_1 for irq mask */ -#define DEV_IRQMASK_2 0x0004 /* use NVREG_IRQMASK_WANTED_2 for irq mask */ -#define DEV_NEED_TIMERIRQ 0x0008 /* set the timer irq flag in the irq mask */ -#define DEV_NEED_LINKTIMER 0x0010 /* poll link settings. Relies on the timer irq */ +#define DEV_NEED_TIMERIRQ 0x0001 /* set the timer irq flag in the irq mask */ +#define DEV_NEED_LINKTIMER 0x0002 /* poll link settings. Relies on the timer irq */ +#define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */ +#define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */ enum { NvRegIrqStatus = 0x000, @@ -146,13 +155,16 @@ enum { #define NVREG_IRQ_RX 0x0002 #define NVREG_IRQ_RX_NOBUF 0x0004 #define NVREG_IRQ_TX_ERR 0x0008 -#define NVREG_IRQ_TX2 0x0010 +#define NVREG_IRQ_TX_OK 0x0010 #define NVREG_IRQ_TIMER 0x0020 #define NVREG_IRQ_LINK 0x0040 +#define NVREG_IRQ_TX_ERROR 0x0080 #define NVREG_IRQ_TX1 0x0100 -#define NVREG_IRQMASK_WANTED_1 0x005f -#define NVREG_IRQMASK_WANTED_2 0x0147 -#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1)) +#define NVREG_IRQMASK_WANTED 0x00df + +#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \ + NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX_ERROR| \ + NVREG_IRQ_TX1)) NvRegUnknownSetupReg6 = 0x008, #define NVREG_UNKSETUP6_VAL 3 @@ -286,6 +298,18 @@ struct ring_desc { u32 FlagLen; }; +struct ring_desc_ex { + u32 PacketBufferHigh; + u32 PacketBufferLow; + u32 Reserved; + u32 FlagLen; +}; + +typedef union _ring_type { + struct ring_desc* orig; + struct ring_desc_ex* ex; +} ring_type; + #define FLAG_MASK_V1 0xffff0000 #define FLAG_MASK_V2 0xffffc000 #define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1) @@ -293,7 +317,7 @@ struct ring_desc { #define NV_TX_LASTPACKET (1<<16) #define NV_TX_RETRYERROR (1<<19) -#define NV_TX_LASTPACKET1 (1<<24) +#define NV_TX_FORCED_INTERRUPT (1<<24) #define NV_TX_DEFERRED (1<<26) #define NV_TX_CARRIERLOST (1<<27) #define NV_TX_LATECOLLISION (1<<28) @@ -303,7 +327,7 @@ struct ring_desc { #define NV_TX2_LASTPACKET (1<<29) #define NV_TX2_RETRYERROR (1<<18) -#define NV_TX2_LASTPACKET1 (1<<23) +#define NV_TX2_FORCED_INTERRUPT (1<<30) #define NV_TX2_DEFERRED (1<<25) #define NV_TX2_CARRIERLOST (1<<26) #define NV_TX2_LATECOLLISION (1<<27) @@ -379,9 +403,13 @@ struct ring_desc { #define TX_LIMIT_START 62 /* rx/tx mac addr + type + vlan + align + slack*/ -#define RX_NIC_BUFSIZE (ETH_DATA_LEN + 64) -/* even more slack */ -#define RX_ALLOC_BUFSIZE (ETH_DATA_LEN + 128) +#define NV_RX_HEADERS (64) +/* even more slack. */ +#define NV_RX_ALLOC_PAD (64) + +/* maximum mtu size */ +#define NV_PKTLIMIT_1 ETH_DATA_LEN /* hard limit not known */ +#define NV_PKTLIMIT_2 9100 /* Actual limit according to NVidia: 9202 */ #define OOM_REFILL (1+HZ/20) #define POLL_WAIT (1+HZ/100) @@ -396,6 +424,7 @@ struct ring_desc { */ #define DESC_VER_1 0x0 #define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK) +#define DESC_VER_3 (0x02200|NVREG_TXRXCTL_RXCHECK) /* PHY defines */ #define PHY_OUI_MARVELL 0x5043 @@ -468,11 +497,12 @@ struct fe_priv { /* rx specific fields. * Locking: Within irq hander or disable_irq+spin_lock(&np->lock); */ - struct ring_desc *rx_ring; + ring_type rx_ring; unsigned int cur_rx, refill_rx; struct sk_buff *rx_skbuff[RX_RING]; dma_addr_t rx_dma[RX_RING]; unsigned int rx_buf_sz; + unsigned int pkt_limit; struct timer_list oom_kick; struct timer_list nic_poll; @@ -484,7 +514,7 @@ struct fe_priv { /* * tx specific fields. */ - struct ring_desc *tx_ring; + ring_type tx_ring; unsigned int next_tx, nic_tx; struct sk_buff *tx_skbuff[TX_RING]; dma_addr_t tx_dma[TX_RING]; @@ -519,6 +549,11 @@ static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v) & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2); } +static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v) +{ + return le32_to_cpu(prd->FlagLen) & LEN_MASK_V2; +} + static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target, int delay, int delaymax, const char *msg) { @@ -792,7 +827,7 @@ static int nv_alloc_rx(struct net_device *dev) nr = refill_rx % RX_RING; if (np->rx_skbuff[nr] == NULL) { - skb = dev_alloc_skb(RX_ALLOC_BUFSIZE); + skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD); if (!skb) break; @@ -803,9 +838,16 @@ static int nv_alloc_rx(struct net_device *dev) } np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len, PCI_DMA_FROMDEVICE); - np->rx_ring[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]); - wmb(); - np->rx_ring[nr].FlagLen = cpu_to_le32(RX_NIC_BUFSIZE | NV_RX_AVAIL); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->rx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]); + wmb(); + np->rx_ring.orig[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL); + } else { + np->rx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->rx_dma[nr]) >> 32; + np->rx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF; + wmb(); + np->rx_ring.ex[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL); + } dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n", dev->name, refill_rx); refill_rx++; @@ -831,19 +873,37 @@ static void nv_do_rx_refill(unsigned long data) enable_irq(dev->irq); } -static int nv_init_ring(struct net_device *dev) +static void nv_init_rx(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); int i; - np->next_tx = np->nic_tx = 0; - for (i = 0; i < TX_RING; i++) - np->tx_ring[i].FlagLen = 0; - np->cur_rx = RX_RING; np->refill_rx = 0; for (i = 0; i < RX_RING; i++) - np->rx_ring[i].FlagLen = 0; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->rx_ring.orig[i].FlagLen = 0; + else + np->rx_ring.ex[i].FlagLen = 0; +} + +static void nv_init_tx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int i; + + np->next_tx = np->nic_tx = 0; + for (i = 0; i < TX_RING; i++) + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->tx_ring.orig[i].FlagLen = 0; + else + np->tx_ring.ex[i].FlagLen = 0; +} + +static int nv_init_ring(struct net_device *dev) +{ + nv_init_tx(dev); + nv_init_rx(dev); return nv_alloc_rx(dev); } @@ -852,7 +912,10 @@ static void nv_drain_tx(struct net_device *dev) struct fe_priv *np = get_nvpriv(dev); int i; for (i = 0; i < TX_RING; i++) { - np->tx_ring[i].FlagLen = 0; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->tx_ring.orig[i].FlagLen = 0; + else + np->tx_ring.ex[i].FlagLen = 0; if (np->tx_skbuff[i]) { pci_unmap_single(np->pci_dev, np->tx_dma[i], np->tx_skbuff[i]->len, @@ -869,7 +932,10 @@ static void nv_drain_rx(struct net_device *dev) struct fe_priv *np = get_nvpriv(dev); int i; for (i = 0; i < RX_RING; i++) { - np->rx_ring[i].FlagLen = 0; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->rx_ring.orig[i].FlagLen = 0; + else + np->rx_ring.ex[i].FlagLen = 0; wmb(); if (np->rx_skbuff[i]) { pci_unmap_single(np->pci_dev, np->rx_dma[i], @@ -900,11 +966,19 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len, PCI_DMA_TODEVICE); - np->tx_ring[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + else { + np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; + np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; + } spin_lock_irq(&np->lock); wmb(); - np->tx_ring[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); + else + np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n", dev->name, np->next_tx); { @@ -942,7 +1016,10 @@ static void nv_tx_done(struct net_device *dev) while (np->nic_tx != np->next_tx) { i = np->nic_tx % TX_RING; - Flags = le32_to_cpu(np->tx_ring[i].FlagLen); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen); + else + Flags = le32_to_cpu(np->tx_ring.ex[i].FlagLen); dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n", dev->name, np->nic_tx, Flags); @@ -993,9 +1070,56 @@ static void nv_tx_timeout(struct net_device *dev) struct fe_priv *np = get_nvpriv(dev); u8 __iomem *base = get_hwbase(dev); - dprintk(KERN_DEBUG "%s: Got tx_timeout. irq: %08x\n", dev->name, + printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name, readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK); + { + int i; + + printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n", + dev->name, (unsigned long)np->ring_addr, + np->next_tx, np->nic_tx); + printk(KERN_INFO "%s: Dumping tx registers\n", dev->name); + for (i=0;i<0x400;i+= 32) { + printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n", + i, + readl(base + i + 0), readl(base + i + 4), + readl(base + i + 8), readl(base + i + 12), + readl(base + i + 16), readl(base + i + 20), + readl(base + i + 24), readl(base + i + 28)); + } + printk(KERN_INFO "%s: Dumping tx ring\n", dev->name); + for (i=0;i<TX_RING;i+= 4) { + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n", + i, + le32_to_cpu(np->tx_ring.orig[i].PacketBuffer), + le32_to_cpu(np->tx_ring.orig[i].FlagLen), + le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer), + le32_to_cpu(np->tx_ring.orig[i+1].FlagLen), + le32_to_cpu(np->tx_ring.orig[i+2].PacketBuffer), + le32_to_cpu(np->tx_ring.orig[i+2].FlagLen), + le32_to_cpu(np->tx_ring.orig[i+3].PacketBuffer), + le32_to_cpu(np->tx_ring.orig[i+3].FlagLen)); + } else { + printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n", + i, + le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh), + le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow), + le32_to_cpu(np->tx_ring.ex[i].FlagLen), + le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferHigh), + le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferLow), + le32_to_cpu(np->tx_ring.ex[i+1].FlagLen), + le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferHigh), + le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferLow), + le32_to_cpu(np->tx_ring.ex[i+2].FlagLen), + le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferHigh), + le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferLow), + le32_to_cpu(np->tx_ring.ex[i+3].FlagLen)); + } + } + } + spin_lock_irq(&np->lock); /* 1) stop tx engine */ @@ -1009,7 +1133,10 @@ static void nv_tx_timeout(struct net_device *dev) printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name); nv_drain_tx(dev); np->next_tx = np->nic_tx = 0; - writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + else + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); netif_wake_queue(dev); } @@ -1084,8 +1211,13 @@ static void nv_rx_process(struct net_device *dev) break; /* we scanned the whole ring - do not continue */ i = np->cur_rx % RX_RING; - Flags = le32_to_cpu(np->rx_ring[i].FlagLen); - len = nv_descr_getlength(&np->rx_ring[i], np->desc_ver); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen); + len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver); + } else { + Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen); + len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver); + } dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n", dev->name, np->cur_rx, Flags); @@ -1207,15 +1339,133 @@ next_pkt: } } +static void set_bufsize(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + + if (dev->mtu <= ETH_DATA_LEN) + np->rx_buf_sz = ETH_DATA_LEN + NV_RX_HEADERS; + else + np->rx_buf_sz = dev->mtu + NV_RX_HEADERS; +} + /* * nv_change_mtu: dev->change_mtu function * Called with dev_base_lock held for read. */ static int nv_change_mtu(struct net_device *dev, int new_mtu) { - if (new_mtu > ETH_DATA_LEN) + struct fe_priv *np = get_nvpriv(dev); + int old_mtu; + + if (new_mtu < 64 || new_mtu > np->pkt_limit) return -EINVAL; + + old_mtu = dev->mtu; dev->mtu = new_mtu; + + /* return early if the buffer sizes will not change */ + if (old_mtu <= ETH_DATA_LEN && new_mtu <= ETH_DATA_LEN) + return 0; + if (old_mtu == new_mtu) + return 0; + + /* synchronized against open : rtnl_lock() held by caller */ + if (netif_running(dev)) { + u8 *base = get_hwbase(dev); + /* + * It seems that the nic preloads valid ring entries into an + * internal buffer. The procedure for flushing everything is + * guessed, there is probably a simpler approach. + * Changing the MTU is a rare event, it shouldn't matter. + */ + disable_irq(dev->irq); + spin_lock_bh(&dev->xmit_lock); + spin_lock(&np->lock); + /* stop engines */ + nv_stop_rx(dev); + nv_stop_tx(dev); + nv_txrx_reset(dev); + /* drain rx queue */ + nv_drain_rx(dev); + nv_drain_tx(dev); + /* reinit driver view of the rx queue */ + nv_init_rx(dev); + nv_init_tx(dev); + /* alloc new rx buffers */ + set_bufsize(dev); + if (nv_alloc_rx(dev)) { + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + } + /* reinit nic view of the rx queue */ + writel(np->rx_buf_sz, base + NvRegOffloadConfig); + writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + else + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); + writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), + base + NvRegRingSizes); + pci_push(base); + writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl); + pci_push(base); + + /* restart rx engine */ + nv_start_rx(dev); + nv_start_tx(dev); + spin_unlock(&np->lock); + spin_unlock_bh(&dev->xmit_lock); + enable_irq(dev->irq); + } + return 0; +} + +static void nv_copy_mac_to_hw(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + u32 mac[2]; + + mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + + (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24); + mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8); + + writel(mac[0], base + NvRegMacAddrA); + writel(mac[1], base + NvRegMacAddrB); +} + +/* + * nv_set_mac_address: dev->set_mac_address function + * Called with rtnl_lock() held. + */ +static int nv_set_mac_address(struct net_device *dev, void *addr) +{ + struct fe_priv *np = get_nvpriv(dev); + struct sockaddr *macaddr = (struct sockaddr*)addr; + + if(!is_valid_ether_addr(macaddr->sa_data)) + return -EADDRNOTAVAIL; + + /* synchronized against open : rtnl_lock() held by caller */ + memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN); + + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + spin_lock_irq(&np->lock); + + /* stop rx engine */ + nv_stop_rx(dev); + + /* set mac address */ + nv_copy_mac_to_hw(dev); + + /* restart rx engine */ + nv_start_rx(dev); + spin_unlock_irq(&np->lock); + spin_unlock_bh(&dev->xmit_lock); + } else { + nv_copy_mac_to_hw(dev); + } return 0; } @@ -1470,7 +1720,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) if (!(events & np->irqmask)) break; - if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) { + if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_ERROR|NVREG_IRQ_TX_ERR)) { spin_lock(&np->lock); nv_tx_done(dev); spin_unlock(&np->lock); @@ -1761,6 +2011,50 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) return 0; } +#define FORCEDETH_REGS_VER 1 +#define FORCEDETH_REGS_SIZE 0x400 /* 256 32-bit registers */ + +static int nv_get_regs_len(struct net_device *dev) +{ + return FORCEDETH_REGS_SIZE; +} + +static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 __iomem *base = get_hwbase(dev); + u32 *rbuf = buf; + int i; + + regs->version = FORCEDETH_REGS_VER; + spin_lock_irq(&np->lock); + for (i=0;i<FORCEDETH_REGS_SIZE/sizeof(u32);i++) + rbuf[i] = readl(base + i*sizeof(u32)); + spin_unlock_irq(&np->lock); +} + +static int nv_nway_reset(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int ret; + + spin_lock_irq(&np->lock); + if (np->autoneg) { + int bmcr; + + bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); + bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); + mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); + + ret = 0; + } else { + ret = -EINVAL; + } + spin_unlock_irq(&np->lock); + + return ret; +} + static struct ethtool_ops ops = { .get_drvinfo = nv_get_drvinfo, .get_link = ethtool_op_get_link, @@ -1768,6 +2062,9 @@ static struct ethtool_ops ops = { .set_wol = nv_set_wol, .get_settings = nv_get_settings, .set_settings = nv_set_settings, + .get_regs_len = nv_get_regs_len, + .get_regs = nv_get_regs, + .nway_reset = nv_nway_reset, }; static int nv_open(struct net_device *dev) @@ -1792,6 +2089,7 @@ static int nv_open(struct net_device *dev) writel(0, base + NvRegAdapterControl); /* 2) initialize descriptor rings */ + set_bufsize(dev); oom = nv_init_ring(dev); writel(0, base + NvRegLinkSpeed); @@ -1802,20 +2100,14 @@ static int nv_open(struct net_device *dev) np->in_shutdown = 0; /* 3) set mac address */ - { - u32 mac[2]; - - mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + - (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24); - mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8); - - writel(mac[0], base + NvRegMacAddrA); - writel(mac[1], base + NvRegMacAddrB); - } + nv_copy_mac_to_hw(dev); /* 4) give hw rings */ writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); - writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + else + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes); @@ -1837,7 +2129,7 @@ static int nv_open(struct net_device *dev) writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1); writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus); writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags); - writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig); + writel(np->rx_buf_sz, base + NvRegOffloadConfig); writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus); get_random_bytes(&i, sizeof(i)); @@ -1888,6 +2180,9 @@ static int nv_open(struct net_device *dev) writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat); } + /* set linkspeed to invalid value, thus force nv_update_linkspeed + * to init hw */ + np->linkspeed = 0; ret = nv_update_linkspeed(dev); nv_start_rx(dev); nv_start_tx(dev); @@ -1942,6 +2237,12 @@ static int nv_close(struct net_device *dev) if (np->wolenabled) nv_start_rx(dev); + /* special op: write back the misordered MAC address - otherwise + * the next nv_probe would see a wrong address. + */ + writel(np->orig_mac[0], base + NvRegMacAddrA); + writel(np->orig_mac[1], base + NvRegMacAddrB); + /* FIXME: power down nic */ return 0; @@ -2006,32 +2307,55 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i } /* handle different descriptor versions */ - if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 || - pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 || - pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3 || - pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 || - pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_13) - np->desc_ver = DESC_VER_1; - else + if (id->driver_data & DEV_HAS_HIGH_DMA) { + /* packet format 3: supports 40-bit addressing */ + np->desc_ver = DESC_VER_3; + if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) { + printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n", + pci_name(pci_dev)); + } + } else if (id->driver_data & DEV_HAS_LARGEDESC) { + /* packet format 2: supports jumbo frames */ np->desc_ver = DESC_VER_2; + } else { + /* original packet format */ + np->desc_ver = DESC_VER_1; + } + + np->pkt_limit = NV_PKTLIMIT_1; + if (id->driver_data & DEV_HAS_LARGEDESC) + np->pkt_limit = NV_PKTLIMIT_2; err = -ENOMEM; np->base = ioremap(addr, NV_PCI_REGSZ); if (!np->base) goto out_relreg; dev->base_addr = (unsigned long)np->base; + dev->irq = pci_dev->irq; - np->rx_ring = pci_alloc_consistent(pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), - &np->ring_addr); - if (!np->rx_ring) - goto out_unmap; - np->tx_ring = &np->rx_ring[RX_RING]; + + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->rx_ring.orig = pci_alloc_consistent(pci_dev, + sizeof(struct ring_desc) * (RX_RING + TX_RING), + &np->ring_addr); + if (!np->rx_ring.orig) + goto out_unmap; + np->tx_ring.orig = &np->rx_ring.orig[RX_RING]; + } else { + np->rx_ring.ex = pci_alloc_consistent(pci_dev, + sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), + &np->ring_addr); + if (!np->rx_ring.ex) + goto out_unmap; + np->tx_ring.ex = &np->rx_ring.ex[RX_RING]; + } dev->open = nv_open; dev->stop = nv_close; dev->hard_start_xmit = nv_start_xmit; dev->get_stats = nv_get_stats; dev->change_mtu = nv_change_mtu; + dev->set_mac_address = nv_set_mac_address; dev->set_multicast_list = nv_set_multicast; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = nv_poll_controller; @@ -2080,17 +2404,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (np->desc_ver == DESC_VER_1) { np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID; - if (id->driver_data & DEV_NEED_LASTPACKET1) - np->tx_flags |= NV_TX_LASTPACKET1; } else { np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID; - if (id->driver_data & DEV_NEED_LASTPACKET1) - np->tx_flags |= NV_TX2_LASTPACKET1; } - if (id->driver_data & DEV_IRQMASK_1) - np->irqmask = NVREG_IRQMASK_WANTED_1; - if (id->driver_data & DEV_IRQMASK_2) - np->irqmask = NVREG_IRQMASK_WANTED_2; + np->irqmask = NVREG_IRQMASK_WANTED; if (id->driver_data & DEV_NEED_TIMERIRQ) np->irqmask |= NVREG_IRQ_TIMER; if (id->driver_data & DEV_NEED_LINKTIMER) { @@ -2155,8 +2472,12 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i return 0; out_freering: - pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), - np->rx_ring, np->ring_addr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), + np->rx_ring.orig, np->ring_addr); + else + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), + np->rx_ring.ex, np->ring_addr); pci_set_drvdata(pci_dev, NULL); out_unmap: iounmap(get_hwbase(dev)); @@ -2174,18 +2495,14 @@ static void __devexit nv_remove(struct pci_dev *pci_dev) { struct net_device *dev = pci_get_drvdata(pci_dev); struct fe_priv *np = get_nvpriv(dev); - u8 __iomem *base = get_hwbase(dev); unregister_netdev(dev); - /* special op: write back the misordered MAC address - otherwise - * the next nv_probe would see a wrong address. - */ - writel(np->orig_mac[0], base + NvRegMacAddrA); - writel(np->orig_mac[1], base + NvRegMacAddrB); - /* free all structures */ - pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring, np->ring_addr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring.orig, np->ring_addr); + else + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), np->rx_ring.ex, np->ring_addr); iounmap(get_hwbase(dev)); pci_release_regions(pci_dev); pci_disable_device(pci_dev); @@ -2195,109 +2512,64 @@ static void __devexit nv_remove(struct pci_dev *pci_dev) static struct pci_device_id pci_tbl[] = { { /* nForce Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_1), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce2 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_2), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_3), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_5, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_6, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_7, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, }, { /* CK804 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_8, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, }, { /* CK804 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_9, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, }, { /* MCP04 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_10, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, }, { /* MCP04 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_11, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, }, { /* MCP51 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_12, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA, }, { /* MCP51 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_13, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA, }, { /* MCP55 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_14, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, }, { /* MCP55 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_15, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, }, {0,}, }; diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index f9e3be96963..0b230222bfe 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -308,12 +308,6 @@ static int sp_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr_ax25 *sa = addr; - if (sa->sax25_family != AF_AX25) - return -EINVAL; - - if (!sa->sax25_ndigis) - return -EINVAL; - spin_lock_irq(&dev->xmit_lock); memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN); spin_unlock_irq(&dev->xmit_lock); @@ -668,6 +662,9 @@ static int sixpack_open(struct tty_struct *tty) netif_start_queue(dev); init_timer(&sp->tx_t); + sp->tx_t.function = sp_xmit_on_air; + sp->tx_t.data = (unsigned long) sp; + init_timer(&sp->resync_t); spin_unlock_bh(&sp->lock); diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig index 0cd54306e63..de087cd609d 100644 --- a/drivers/net/hamradio/Kconfig +++ b/drivers/net/hamradio/Kconfig @@ -1,6 +1,6 @@ config MKISS tristate "Serial port KISS driver" - depends on AX25 && BROKEN_ON_SMP + depends on AX25 ---help--- KISS is a protocol used for the exchange of data between a computer and a Terminal Node Controller (a small embedded system commonly diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index a7f15d9f13e..5298096afbd 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -54,6 +54,7 @@ #include <linux/kmod.h> #include <linux/hdlcdrv.h> #include <linux/baycom.h> +#include <linux/jiffies.h> #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) /* prototypes for ax25_encapsulate and ax25_rebuild_header */ #include <net/ax25.h> @@ -287,7 +288,7 @@ static inline void baycom_int_freq(struct baycom_state *bc) * measure the interrupt frequency */ bc->debug_vals.cur_intcnt++; - if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { + if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { bc->debug_vals.last_jiffies = cur_jiffies; bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; bc->debug_vals.cur_intcnt = 0; diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c index 612ad452bee..3b1bef1ee21 100644 --- a/drivers/net/hamradio/baycom_par.c +++ b/drivers/net/hamradio/baycom_par.c @@ -84,6 +84,7 @@ #include <linux/baycom.h> #include <linux/parport.h> #include <linux/bitops.h> +#include <linux/jiffies.h> #include <asm/bug.h> #include <asm/system.h> @@ -165,7 +166,7 @@ static void __inline__ baycom_int_freq(struct baycom_state *bc) * measure the interrupt frequency */ bc->debug_vals.cur_intcnt++; - if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { + if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { bc->debug_vals.last_jiffies = cur_jiffies; bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; bc->debug_vals.cur_intcnt = 0; diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c index 25f270b0537..232793d2ce6 100644 --- a/drivers/net/hamradio/baycom_ser_fdx.c +++ b/drivers/net/hamradio/baycom_ser_fdx.c @@ -79,6 +79,7 @@ #include <asm/io.h> #include <linux/hdlcdrv.h> #include <linux/baycom.h> +#include <linux/jiffies.h> /* --------------------------------------------------------------------- */ @@ -159,7 +160,7 @@ static inline void baycom_int_freq(struct baycom_state *bc) * measure the interrupt frequency */ bc->debug_vals.cur_intcnt++; - if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { + if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { bc->debug_vals.last_jiffies = cur_jiffies; bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; bc->debug_vals.cur_intcnt = 0; diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c index eead85d0096..be596a3eb3f 100644 --- a/drivers/net/hamradio/baycom_ser_hdx.c +++ b/drivers/net/hamradio/baycom_ser_hdx.c @@ -69,6 +69,7 @@ #include <asm/io.h> #include <linux/hdlcdrv.h> #include <linux/baycom.h> +#include <linux/jiffies.h> /* --------------------------------------------------------------------- */ @@ -150,7 +151,7 @@ static inline void baycom_int_freq(struct baycom_state *bc) * measure the interrupt frequency */ bc->debug_vals.cur_intcnt++; - if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { + if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { bc->debug_vals.last_jiffies = cur_jiffies; bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; bc->debug_vals.cur_intcnt = 0; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 3035422f5ad..63b1a2b86ac 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -1,30 +1,19 @@ /* - * MKISS Driver + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. * - * This module: - * This module 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 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. * - * This module implements the AX.25 protocol for kernel-based - * devices like TTYs. It interfaces between a raw TTY, and the - * kernel's AX.25 protocol layers, just like slip.c. - * AX.25 needs to be separated from slip.c while slip.c is no - * longer a static kernel device since it is a module. - * This method clears the way to implement other kiss protocols - * like mkiss smack g8bpq ..... so far only mkiss is implemented. + * 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. * - * Hans Alblas <hans@esrac.ele.tue.nl> - * - * History - * Jonathan (G4KLX) Fixed to match Linux networking changes - 2.1.15. - * Matthias (DG2FEF) Added support for FlexNet CRC (on special request) - * Fixed bug in ax25_close(): dev_lock_wait() was - * called twice, causing a deadlock. - * Jeroen (PE1RXQ) Removed old MKISS_MAGIC stuff and calls to - * MOD_*_USE_COUNT - * Remove cli() and fix rtnl lock usage. + * Copyright (C) Hans Alblas PE1AYX <hans@esrac.ele.tue.nl> + * Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org> */ #include <linux/config.h> @@ -46,177 +35,300 @@ #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/if_arp.h> +#include <linux/jiffies.h> #include <net/ax25.h> -#include "mkiss.h" - #ifdef CONFIG_INET #include <linux/ip.h> #include <linux/tcp.h> #endif -static char banner[] __initdata = KERN_INFO "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n"; - -typedef struct ax25_ctrl { - struct ax_disp ctrl; /* */ - struct net_device dev; /* the device */ -} ax25_ctrl_t; - -static ax25_ctrl_t **ax25_ctrls; - -int ax25_maxdev = AX25_MAXDEV; /* Can be overridden with insmod! */ - -static struct tty_ldisc ax_ldisc; - -static int ax25_init(struct net_device *); -static int kiss_esc(unsigned char *, unsigned char *, int); -static int kiss_esc_crc(unsigned char *, unsigned char *, unsigned short, int); -static void kiss_unesc(struct ax_disp *, unsigned char); +#define AX_MTU 236 + +/* SLIP/KISS protocol characters. */ +#define END 0300 /* indicates end of frame */ +#define ESC 0333 /* indicates byte stuffing */ +#define ESC_END 0334 /* ESC ESC_END means END 'data' */ +#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ + +struct mkiss { + struct tty_struct *tty; /* ptr to TTY structure */ + struct net_device *dev; /* easy for intr handling */ + + /* These are pointers to the malloc()ed frame buffers. */ + spinlock_t buflock;/* lock for rbuf and xbuf */ + unsigned char *rbuff; /* receiver buffer */ + int rcount; /* received chars counter */ + unsigned char *xbuff; /* transmitter buffer */ + unsigned char *xhead; /* pointer to next byte to XMIT */ + int xleft; /* bytes left in XMIT queue */ + + struct net_device_stats stats; + + /* Detailed SLIP statistics. */ + int mtu; /* Our mtu (to spot changes!) */ + int buffsize; /* Max buffers sizes */ + + unsigned long flags; /* Flag values/ mode etc */ + /* long req'd: used by set_bit --RR */ +#define AXF_INUSE 0 /* Channel in use */ +#define AXF_ESCAPE 1 /* ESC received */ +#define AXF_ERROR 2 /* Parity, etc. error */ +#define AXF_KEEPTEST 3 /* Keepalive test flag */ +#define AXF_OUTWAIT 4 /* is outpacket was flag */ + + int mode; + int crcmode; /* MW: for FlexNet, SMACK etc. */ +#define CRC_MODE_NONE 0 +#define CRC_MODE_FLEX 1 +#define CRC_MODE_SMACK 2 + + atomic_t refcnt; + struct semaphore dead_sem; +}; /*---------------------------------------------------------------------------*/ -static const unsigned short Crc_flex_table[] = { - 0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38, - 0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770, - 0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9, - 0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1, - 0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a, - 0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672, - 0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb, - 0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3, - 0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c, - 0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574, - 0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd, - 0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5, - 0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e, - 0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476, - 0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf, - 0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7, - 0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30, - 0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378, - 0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1, - 0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9, - 0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32, - 0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a, - 0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3, - 0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb, - 0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34, - 0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c, - 0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5, - 0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd, - 0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36, - 0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e, - 0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7, - 0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff +static const unsigned short crc_flex_table[] = { + 0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38, + 0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770, + 0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9, + 0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1, + 0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a, + 0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672, + 0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb, + 0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3, + 0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c, + 0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574, + 0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd, + 0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5, + 0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e, + 0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476, + 0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf, + 0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7, + 0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30, + 0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378, + 0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1, + 0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9, + 0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32, + 0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a, + 0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3, + 0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb, + 0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34, + 0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c, + 0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5, + 0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd, + 0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36, + 0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e, + 0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7, + 0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff }; -/*---------------------------------------------------------------------------*/ - static unsigned short calc_crc_flex(unsigned char *cp, int size) { - unsigned short crc = 0xffff; - - while (size--) - crc = (crc << 8) ^ Crc_flex_table[((crc >> 8) ^ *cp++) & 0xff]; + unsigned short crc = 0xffff; - return crc; -} + while (size--) + crc = (crc << 8) ^ crc_flex_table[((crc >> 8) ^ *cp++) & 0xff]; -/*---------------------------------------------------------------------------*/ + return crc; +} static int check_crc_flex(unsigned char *cp, int size) { - unsigned short crc = 0xffff; + unsigned short crc = 0xffff; - if (size < 3) - return -1; + if (size < 3) + return -1; - while (size--) - crc = (crc << 8) ^ Crc_flex_table[((crc >> 8) ^ *cp++) & 0xff]; + while (size--) + crc = (crc << 8) ^ crc_flex_table[((crc >> 8) ^ *cp++) & 0xff]; - if ((crc & 0xffff) != 0x7070) - return -1; + if ((crc & 0xffff) != 0x7070) + return -1; - return 0; + return 0; } -/*---------------------------------------------------------------------------*/ +/* + * Standard encapsulation + */ -/* Find a free channel, and link in this `tty' line. */ -static inline struct ax_disp *ax_alloc(void) +static int kiss_esc(unsigned char *s, unsigned char *d, int len) { - ax25_ctrl_t *axp=NULL; - int i; + unsigned char *ptr = d; + unsigned char c; - for (i = 0; i < ax25_maxdev; i++) { - axp = ax25_ctrls[i]; + /* + * Send an initial END character to flush out any data that may have + * accumulated in the receiver due to line noise. + */ - /* Not allocated ? */ - if (axp == NULL) - break; + *ptr++ = END; - /* Not in use ? */ - if (!test_and_set_bit(AXF_INUSE, &axp->ctrl.flags)) + while (len-- > 0) { + switch (c = *s++) { + case END: + *ptr++ = ESC; + *ptr++ = ESC_END; break; + case ESC: + *ptr++ = ESC; + *ptr++ = ESC_ESC; + break; + default: + *ptr++ = c; + break; + } } - /* Sorry, too many, all slots in use */ - if (i >= ax25_maxdev) - return NULL; + *ptr++ = END; + + return ptr - d; +} + +/* + * MW: + * OK its ugly, but tell me a better solution without copying the + * packet to a temporary buffer :-) + */ +static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, + int len) +{ + unsigned char *ptr = d; + unsigned char c=0; + + *ptr++ = END; + while (len > 0) { + if (len > 2) + c = *s++; + else if (len > 1) + c = crc >> 8; + else if (len > 0) + c = crc & 0xff; + + len--; - /* If no channels are available, allocate one */ - if (axp == NULL && (ax25_ctrls[i] = kmalloc(sizeof(ax25_ctrl_t), GFP_KERNEL)) != NULL) { - axp = ax25_ctrls[i]; + switch (c) { + case END: + *ptr++ = ESC; + *ptr++ = ESC_END; + break; + case ESC: + *ptr++ = ESC; + *ptr++ = ESC_ESC; + break; + default: + *ptr++ = c; + break; + } } - memset(axp, 0, sizeof(ax25_ctrl_t)); - - /* Initialize channel control data */ - set_bit(AXF_INUSE, &axp->ctrl.flags); - sprintf(axp->dev.name, "ax%d", i++); - axp->ctrl.tty = NULL; - axp->dev.base_addr = i; - axp->dev.priv = (void *)&axp->ctrl; - axp->dev.next = NULL; - axp->dev.init = ax25_init; - - if (axp != NULL) { - /* - * register device so that it can be ifconfig'ed - * ax25_init() will be called as a side-effect - * SIDE-EFFECT WARNING: ax25_init() CLEARS axp->ctrl ! - */ - if (register_netdev(&axp->dev) == 0) { - /* (Re-)Set the INUSE bit. Very Important! */ - set_bit(AXF_INUSE, &axp->ctrl.flags); - axp->ctrl.dev = &axp->dev; - axp->dev.priv = (void *) &axp->ctrl; - - return &axp->ctrl; - } else { - clear_bit(AXF_INUSE,&axp->ctrl.flags); - printk(KERN_ERR "mkiss: ax_alloc() - register_netdev() failure.\n"); + *ptr++ = END; + + return ptr - d; +} + +/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ +static void ax_bump(struct mkiss *ax) +{ + struct sk_buff *skb; + int count; + + spin_lock_bh(&ax->buflock); + if (ax->rbuff[0] > 0x0f) { + if (ax->rbuff[0] & 0x20) { + ax->crcmode = CRC_MODE_FLEX; + if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { + ax->stats.rx_errors++; + return; + } + ax->rcount -= 2; + /* dl9sau bugfix: the trailling two bytes flexnet crc + * will not be passed to the kernel. thus we have + * to correct the kissparm signature, because it + * indicates a crc but there's none + */ + *ax->rbuff &= ~0x20; } + } + spin_unlock_bh(&ax->buflock); + + count = ax->rcount; + + if ((skb = dev_alloc_skb(count)) == NULL) { + printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", + ax->dev->name); + ax->stats.rx_dropped++; + return; } - return NULL; + spin_lock_bh(&ax->buflock); + memcpy(skb_put(skb,count), ax->rbuff, count); + spin_unlock_bh(&ax->buflock); + skb->protocol = ax25_type_trans(skb, ax->dev); + netif_rx(skb); + ax->dev->last_rx = jiffies; + ax->stats.rx_packets++; + ax->stats.rx_bytes += count; } -/* Free an AX25 channel. */ -static inline void ax_free(struct ax_disp *ax) +static void kiss_unesc(struct mkiss *ax, unsigned char s) { - /* Free all AX25 frame buffers. */ - if (ax->rbuff) - kfree(ax->rbuff); - ax->rbuff = NULL; - if (ax->xbuff) - kfree(ax->xbuff); - ax->xbuff = NULL; - if (!test_and_clear_bit(AXF_INUSE, &ax->flags)) - printk(KERN_ERR "mkiss: %s: ax_free for already free unit.\n", ax->dev->name); + switch (s) { + case END: + /* drop keeptest bit = VSV */ + if (test_bit(AXF_KEEPTEST, &ax->flags)) + clear_bit(AXF_KEEPTEST, &ax->flags); + + if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2)) + ax_bump(ax); + + clear_bit(AXF_ESCAPE, &ax->flags); + ax->rcount = 0; + return; + + case ESC: + set_bit(AXF_ESCAPE, &ax->flags); + return; + case ESC_ESC: + if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) + s = ESC; + break; + case ESC_END: + if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) + s = END; + break; + } + + spin_lock_bh(&ax->buflock); + if (!test_bit(AXF_ERROR, &ax->flags)) { + if (ax->rcount < ax->buffsize) { + ax->rbuff[ax->rcount++] = s; + spin_unlock_bh(&ax->buflock); + return; + } + + ax->stats.rx_over_errors++; + set_bit(AXF_ERROR, &ax->flags); + } + spin_unlock_bh(&ax->buflock); +} + +static int ax_set_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr_ax25 *sa = addr; + + spin_lock_irq(&dev->xmit_lock); + memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN); + spin_unlock_irq(&dev->xmit_lock); + + return 0; } -static void ax_changedmtu(struct ax_disp *ax) +/*---------------------------------------------------------------------------*/ + +static void ax_changedmtu(struct mkiss *ax) { struct net_device *dev = ax->dev; unsigned char *xbuff, *rbuff, *oxbuff, *orbuff; @@ -236,7 +348,8 @@ static void ax_changedmtu(struct ax_disp *ax) rbuff = kmalloc(len + 4, GFP_ATOMIC); if (xbuff == NULL || rbuff == NULL) { - printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, MTU change cancelled.\n", + printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, " + "MTU change cancelled.\n", ax->dev->name); dev->mtu = ax->mtu; if (xbuff != NULL) @@ -258,7 +371,7 @@ static void ax_changedmtu(struct ax_disp *ax) memcpy(ax->xbuff, ax->xhead, ax->xleft); } else { ax->xleft = 0; - ax->tx_dropped++; + ax->stats.tx_dropped++; } } @@ -269,7 +382,7 @@ static void ax_changedmtu(struct ax_disp *ax) memcpy(ax->rbuff, orbuff, ax->rcount); } else { ax->rcount = 0; - ax->rx_over_errors++; + ax->stats.rx_over_errors++; set_bit(AXF_ERROR, &ax->flags); } } @@ -279,72 +392,14 @@ static void ax_changedmtu(struct ax_disp *ax) spin_unlock_bh(&ax->buflock); - if (oxbuff != NULL) - kfree(oxbuff); - if (orbuff != NULL) - kfree(orbuff); -} - - -/* Set the "sending" flag. This must be atomic. */ -static inline void ax_lock(struct ax_disp *ax) -{ - netif_stop_queue(ax->dev); -} - - -/* Clear the "sending" flag. This must be atomic. */ -static inline void ax_unlock(struct ax_disp *ax) -{ - netif_start_queue(ax->dev); -} - -/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ -static void ax_bump(struct ax_disp *ax) -{ - struct sk_buff *skb; - int count; - - spin_lock_bh(&ax->buflock); - if (ax->rbuff[0] > 0x0f) { - if (ax->rbuff[0] & 0x20) { - ax->crcmode = CRC_MODE_FLEX; - if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { - ax->rx_errors++; - return; - } - ax->rcount -= 2; - /* dl9sau bugfix: the trailling two bytes flexnet crc - * will not be passed to the kernel. thus we have - * to correct the kissparm signature, because it - * indicates a crc but there's none - */ - *ax->rbuff &= ~0x20; - } - } - spin_unlock_bh(&ax->buflock); - - count = ax->rcount; - - if ((skb = dev_alloc_skb(count)) == NULL) { - printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", ax->dev->name); - ax->rx_dropped++; - return; - } - - spin_lock_bh(&ax->buflock); - memcpy(skb_put(skb,count), ax->rbuff, count); - spin_unlock_bh(&ax->buflock); - skb->protocol = ax25_type_trans(skb, ax->dev); - netif_rx(skb); - ax->dev->last_rx = jiffies; - ax->rx_packets++; - ax->rx_bytes+=count; + kfree(oxbuff); + kfree(orbuff); } /* Encapsulate one AX.25 packet and stuff into a TTY queue. */ -static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len) +static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) { + struct mkiss *ax = netdev_priv(dev); unsigned char *p; int actual, count; @@ -354,8 +409,8 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len) if (len > ax->mtu) { /* Sigh, shouldn't occur BUT ... */ len = ax->mtu; printk(KERN_ERR "mkiss: %s: truncating oversized transmit packet!\n", ax->dev->name); - ax->tx_dropped++; - ax_unlock(ax); + ax->stats.tx_dropped++; + netif_start_queue(dev); return; } @@ -376,10 +431,11 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len) break; } - ax->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); actual = ax->tty->driver->write(ax->tty, ax->xbuff, count); - ax->tx_packets++; - ax->tx_bytes+=actual; + ax->stats.tx_packets++; + ax->stats.tx_bytes += actual; + ax->dev->trans_start = jiffies; ax->xleft = count - actual; ax->xhead = ax->xbuff + actual; @@ -387,37 +443,10 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len) spin_unlock_bh(&ax->buflock); } -/* - * Called by the driver when there's room for more data. If we have - * more packets to send, we send them here. - */ -static void ax25_write_wakeup(struct tty_struct *tty) -{ - int actual; - struct ax_disp *ax = (struct ax_disp *) tty->disc_data; - - /* First make sure we're connected. */ - if (ax == NULL || ax->magic != AX25_MAGIC || !netif_running(ax->dev)) - return; - if (ax->xleft <= 0) { - /* Now serial buffer is almost free & we can start - * transmission of another packet - */ - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - - netif_wake_queue(ax->dev); - return; - } - - actual = tty->driver->write(tty, ax->xhead, ax->xleft); - ax->xleft -= actual; - ax->xhead += actual; -} - /* Encapsulate an AX.25 packet and kick it into a TTY queue. */ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ax_disp *ax = netdev_priv(dev); + struct mkiss *ax = netdev_priv(dev); if (!netif_running(dev)) { printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name); @@ -429,7 +458,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) * May be we must check transmitter timeout here ? * 14 Oct 1994 Dmitry Gorodchanin. */ - if (jiffies - dev->trans_start < 20 * HZ) { + if (time_before(jiffies, dev->trans_start + 20 * HZ)) { /* 20 sec timeout not reached */ return 1; } @@ -439,20 +468,30 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) "bad line quality" : "driver error"); ax->xleft = 0; - ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - ax_unlock(ax); + clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); + netif_start_queue(dev); } /* We were not busy, so we are now... :-) */ if (skb != NULL) { - ax_lock(ax); - ax_encaps(ax, skb->data, skb->len); + netif_stop_queue(dev); + ax_encaps(dev, skb->data, skb->len); kfree_skb(skb); } return 0; } +static int ax_open_dev(struct net_device *dev) +{ + struct mkiss *ax = netdev_priv(dev); + + if (ax->tty == NULL) + return -ENODEV; + + return 0; +} + #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) /* Return the frame type ID */ @@ -481,7 +520,7 @@ static int ax_rebuild_header(struct sk_buff *skb) /* Open the low-level part of the AX25 channel. Easy! */ static int ax_open(struct net_device *dev) { - struct ax_disp *ax = netdev_priv(dev); + struct mkiss *ax = netdev_priv(dev); unsigned long len; if (ax->tty == NULL) @@ -518,7 +557,6 @@ static int ax_open(struct net_device *dev) spin_lock_init(&ax->buflock); - netif_start_queue(dev); return 0; noxbuff: @@ -532,68 +570,100 @@ norbuff: /* Close the low-level part of the AX25 channel. Easy! */ static int ax_close(struct net_device *dev) { - struct ax_disp *ax = netdev_priv(dev); + struct mkiss *ax = netdev_priv(dev); - if (ax->tty == NULL) - return -EBUSY; - - ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + if (ax->tty) + clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); netif_stop_queue(dev); return 0; } -static int ax25_receive_room(struct tty_struct *tty) +static struct net_device_stats *ax_get_stats(struct net_device *dev) { - return 65536; /* We can handle an infinite amount of data. :-) */ + struct mkiss *ax = netdev_priv(dev); + + return &ax->stats; +} + +static void ax_setup(struct net_device *dev) +{ + static char ax25_bcast[AX25_ADDR_LEN] = + {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; + static char ax25_test[AX25_ADDR_LEN] = + {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; + + /* Finish setting up the DEVICE info. */ + dev->mtu = AX_MTU; + dev->hard_start_xmit = ax_xmit; + dev->open = ax_open_dev; + dev->stop = ax_close; + dev->get_stats = ax_get_stats; + dev->set_mac_address = ax_set_mac_address; + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->type = ARPHRD_AX25; + dev->tx_queue_len = 10; + dev->hard_header = ax_header; + dev->rebuild_header = ax_rebuild_header; + + memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); + + dev->flags = IFF_BROADCAST | IFF_MULTICAST; } /* - * Handle the 'receiver data ready' interrupt. - * This function is called by the 'tty_io' module in the kernel when - * a block of data has been received, which can now be decapsulated - * and sent on to the AX.25 layer for further processing. + * We have a potential race on dereferencing tty->disc_data, because the tty + * layer provides no locking at all - thus one cpu could be running + * sixpack_receive_buf while another calls sixpack_close, which zeroes + * tty->disc_data and frees the memory that sixpack_receive_buf is using. The + * best way to fix this is to use a rwlock in the tty struct, but for now we + * use a single global rwlock for all ttys in ppp line discipline. */ -static void ax25_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; + +static struct mkiss *mkiss_get(struct tty_struct *tty) { - struct ax_disp *ax = (struct ax_disp *) tty->disc_data; + struct mkiss *ax; - if (ax == NULL || ax->magic != AX25_MAGIC || !netif_running(ax->dev)) - return; + read_lock(&disc_data_lock); + ax = tty->disc_data; + if (ax) + atomic_inc(&ax->refcnt); + read_unlock(&disc_data_lock); - /* - * Argh! mtu change time! - costs us the packet part received - * at the change - */ - if (ax->mtu != ax->dev->mtu + 73) - ax_changedmtu(ax); - - /* Read the characters out of the buffer */ - while (count--) { - if (fp != NULL && *fp++) { - if (!test_and_set_bit(AXF_ERROR, &ax->flags)) - ax->rx_errors++; - cp++; - continue; - } + return ax; +} - kiss_unesc(ax, *cp++); - } +static void mkiss_put(struct mkiss *ax) +{ + if (atomic_dec_and_test(&ax->refcnt)) + up(&ax->dead_sem); } -static int ax25_open(struct tty_struct *tty) +static int mkiss_open(struct tty_struct *tty) { - struct ax_disp *ax = (struct ax_disp *) tty->disc_data; + struct net_device *dev; + struct mkiss *ax; int err; - /* First make sure we're not already connected. */ - if (ax && ax->magic == AX25_MAGIC) - return -EEXIST; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; - /* OK. Find a free AX25 channel to use. */ - if ((ax = ax_alloc()) == NULL) - return -ENFILE; + dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup); + if (!dev) { + err = -ENOMEM; + goto out; + } + + ax = netdev_priv(dev); + ax->dev = dev; + + spin_lock_init(&ax->buflock); + atomic_set(&ax->refcnt, 1); + init_MUTEX_LOCKED(&ax->dead_sem); ax->tty = tty; tty->disc_data = ax; @@ -602,283 +672,212 @@ static int ax25_open(struct tty_struct *tty) tty->driver->flush_buffer(tty); /* Restore default settings */ - ax->dev->type = ARPHRD_AX25; + dev->type = ARPHRD_AX25; /* Perform the low-level AX25 initialization. */ - if ((err = ax_open(ax->dev))) - return err; + if ((err = ax_open(ax->dev))) { + goto out_free_netdev; + } - /* Done. We have linked the TTY line to a channel. */ - return ax->dev->base_addr; -} + if (register_netdev(dev)) + goto out_free_buffers; -static void ax25_close(struct tty_struct *tty) -{ - struct ax_disp *ax = (struct ax_disp *) tty->disc_data; + netif_start_queue(dev); - /* First make sure we're connected. */ - if (ax == NULL || ax->magic != AX25_MAGIC) - return; + /* Done. We have linked the TTY line to a channel. */ + return 0; - unregister_netdev(ax->dev); +out_free_buffers: + kfree(ax->rbuff); + kfree(ax->xbuff); - tty->disc_data = NULL; - ax->tty = NULL; +out_free_netdev: + free_netdev(dev); - ax_free(ax); +out: + return err; } - -static struct net_device_stats *ax_get_stats(struct net_device *dev) +static void mkiss_close(struct tty_struct *tty) { - static struct net_device_stats stats; - struct ax_disp *ax = netdev_priv(dev); - - memset(&stats, 0, sizeof(struct net_device_stats)); - - stats.rx_packets = ax->rx_packets; - stats.tx_packets = ax->tx_packets; - stats.rx_bytes = ax->rx_bytes; - stats.tx_bytes = ax->tx_bytes; - stats.rx_dropped = ax->rx_dropped; - stats.tx_dropped = ax->tx_dropped; - stats.tx_errors = ax->tx_errors; - stats.rx_errors = ax->rx_errors; - stats.rx_over_errors = ax->rx_over_errors; - - return &stats; -} + struct mkiss *ax; + write_lock(&disc_data_lock); + ax = tty->disc_data; + tty->disc_data = NULL; + write_unlock(&disc_data_lock); -/************************************************************************ - * STANDARD ENCAPSULATION * - ************************************************************************/ - -static int kiss_esc(unsigned char *s, unsigned char *d, int len) -{ - unsigned char *ptr = d; - unsigned char c; + if (ax == 0) + return; /* - * Send an initial END character to flush out any - * data that may have accumulated in the receiver - * due to line noise. + * We have now ensured that nobody can start using ap from now on, but + * we have to wait for all existing users to finish. */ + if (!atomic_dec_and_test(&ax->refcnt)) + down(&ax->dead_sem); - *ptr++ = END; - - while (len-- > 0) { - switch (c = *s++) { - case END: - *ptr++ = ESC; - *ptr++ = ESC_END; - break; - case ESC: - *ptr++ = ESC; - *ptr++ = ESC_ESC; - break; - default: - *ptr++ = c; - break; - } - } + unregister_netdev(ax->dev); - *ptr++ = END; + /* Free all AX25 frame buffers. */ + kfree(ax->rbuff); + kfree(ax->xbuff); - return ptr - d; + ax->tty = NULL; } -/* - * MW: - * OK its ugly, but tell me a better solution without copying the - * packet to a temporary buffer :-) - */ -static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, int len) +/* Perform I/O control on an active ax25 channel. */ +static int mkiss_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { - unsigned char *ptr = d; - unsigned char c=0; - - *ptr++ = END; - while (len > 0) { - if (len > 2) - c = *s++; - else if (len > 1) - c = crc >> 8; - else if (len > 0) - c = crc & 0xff; + struct mkiss *ax = mkiss_get(tty); + struct net_device *dev = ax->dev; + unsigned int tmp, err; - len--; + /* First make sure we're connected. */ + if (ax == NULL) + return -ENXIO; - switch (c) { - case END: - *ptr++ = ESC; - *ptr++ = ESC_END; - break; - case ESC: - *ptr++ = ESC; - *ptr++ = ESC_ESC; - break; - default: - *ptr++ = c; - break; + switch (cmd) { + case SIOCGIFNAME: + err = copy_to_user((void __user *) arg, ax->dev->name, + strlen(ax->dev->name) + 1) ? -EFAULT : 0; + break; + + case SIOCGIFENCAP: + err = put_user(4, (int __user *) arg); + break; + + case SIOCSIFENCAP: + if (get_user(tmp, (int __user *) arg)) { + err = -EFAULT; + break; } - } - *ptr++ = END; - return ptr - d; -} -static void kiss_unesc(struct ax_disp *ax, unsigned char s) -{ - switch (s) { - case END: - /* drop keeptest bit = VSV */ - if (test_bit(AXF_KEEPTEST, &ax->flags)) - clear_bit(AXF_KEEPTEST, &ax->flags); + ax->mode = tmp; + dev->addr_len = AX25_ADDR_LEN; + dev->hard_header_len = AX25_KISS_HEADER_LEN + + AX25_MAX_HEADER_LEN + 3; + dev->type = ARPHRD_AX25; - if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2)) - ax_bump(ax); + err = 0; + break; - clear_bit(AXF_ESCAPE, &ax->flags); - ax->rcount = 0; - return; + case SIOCSIFHWADDR: { + char addr[AX25_ADDR_LEN]; +printk(KERN_INFO "In SIOCSIFHWADDR"); - case ESC: - set_bit(AXF_ESCAPE, &ax->flags); - return; - case ESC_ESC: - if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) - s = ESC; + if (copy_from_user(&addr, + (void __user *) arg, AX25_ADDR_LEN)) { + err = -EFAULT; break; - case ESC_END: - if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) - s = END; - break; - } - - spin_lock_bh(&ax->buflock); - if (!test_bit(AXF_ERROR, &ax->flags)) { - if (ax->rcount < ax->buffsize) { - ax->rbuff[ax->rcount++] = s; - spin_unlock_bh(&ax->buflock); - return; } - ax->rx_over_errors++; - set_bit(AXF_ERROR, &ax->flags); + spin_lock_irq(&dev->xmit_lock); + memcpy(dev->dev_addr, addr, AX25_ADDR_LEN); + spin_unlock_irq(&dev->xmit_lock); + + err = 0; + break; + } + default: + err = -ENOIOCTLCMD; } - spin_unlock_bh(&ax->buflock); -} + mkiss_put(ax); -static int ax_set_mac_address(struct net_device *dev, void __user *addr) -{ - if (copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN)) - return -EFAULT; - return 0; + return err; } -static int ax_set_dev_mac_address(struct net_device *dev, void *addr) +/* + * Handle the 'receiver data ready' interrupt. + * This function is called by the 'tty_io' module in the kernel when + * a block of data has been received, which can now be decapsulated + * and sent on to the AX.25 layer for further processing. + */ +static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) { - struct sockaddr *sa = addr; - - memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN); + struct mkiss *ax = mkiss_get(tty); - return 0; -} - - -/* Perform I/O control on an active ax25 channel. */ -static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void __user *arg) -{ - struct ax_disp *ax = (struct ax_disp *) tty->disc_data; - unsigned int tmp; + if (!ax) + return; - /* First make sure we're connected. */ - if (ax == NULL || ax->magic != AX25_MAGIC) - return -EINVAL; + /* + * Argh! mtu change time! - costs us the packet part received + * at the change + */ + if (ax->mtu != ax->dev->mtu + 73) + ax_changedmtu(ax); - switch (cmd) { - case SIOCGIFNAME: - if (copy_to_user(arg, ax->dev->name, strlen(ax->dev->name) + 1)) - return -EFAULT; - return 0; - - case SIOCGIFENCAP: - return put_user(4, (int __user *)arg); - - case SIOCSIFENCAP: - if (get_user(tmp, (int __user *)arg)) - return -EFAULT; - ax->mode = tmp; - ax->dev->addr_len = AX25_ADDR_LEN; /* sizeof an AX.25 addr */ - ax->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3; - ax->dev->type = ARPHRD_AX25; - return 0; - - case SIOCSIFHWADDR: - return ax_set_mac_address(ax->dev, arg); + /* Read the characters out of the buffer */ + while (count--) { + if (fp != NULL && *fp++) { + if (!test_and_set_bit(AXF_ERROR, &ax->flags)) + ax->stats.rx_errors++; + cp++; + continue; + } - default: - return -ENOIOCTLCMD; + kiss_unesc(ax, *cp++); } + + mkiss_put(ax); + if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) + && tty->driver->unthrottle) + tty->driver->unthrottle(tty); } -static int ax_open_dev(struct net_device *dev) +static int mkiss_receive_room(struct tty_struct *tty) { - struct ax_disp *ax = netdev_priv(dev); - - if (ax->tty == NULL) - return -ENODEV; - - return 0; + return 65536; /* We can handle an infinite amount of data. :-) */ } - -/* Initialize the driver. Called by network startup. */ -static int ax25_init(struct net_device *dev) +/* + * Called by the driver when there's room for more data. If we have + * more packets to send, we send them here. + */ +static void mkiss_write_wakeup(struct tty_struct *tty) { - struct ax_disp *ax = netdev_priv(dev); - - static char ax25_bcast[AX25_ADDR_LEN] = - {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; - static char ax25_test[AX25_ADDR_LEN] = - {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; - - if (ax == NULL) /* Allocation failed ?? */ - return -ENODEV; + struct mkiss *ax = mkiss_get(tty); + int actual; - /* Set up the "AX25 Control Block". (And clear statistics) */ - memset(ax, 0, sizeof (struct ax_disp)); - ax->magic = AX25_MAGIC; - ax->dev = dev; + if (!ax) + return; - /* Finish setting up the DEVICE info. */ - dev->mtu = AX_MTU; - dev->hard_start_xmit = ax_xmit; - dev->open = ax_open_dev; - dev->stop = ax_close; - dev->get_stats = ax_get_stats; - dev->set_mac_address = ax_set_dev_mac_address; - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->type = ARPHRD_AX25; - dev->tx_queue_len = 10; - dev->hard_header = ax_header; - dev->rebuild_header = ax_rebuild_header; + if (ax->xleft <= 0) { + /* Now serial buffer is almost free & we can start + * transmission of another packet + */ + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); - memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); + netif_wake_queue(ax->dev); + goto out; + } - /* New-style flags. */ - dev->flags = IFF_BROADCAST | IFF_MULTICAST; + actual = tty->driver->write(tty, ax->xhead, ax->xleft); + ax->xleft -= actual; + ax->xhead += actual; - return 0; +out: + mkiss_put(ax); } +static struct tty_ldisc ax_ldisc = { + .magic = TTY_LDISC_MAGIC, + .name = "mkiss", + .open = mkiss_open, + .close = mkiss_close, + .ioctl = mkiss_ioctl, + .receive_buf = mkiss_receive_buf, + .receive_room = mkiss_receive_room, + .write_wakeup = mkiss_write_wakeup +}; -/* ******************************************************************** */ -/* * Init MKISS driver * */ -/* ******************************************************************** */ +static char banner[] __initdata = KERN_INFO \ + "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n"; +static char msg_regfail[] __initdata = KERN_ERR \ + "mkiss: can't register line discipline (err = %d)\n"; static int __init mkiss_init_driver(void) { @@ -886,64 +885,27 @@ static int __init mkiss_init_driver(void) printk(banner); - if (ax25_maxdev < 4) - ax25_maxdev = 4; /* Sanity */ + if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0) + printk(msg_regfail); - if ((ax25_ctrls = kmalloc(sizeof(void *) * ax25_maxdev, GFP_KERNEL)) == NULL) { - printk(KERN_ERR "mkiss: Can't allocate ax25_ctrls[] array!\n"); - return -ENOMEM; - } - - /* Clear the pointer array, we allocate devices when we need them */ - memset(ax25_ctrls, 0, sizeof(void*) * ax25_maxdev); /* Pointers */ - - /* Fill in our line protocol discipline, and register it */ - ax_ldisc.magic = TTY_LDISC_MAGIC; - ax_ldisc.name = "mkiss"; - ax_ldisc.open = ax25_open; - ax_ldisc.close = ax25_close; - ax_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, - unsigned int, unsigned long))ax25_disp_ioctl; - ax_ldisc.receive_buf = ax25_receive_buf; - ax_ldisc.receive_room = ax25_receive_room; - ax_ldisc.write_wakeup = ax25_write_wakeup; - - if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0) { - printk(KERN_ERR "mkiss: can't register line discipline (err = %d)\n", status); - kfree(ax25_ctrls); - } return status; } +static const char msg_unregfail[] __exitdata = KERN_ERR \ + "mkiss: can't unregister line discipline (err = %d)\n"; + static void __exit mkiss_exit_driver(void) { - int i; - - for (i = 0; i < ax25_maxdev; i++) { - if (ax25_ctrls[i]) { - /* - * VSV = if dev->start==0, then device - * unregistered while close proc. - */ - if (netif_running(&ax25_ctrls[i]->dev)) - unregister_netdev(&ax25_ctrls[i]->dev); - kfree(ax25_ctrls[i]); - } - } + int ret; - kfree(ax25_ctrls); - ax25_ctrls = NULL; - - if ((i = tty_unregister_ldisc(N_AX25))) - printk(KERN_ERR "mkiss: can't unregister line discipline (err = %d)\n", i); + if ((ret = tty_unregister_ldisc(N_AX25))) + printk(msg_unregfail, ret); } -MODULE_AUTHOR("Hans Albas PE1AYX <hans@esrac.ele.tue.nl>"); +MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>"); MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); -MODULE_PARM(ax25_maxdev, "i"); -MODULE_PARM_DESC(ax25_maxdev, "number of MKISS devices"); MODULE_LICENSE("GPL"); MODULE_ALIAS_LDISC(N_AX25); + module_init(mkiss_init_driver); module_exit(mkiss_exit_driver); - diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index 6482d994d48..0de3bb90617 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -1253,7 +1253,7 @@ static int emac_init_tah(struct ocp_enet_private *fep) TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP | TAH_MR_DIG); - iounmap(&tahp); + iounmap(tahp); return 0; } @@ -1712,11 +1712,10 @@ struct mal_commac_ops emac_commac_ops = { }; #ifdef CONFIG_NET_POLL_CONTROLLER -static int emac_netpoll(struct net_device *ndev) +static void emac_netpoll(struct net_device *ndev) { emac_rxeob_dev((void *)ndev, 0); emac_txeob_dev((void *)ndev, 0); - return 0; } #endif diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index d520b5920d6..49e5467bdd7 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -499,7 +499,7 @@ static int ioc3_mdio_read(struct net_device *dev, int phy, int reg) ioc3_w_micr((phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG); while (ioc3_r_micr() & MICR_BUSY); - return ioc3_r_micr() & MIDR_DATA_MASK; + return ioc3_r_midr_r() & MIDR_DATA_MASK; } static void ioc3_mdio_write(struct net_device *dev, int phy, int reg, int data) @@ -1291,7 +1291,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->features = NETIF_F_IP_CSUM; #endif - ioc3_setup_duplex(ip); sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1); sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2); @@ -1300,6 +1299,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_stop; mii_check_media(&ip->mii, 1, 1); + ioc3_setup_duplex(ip); vendor = (sw_physid1 << 12) | (sw_physid2 >> 4); model = (sw_physid2 >> 4) & 0x3f; @@ -1524,7 +1524,7 @@ static void ioc3_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) { struct ioc3_private *ip = netdev_priv(dev); - + strcpy (info->driver, IOC3_NAME); strcpy (info->version, IOC3_VERSION); strcpy (info->bus_info, pci_name(ip->pdev)); @@ -1550,7 +1550,7 @@ static int ioc3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) spin_lock_irq(&ip->ioc3_lock); rc = mii_ethtool_sset(&ip->mii, cmd); spin_unlock_irq(&ip->ioc3_lock); - + return rc; } diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index f8d3385c784..c83271b3862 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -119,7 +119,7 @@ struct ixgb_adapter; * so a DMA handle can be stored along with the buffer */ struct ixgb_buffer { struct sk_buff *skb; - uint64_t dma; + dma_addr_t dma; unsigned long time_stamp; uint16_t length; uint16_t next_to_watch; diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c index 3aae110c556..661a46b95a6 100644 --- a/drivers/net/ixgb/ixgb_ee.c +++ b/drivers/net/ixgb/ixgb_ee.c @@ -565,24 +565,6 @@ ixgb_get_ee_mac_addr(struct ixgb_hw *hw, } } -/****************************************************************************** - * return the compatibility flags from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * compatibility flags if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_compatibility(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->compatibility)); - - return(0); -} /****************************************************************************** * return the Printed Board Assembly number from EEPROM @@ -602,81 +584,6 @@ ixgb_get_ee_pba_number(struct ixgb_hw *hw) return(0); } -/****************************************************************************** - * return the Initialization Control Word 1 from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * Initialization Control Word 1 if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_init_ctrl_reg_1(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->init_ctrl_reg_1)); - - return(0); -} - -/****************************************************************************** - * return the Initialization Control Word 2 from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * Initialization Control Word 2 if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_init_ctrl_reg_2(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->init_ctrl_reg_2)); - - return(0); -} - -/****************************************************************************** - * return the Subsystem Id from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * Subsystem Id if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_subsystem_id(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->subsystem_id)); - - return(0); -} - -/****************************************************************************** - * return the Sub Vendor Id from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * Sub Vendor Id if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_subvendor_id(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->subvendor_id)); - - return(0); -} /****************************************************************************** * return the Device Id from EEPROM @@ -694,81 +601,6 @@ ixgb_get_ee_device_id(struct ixgb_hw *hw) if(ixgb_check_and_get_eeprom_data(hw) == TRUE) return (le16_to_cpu(ee_map->device_id)); - return(0); -} - -/****************************************************************************** - * return the Vendor Id from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * Device Id if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_vendor_id(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->vendor_id)); - - return(0); -} - -/****************************************************************************** - * return the Software Defined Pins Register from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * SDP Register if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_swdpins_reg(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->swdpins_reg)); - - return(0); + return (0); } -/****************************************************************************** - * return the D3 Power Management Bits from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * D3 Power Management Bits if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint8_t -ixgb_get_ee_d3_power(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->d3_power)); - - return(0); -} - -/****************************************************************************** - * return the D0 Power Management Bits from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * D0 Power Management Bits if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint8_t -ixgb_get_ee_d0_power(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->d0_power)); - - return(0); -} diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 3fa113854ee..9d026ed77dd 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -98,10 +98,10 @@ static struct ixgb_stats ixgb_gstrings_stats[] = { static int ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); - ecmd->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); + ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); ecmd->port = PORT_FIBRE; ecmd->transceiver = XCVR_EXTERNAL; @@ -120,7 +120,7 @@ ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) static int ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); if(ecmd->autoneg == AUTONEG_ENABLE || ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL) @@ -130,6 +130,12 @@ ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ixgb_down(adapter, TRUE); ixgb_reset(adapter); ixgb_up(adapter); + /* be optimistic about our link, since we were up before */ + adapter->link_speed = 10000; + adapter->link_duplex = FULL_DUPLEX; + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } else ixgb_reset(adapter); @@ -140,7 +146,7 @@ static void ixgb_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; pause->autoneg = AUTONEG_DISABLE; @@ -159,7 +165,7 @@ static int ixgb_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; if(pause->autoneg == AUTONEG_ENABLE) @@ -177,6 +183,11 @@ ixgb_set_pauseparam(struct net_device *netdev, if(netif_running(adapter->netdev)) { ixgb_down(adapter, TRUE); ixgb_up(adapter); + /* be optimistic about our link, since we were up before */ + adapter->link_speed = 10000; + adapter->link_duplex = FULL_DUPLEX; + netif_carrier_on(netdev); + netif_wake_queue(netdev); } else ixgb_reset(adapter); @@ -186,19 +197,26 @@ ixgb_set_pauseparam(struct net_device *netdev, static uint32_t ixgb_get_rx_csum(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); + return adapter->rx_csum; } static int ixgb_set_rx_csum(struct net_device *netdev, uint32_t data) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); + adapter->rx_csum = data; if(netif_running(netdev)) { ixgb_down(adapter,TRUE); ixgb_up(adapter); + /* be optimistic about our link, since we were up before */ + adapter->link_speed = 10000; + adapter->link_duplex = FULL_DUPLEX; + netif_carrier_on(netdev); + netif_wake_queue(netdev); } else ixgb_reset(adapter); return 0; @@ -246,14 +264,15 @@ static void ixgb_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; uint32_t *reg = p; uint32_t *reg_start = reg; uint8_t i; /* the 1 (one) below indicates an attempt at versioning, if the - * interface in ethtool or the driver this 1 should be incremented */ + * interface in ethtool or the driver changes, this 1 should be + * incremented */ regs->version = (1<<24) | hw->revision_id << 16 | hw->device_id; /* General Registers */ @@ -283,7 +302,8 @@ ixgb_get_regs(struct net_device *netdev, *reg++ = IXGB_READ_REG(hw, RAIDC); /* 19 */ *reg++ = IXGB_READ_REG(hw, RXCSUM); /* 20 */ - for (i = 0; i < IXGB_RAR_ENTRIES; i++) { + /* there are 16 RAR entries in hardware, we only use 3 */ + for(i = 0; i < 16; i++) { *reg++ = IXGB_READ_REG_ARRAY(hw, RAL, (i << 1)); /*21,...,51 */ *reg++ = IXGB_READ_REG_ARRAY(hw, RAH, (i << 1)); /*22,...,52 */ } @@ -391,7 +411,7 @@ static int ixgb_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, uint8_t *bytes) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; uint16_t *eeprom_buff; int i, max_len, first_word, last_word; @@ -439,7 +459,7 @@ static int ixgb_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, uint8_t *bytes) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; uint16_t *eeprom_buff; void *ptr; @@ -497,7 +517,7 @@ static void ixgb_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); strncpy(drvinfo->driver, ixgb_driver_name, 32); strncpy(drvinfo->version, ixgb_driver_version, 32); @@ -512,7 +532,7 @@ static void ixgb_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_desc_ring *txdr = &adapter->tx_ring; struct ixgb_desc_ring *rxdr = &adapter->rx_ring; @@ -530,7 +550,7 @@ static int ixgb_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_desc_ring *txdr = &adapter->tx_ring; struct ixgb_desc_ring *rxdr = &adapter->rx_ring; struct ixgb_desc_ring tx_old, tx_new, rx_old, rx_new; @@ -573,6 +593,11 @@ ixgb_set_ringparam(struct net_device *netdev, adapter->tx_ring = tx_new; if((err = ixgb_up(adapter))) return err; + /* be optimistic about our link, since we were up before */ + adapter->link_speed = 10000; + adapter->link_duplex = FULL_DUPLEX; + netif_carrier_on(netdev); + netif_wake_queue(netdev); } return 0; @@ -607,7 +632,7 @@ ixgb_led_blink_callback(unsigned long data) static int ixgb_phys_id(struct net_device *netdev, uint32_t data) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ)) data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ); @@ -643,7 +668,7 @@ static void ixgb_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); int i; ixgb_update_stats(adapter); diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h index 97898efe7cc..8bcf31ed10c 100644 --- a/drivers/net/ixgb/ixgb_hw.h +++ b/drivers/net/ixgb/ixgb_hw.h @@ -822,17 +822,8 @@ extern void ixgb_clear_vfta(struct ixgb_hw *hw); /* Access functions to eeprom data */ void ixgb_get_ee_mac_addr(struct ixgb_hw *hw, uint8_t *mac_addr); -uint16_t ixgb_get_ee_compatibility(struct ixgb_hw *hw); uint32_t ixgb_get_ee_pba_number(struct ixgb_hw *hw); -uint16_t ixgb_get_ee_init_ctrl_reg_1(struct ixgb_hw *hw); -uint16_t ixgb_get_ee_init_ctrl_reg_2(struct ixgb_hw *hw); -uint16_t ixgb_get_ee_subsystem_id(struct ixgb_hw *hw); -uint16_t ixgb_get_ee_subvendor_id(struct ixgb_hw *hw); uint16_t ixgb_get_ee_device_id(struct ixgb_hw *hw); -uint16_t ixgb_get_ee_vendor_id(struct ixgb_hw *hw); -uint16_t ixgb_get_ee_swdpins_reg(struct ixgb_hw *hw); -uint8_t ixgb_get_ee_d3_power(struct ixgb_hw *hw); -uint8_t ixgb_get_ee_d0_power(struct ixgb_hw *hw); boolean_t ixgb_get_eeprom_data(struct ixgb_hw *hw); uint16_t ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index); diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 097b90ccf57..5c555373adb 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -29,6 +29,11 @@ #include "ixgb.h" /* Change Log + * 1.0.96 04/19/05 + * - Make needlessly global code static -- bunk@stusta.de + * - ethtool cleanup -- shemminger@osdl.org + * - Support for MODULE_VERSION -- linville@tuxdriver.com + * - add skb_header_cloned check to the tso path -- herbert@apana.org.au * 1.0.88 01/05/05 * - include fix to the condition that determines when to quit NAPI - Robert Olsson * - use netif_poll_{disable/enable} to synchronize between NAPI and i/f up/down @@ -47,10 +52,9 @@ char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif - -#define DRV_VERSION "1.0.95-k2"DRIVERNAPI +#define DRV_VERSION "1.0.100-k2"DRIVERNAPI char ixgb_driver_version[] = DRV_VERSION; -char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation."; +static char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation."; /* ixgb_pci_tbl - PCI Device ID Table * @@ -145,10 +149,12 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); /* some defines for controlling descriptor fetches in h/w */ -#define RXDCTL_PTHRESH_DEFAULT 128 /* chip considers prefech below this */ -#define RXDCTL_HTHRESH_DEFAULT 16 /* chip will only prefetch if tail is - pushed this many descriptors from head */ #define RXDCTL_WTHRESH_DEFAULT 16 /* chip writes back at this many or RXT0 */ +#define RXDCTL_PTHRESH_DEFAULT 0 /* chip considers prefech below + * this */ +#define RXDCTL_HTHRESH_DEFAULT 0 /* chip will only prefetch if tail + * is pushed this many descriptors + * from head */ /** * ixgb_init_module - Driver Registration Routine @@ -376,7 +382,7 @@ ixgb_probe(struct pci_dev *pdev, SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); - adapter = netdev->priv; + adapter = netdev_priv(netdev); adapter->netdev = netdev; adapter->pdev = pdev; adapter->hw.back = adapter; @@ -512,7 +518,7 @@ static void __devexit ixgb_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); unregister_netdev(netdev); @@ -583,7 +589,7 @@ ixgb_sw_init(struct ixgb_adapter *adapter) static int ixgb_open(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); int err; /* allocate transmit descriptors */ @@ -626,7 +632,7 @@ err_setup_tx: static int ixgb_close(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); ixgb_down(adapter, TRUE); @@ -1017,7 +1023,7 @@ ixgb_clean_rx_ring(struct ixgb_adapter *adapter) static int ixgb_set_mac(struct net_device *netdev, void *p) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct sockaddr *addr = p; if(!is_valid_ether_addr(addr->sa_data)) @@ -1043,7 +1049,7 @@ ixgb_set_mac(struct net_device *netdev, void *p) static void ixgb_set_multi(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; struct dev_mc_list *mc_ptr; uint32_t rctl; @@ -1371,7 +1377,7 @@ ixgb_tx_queue(struct ixgb_adapter *adapter, int count, int vlan_id,int tx_flags) static int ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); unsigned int first; unsigned int tx_flags = 0; unsigned long flags; @@ -1425,7 +1431,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) static void ixgb_tx_timeout(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); /* Do the reset outside of interrupt context */ schedule_work(&adapter->tx_timeout_task); @@ -1434,7 +1440,7 @@ ixgb_tx_timeout(struct net_device *netdev) static void ixgb_tx_timeout_task(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); ixgb_down(adapter, TRUE); ixgb_up(adapter); @@ -1451,7 +1457,7 @@ ixgb_tx_timeout_task(struct net_device *netdev) static struct net_device_stats * ixgb_get_stats(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); return &adapter->net_stats; } @@ -1467,7 +1473,7 @@ ixgb_get_stats(struct net_device *netdev) static int ixgb_change_mtu(struct net_device *netdev, int new_mtu) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); int max_frame = new_mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH; int old_max_frame = netdev->mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH; @@ -1522,7 +1528,8 @@ ixgb_update_stats(struct ixgb_adapter *adapter) multi |= ((u64)IXGB_READ_REG(&adapter->hw, MPRCH) << 32); /* fix up multicast stats by removing broadcasts */ - multi -= bcast; + if(multi >= bcast) + multi -= bcast; adapter->stats.mprcl += (multi & 0xFFFFFFFF); adapter->stats.mprch += (multi >> 32); @@ -1641,7 +1648,7 @@ static irqreturn_t ixgb_intr(int irq, void *data, struct pt_regs *regs) { struct net_device *netdev = data; - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; uint32_t icr = IXGB_READ_REG(hw, ICR); #ifndef CONFIG_IXGB_NAPI @@ -1688,7 +1695,7 @@ ixgb_intr(int irq, void *data, struct pt_regs *regs) static int ixgb_clean(struct net_device *netdev, int *budget) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); int work_to_do = min(*budget, netdev->quota); int tx_cleaned; int work_done = 0; @@ -2017,7 +2024,7 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter) static void ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); uint32_t ctrl, rctl; ixgb_irq_disable(adapter); @@ -2055,7 +2062,7 @@ ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) static void ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); uint32_t vfta, index; /* add VID to filter table */ @@ -2069,7 +2076,7 @@ ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid) static void ixgb_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); uint32_t vfta, index; ixgb_irq_disable(adapter); diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 7fec613e167..8423cb6875f 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -1,5 +1,10 @@ /* - * sonic.c + * jazzsonic.c + * + * (C) 2005 Finn Thain + * + * Converted to DMA API, and (from the mac68k project) introduced + * dhd's support for 16-bit cards. * * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de) * @@ -28,8 +33,8 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include <linux/bitops.h> #include <linux/device.h> +#include <linux/dma-mapping.h> #include <asm/bootinfo.h> #include <asm/system.h> @@ -44,22 +49,20 @@ static struct platform_device *jazz_sonic_device; #define SONIC_MEM_SIZE 0x100 -#define SREGS_PAD(n) u16 n; - #include "sonic.h" /* * Macros to access SONIC registers */ -#define SONIC_READ(reg) (*((volatile unsigned int *)base_addr+reg)) +#define SONIC_READ(reg) (*((volatile unsigned int *)dev->base_addr+reg)) #define SONIC_WRITE(reg,val) \ do { \ - *((volatile unsigned int *)base_addr+(reg)) = (val); \ + *((volatile unsigned int *)dev->base_addr+(reg)) = (val); \ } while (0) -/* use 0 for production, 1 for verification, >2 for debug */ +/* use 0 for production, 1 for verification, >1 for debug */ #ifdef SONIC_DEBUG static unsigned int sonic_debug = SONIC_DEBUG; #else @@ -85,18 +88,18 @@ static unsigned short known_revisions[] = 0xffff /* end of list */ }; -static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr, - unsigned int irq) +static int __init sonic_probe1(struct net_device *dev) { static unsigned version_printed; unsigned int silicon_revision; unsigned int val; - struct sonic_local *lp; + struct sonic_local *lp = netdev_priv(dev); int err = -ENODEV; int i; - if (!request_mem_region(base_addr, SONIC_MEM_SIZE, jazz_sonic_string)) + if (!request_mem_region(dev->base_addr, SONIC_MEM_SIZE, jazz_sonic_string)) return -EBUSY; + /* * get the Silicon Revision ID. If this is one of the known * one assume that we found a SONIC ethernet controller at @@ -120,11 +123,7 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr, if (sonic_debug && version_printed++ == 0) printk(version); - printk("%s: Sonic ethernet found at 0x%08lx, ", dev->name, base_addr); - - /* Fill in the 'dev' fields. */ - dev->base_addr = base_addr; - dev->irq = irq; + printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ", lp->device->bus_id, dev->base_addr); /* * Put the sonic into software reset, then @@ -138,84 +137,44 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr, dev->dev_addr[i*2+1] = val >> 8; } - printk("HW Address "); - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i<5) - printk(":"); - } - - printk(" IRQ %d\n", irq); - err = -ENOMEM; /* Initialize the device structure. */ - if (dev->priv == NULL) { - /* - * the memory be located in the same 64kb segment - */ - lp = NULL; - i = 0; - do { - lp = kmalloc(sizeof(*lp), GFP_KERNEL); - if ((unsigned long) lp >> 16 - != ((unsigned long)lp + sizeof(*lp) ) >> 16) { - /* FIXME, free the memory later */ - kfree(lp); - lp = NULL; - } - } while (lp == NULL && i++ < 20); - - if (lp == NULL) { - printk("%s: couldn't allocate memory for descriptors\n", - dev->name); - goto out; - } - memset(lp, 0, sizeof(struct sonic_local)); - - /* get the virtual dma address */ - lp->cda_laddr = vdma_alloc(CPHYSADDR(lp),sizeof(*lp)); - if (lp->cda_laddr == ~0UL) { - printk("%s: couldn't get DMA page entry for " - "descriptors\n", dev->name); - goto out1; - } - - lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda); - lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda); - lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra); - - /* allocate receive buffer area */ - /* FIXME, maybe we should use skbs */ - lp->rba = kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL); - if (!lp->rba) { - printk("%s: couldn't allocate receive buffers\n", - dev->name); - goto out2; - } + lp->dma_bitmode = SONIC_BITMODE32; - /* get virtual dma address */ - lp->rba_laddr = vdma_alloc(CPHYSADDR(lp->rba), - SONIC_NUM_RRS * SONIC_RBSIZE); - if (lp->rba_laddr == ~0UL) { - printk("%s: couldn't get DMA page entry for receive " - "buffers\n",dev->name); - goto out3; - } - - /* now convert pointer to KSEG1 pointer */ - lp->rba = (char *)KSEG1ADDR(lp->rba); - flush_cache_all(); - dev->priv = (struct sonic_local *)KSEG1ADDR(lp); + /* Allocate the entire chunk of memory for the descriptors. + Note that this cannot cross a 64K boundary. */ + if ((lp->descriptors = dma_alloc_coherent(lp->device, + SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), + &lp->descriptors_laddr, GFP_KERNEL)) == NULL) { + printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id); + goto out; } - lp = (struct sonic_local *)dev->priv; + /* Now set up the pointers to point to the appropriate places */ + lp->cda = lp->descriptors; + lp->tda = lp->cda + (SIZEOF_SONIC_CDA + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + + lp->cda_laddr = lp->descriptors_laddr; + lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + dev->open = sonic_open; dev->stop = sonic_close; dev->hard_start_xmit = sonic_send_packet; - dev->get_stats = sonic_get_stats; + dev->get_stats = sonic_get_stats; dev->set_multicast_list = &sonic_multicast_list; + dev->tx_timeout = sonic_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; /* @@ -226,14 +185,8 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr, SONIC_WRITE(SONIC_MPT,0xffff); return 0; -out3: - kfree(lp->rba); -out2: - vdma_free(lp->cda_laddr); -out1: - kfree(lp); out: - release_region(base_addr, SONIC_MEM_SIZE); + release_region(dev->base_addr, SONIC_MEM_SIZE); return err; } @@ -245,7 +198,6 @@ static int __init jazz_sonic_probe(struct device *device) { struct net_device *dev; struct sonic_local *lp; - unsigned long base_addr; int err = 0; int i; @@ -255,21 +207,26 @@ static int __init jazz_sonic_probe(struct device *device) if (mips_machgroup != MACH_GROUP_JAZZ) return -ENODEV; - dev = alloc_etherdev(0); + dev = alloc_etherdev(sizeof(struct sonic_local)); if (!dev) return -ENOMEM; + lp = netdev_priv(dev); + lp->device = device; + SET_NETDEV_DEV(dev, device); + SET_MODULE_OWNER(dev); + netdev_boot_setup_check(dev); - base_addr = dev->base_addr; - if (base_addr >= KSEG0) { /* Check a single specified location. */ - err = sonic_probe1(dev, base_addr, dev->irq); - } else if (base_addr != 0) { /* Don't probe at all. */ + if (dev->base_addr >= KSEG0) { /* Check a single specified location. */ + err = sonic_probe1(dev); + } else if (dev->base_addr != 0) { /* Don't probe at all. */ err = -ENXIO; } else { for (i = 0; sonic_portlist[i].port; i++) { - int io = sonic_portlist[i].port; - if (sonic_probe1(dev, io, sonic_portlist[i].irq) == 0) + dev->base_addr = sonic_portlist[i].port; + dev->irq = sonic_portlist[i].irq; + if (sonic_probe1(dev) == 0) break; } if (!sonic_portlist[i].port) @@ -281,14 +238,17 @@ static int __init jazz_sonic_probe(struct device *device) if (err) goto out1; + printk("%s: MAC ", dev->name); + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } + printk(" IRQ %d\n", dev->irq); + return 0; out1: - lp = dev->priv; - vdma_free(lp->rba_laddr); - kfree(lp->rba); - vdma_free(lp->cda_laddr); - kfree(lp); release_region(dev->base_addr, SONIC_MEM_SIZE); out: free_netdev(dev); @@ -296,21 +256,22 @@ out: return err; } -/* - * SONIC uses a normal IRQ - */ -#define sonic_request_irq request_irq -#define sonic_free_irq free_irq +MODULE_DESCRIPTION("Jazz SONIC ethernet driver"); +module_param(sonic_debug, int, 0); +MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)"); -#define sonic_chiptomem(x) KSEG1ADDR(vdma_log2phys(x)) +#define SONIC_IRQ_FLAG SA_INTERRUPT #include "sonic.c" static int __devexit jazz_sonic_device_remove (struct device *device) { struct net_device *dev = device->driver_data; + struct sonic_local* lp = netdev_priv(dev); unregister_netdev (dev); + dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), + lp->descriptors, lp->descriptors_laddr); release_region (dev->base_addr, SONIC_MEM_SIZE); free_netdev (dev); @@ -323,7 +284,7 @@ static struct device_driver jazz_sonic_driver = { .probe = jazz_sonic_probe, .remove = __devexit_p(jazz_sonic_device_remove), }; - + static void jazz_sonic_platform_release (struct device *device) { struct platform_device *pldev; @@ -336,10 +297,11 @@ static void jazz_sonic_platform_release (struct device *device) static int __init jazz_sonic_init_module(void) { struct platform_device *pldev; + int err; - if (driver_register(&jazz_sonic_driver)) { + if ((err = driver_register(&jazz_sonic_driver))) { printk(KERN_ERR "Driver registration failed\n"); - return -ENOMEM; + return err; } jazz_sonic_device = NULL; diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index b33111e2131..690a1aae0b3 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -68,6 +68,7 @@ static DEFINE_PER_CPU(struct net_device_stats, loopback_stats); * of largesending device modulo TCP checksum, which is ignored for loopback. */ +#ifdef LOOPBACK_TSO static void emulate_large_send_offload(struct sk_buff *skb) { struct iphdr *iph = skb->nh.iph; @@ -119,6 +120,7 @@ static void emulate_large_send_offload(struct sk_buff *skb) dev_kfree_skb(skb); } +#endif /* LOOPBACK_TSO */ /* * The higher levels take care of making this non-reentrant (it's @@ -130,12 +132,13 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) skb_orphan(skb); - skb->protocol=eth_type_trans(skb,dev); - skb->dev=dev; + skb->protocol = eth_type_trans(skb,dev); + skb->dev = dev; #ifndef LOOPBACK_MUST_CHECKSUM skb->ip_summed = CHECKSUM_UNNECESSARY; #endif +#ifdef LOOPBACK_TSO if (skb_shinfo(skb)->tso_size) { BUG_ON(skb->protocol != htons(ETH_P_IP)); BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP); @@ -143,14 +146,14 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) emulate_large_send_offload(skb); return 0; } - +#endif dev->last_rx = jiffies; lb_stats = &per_cpu(loopback_stats, get_cpu()); lb_stats->rx_bytes += skb->len; - lb_stats->tx_bytes += skb->len; + lb_stats->tx_bytes = lb_stats->rx_bytes; lb_stats->rx_packets++; - lb_stats->tx_packets++; + lb_stats->tx_packets = lb_stats->rx_packets; put_cpu(); netif_rx(skb); @@ -208,13 +211,16 @@ struct net_device loopback_dev = { .type = ARPHRD_LOOPBACK, /* 0x0001*/ .rebuild_header = eth_rebuild_header, .flags = IFF_LOOPBACK, - .features = NETIF_F_SG|NETIF_F_FRAGLIST - |NETIF_F_NO_CSUM|NETIF_F_HIGHDMA - |NETIF_F_LLTX, + .features = NETIF_F_SG | NETIF_F_FRAGLIST +#ifdef LOOPBACK_TSO + | NETIF_F_TSO +#endif + | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA + | NETIF_F_LLTX, .ethtool_ops = &loopback_ethtool_ops, }; -/* Setup and register the of the LOOPBACK device. */ +/* Setup and register the loopback device. */ int __init loopback_init(void) { struct net_device_stats *stats; diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index be28c65de72..405e18365ed 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -1,6 +1,12 @@ /* * macsonic.c * + * (C) 2005 Finn Thain + * + * Converted to DMA API, converted to unified driver model, made it work as + * a module again, and from the mac68k project, introduced more 32-bit cards + * and dhd's support for 16-bit cards. + * * (C) 1998 Alan Cox * * Debugging Andreas Ehliar, Michael Schmitz @@ -26,8 +32,8 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/types.h> -#include <linux/ctype.h> #include <linux/fcntl.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -41,8 +47,8 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include <linux/module.h> -#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> #include <asm/bootinfo.h> #include <asm/system.h> @@ -54,25 +60,28 @@ #include <asm/macints.h> #include <asm/mac_via.h> -#define SREGS_PAD(n) u16 n; +static char mac_sonic_string[] = "macsonic"; +static struct platform_device *mac_sonic_device; #include "sonic.h" -#define SONIC_READ(reg) \ - nubus_readl(base_addr+(reg)) -#define SONIC_WRITE(reg,val) \ - nubus_writel((val), base_addr+(reg)) -#define sonic_read(dev, reg) \ - nubus_readl((dev)->base_addr+(reg)) -#define sonic_write(dev, reg, val) \ - nubus_writel((val), (dev)->base_addr+(reg)) - +/* These should basically be bus-size and endian independent (since + the SONIC is at least smart enough that it uses the same endianness + as the host, unlike certain less enlightened Macintosh NICs) */ +#define SONIC_READ(reg) (nubus_readw(dev->base_addr + (reg * 4) \ + + lp->reg_offset)) +#define SONIC_WRITE(reg,val) (nubus_writew(val, dev->base_addr + (reg * 4) \ + + lp->reg_offset)) + +/* use 0 for production, 1 for verification, >1 for debug */ +#ifdef SONIC_DEBUG +static unsigned int sonic_debug = SONIC_DEBUG; +#else +static unsigned int sonic_debug = 1; +#endif -static int sonic_debug; static int sonic_version_printed; -static int reg_offset; - extern int mac_onboard_sonic_probe(struct net_device* dev); extern int mac_nubus_sonic_probe(struct net_device* dev); @@ -108,40 +117,6 @@ enum macsonic_type { #define SONIC_READ_PROM(addr) nubus_readb(prom_addr+addr) -struct net_device * __init macsonic_probe(int unit) -{ - struct net_device *dev = alloc_etherdev(0); - int err; - - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) - sprintf(dev->name, "eth%d", unit); - - SET_MODULE_OWNER(dev); - - /* This will catch fatal stuff like -ENOMEM as well as success */ - err = mac_onboard_sonic_probe(dev); - if (err == 0) - goto found; - if (err != -ENODEV) - goto out; - err = mac_nubus_sonic_probe(dev); - if (err) - goto out; -found: - err = register_netdev(dev); - if (err) - goto out1; - return dev; -out1: - kfree(dev->priv); -out: - free_netdev(dev); - return ERR_PTR(err); -} - /* * For reversing the PROM address */ @@ -160,103 +135,55 @@ static inline void bit_reverse_addr(unsigned char addr[6]) int __init macsonic_init(struct net_device* dev) { - struct sonic_local* lp = NULL; - int i; + struct sonic_local* lp = netdev_priv(dev); /* Allocate the entire chunk of memory for the descriptors. Note that this cannot cross a 64K boundary. */ - for (i = 0; i < 20; i++) { - unsigned long desc_base, desc_top; - if((lp = kmalloc(sizeof(struct sonic_local), GFP_KERNEL | GFP_DMA)) == NULL) { - printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name); - return -ENOMEM; - } - - desc_base = (unsigned long) lp; - desc_top = desc_base + sizeof(struct sonic_local); - if ((desc_top & 0xffff) >= (desc_base & 0xffff)) - break; - /* Hmm. try again (FIXME: does this actually work?) */ - kfree(lp); - printk(KERN_DEBUG - "%s: didn't get continguous chunk [%08lx - %08lx], trying again\n", - dev->name, desc_base, desc_top); - } - - if (lp == NULL) { - printk(KERN_ERR "%s: tried 20 times to allocate descriptor buffers, giving up.\n", - dev->name); + if ((lp->descriptors = dma_alloc_coherent(lp->device, + SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), + &lp->descriptors_laddr, GFP_KERNEL)) == NULL) { + printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id); return -ENOMEM; - } - - dev->priv = lp; - -#if 0 - /* this code is only here as a curiousity... mainly, where the - fuck did SONIC_BUS_SCALE come from, and what was it supposed - to do? the normal allocation works great for 32 bit stuffs.. */ + } /* Now set up the pointers to point to the appropriate places */ - lp->cda = lp->sonic_desc; - lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->cda = lp->descriptors; + lp->tda = lp->cda + (SIZEOF_SONIC_CDA + * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); + * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); + * SONIC_BUS_SCALE(lp->dma_bitmode)); -#endif - - memset(lp, 0, sizeof(struct sonic_local)); - - lp->cda_laddr = (unsigned int)&(lp->cda); - lp->tda_laddr = (unsigned int)lp->tda; - lp->rra_laddr = (unsigned int)lp->rra; - lp->rda_laddr = (unsigned int)lp->rda; - - /* FIXME, maybe we should use skbs */ - if ((lp->rba = (char *) - kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) { - printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name); - dev->priv = NULL; - kfree(lp); - return -ENOMEM; - } - - lp->rba_laddr = (unsigned int)lp->rba; - - { - int rs, ds; - - /* almost always 12*4096, but let's not take chances */ - rs = ((SONIC_NUM_RRS * SONIC_RBSIZE + 4095) / 4096) * 4096; - /* almost always under a page, but let's not take chances */ - ds = ((sizeof(struct sonic_local) + 4095) / 4096) * 4096; - kernel_set_cachemode(lp->rba, rs, IOMAP_NOCACHE_SER); - kernel_set_cachemode(lp, ds, IOMAP_NOCACHE_SER); - } - -#if 0 - flush_cache_all(); -#endif + lp->cda_laddr = lp->descriptors_laddr; + lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); dev->open = sonic_open; dev->stop = sonic_close; dev->hard_start_xmit = sonic_send_packet; dev->get_stats = sonic_get_stats; dev->set_multicast_list = &sonic_multicast_list; + dev->tx_timeout = sonic_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; /* * clear tally counter */ - sonic_write(dev, SONIC_CRCT, 0xffff); - sonic_write(dev, SONIC_FAET, 0xffff); - sonic_write(dev, SONIC_MPT, 0xffff); + SONIC_WRITE(SONIC_CRCT, 0xffff); + SONIC_WRITE(SONIC_FAET, 0xffff); + SONIC_WRITE(SONIC_MPT, 0xffff); return 0; } int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) { + struct sonic_local *lp = netdev_priv(dev); const int prom_addr = ONBOARD_SONIC_PROM_BASE; int i; @@ -270,6 +197,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) why this is so. */ if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x80\x19", 3) && memcmp(dev->dev_addr, "\x00\x05\x02", 3)) bit_reverse_addr(dev->dev_addr); else @@ -281,22 +209,23 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) the card... */ if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x80\x19", 3) && memcmp(dev->dev_addr, "\x00\x05\x02", 3)) { unsigned short val; printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n"); - sonic_write(dev, SONIC_CMD, SONIC_CR_RST); - sonic_write(dev, SONIC_CEP, 15); + SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); + SONIC_WRITE(SONIC_CEP, 15); - val = sonic_read(dev, SONIC_CAP2); + val = SONIC_READ(SONIC_CAP2); dev->dev_addr[5] = val >> 8; dev->dev_addr[4] = val & 0xff; - val = sonic_read(dev, SONIC_CAP1); + val = SONIC_READ(SONIC_CAP1); dev->dev_addr[3] = val >> 8; dev->dev_addr[2] = val & 0xff; - val = sonic_read(dev, SONIC_CAP0); + val = SONIC_READ(SONIC_CAP0); dev->dev_addr[1] = val >> 8; dev->dev_addr[0] = val & 0xff; @@ -311,6 +240,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x80\x19", 3) && memcmp(dev->dev_addr, "\x00\x05\x02", 3)) { /* @@ -325,8 +255,9 @@ int __init mac_onboard_sonic_probe(struct net_device* dev) { /* Bwahahaha */ static int once_is_more_than_enough; - int i; - int dma_bitmode; + struct sonic_local* lp = netdev_priv(dev); + int sr; + int commslot = 0; if (once_is_more_than_enough) return -ENODEV; @@ -335,20 +266,18 @@ int __init mac_onboard_sonic_probe(struct net_device* dev) if (!MACH_IS_MAC) return -ENODEV; - printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. "); - if (macintosh_config->ether_type != MAC_ETHER_SONIC) - { - printk("none.\n"); return -ENODEV; - } - + + printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. "); + /* Bogus probing, on the models which may or may not have Ethernet (BTW, the Ethernet *is* always at the same address, and nothing else lives there, at least if Apple's documentation is to be believed) */ if (macintosh_config->ident == MAC_MODEL_Q630 || macintosh_config->ident == MAC_MODEL_P588 || + macintosh_config->ident == MAC_MODEL_P575 || macintosh_config->ident == MAC_MODEL_C610) { unsigned long flags; int card_present; @@ -361,13 +290,13 @@ int __init mac_onboard_sonic_probe(struct net_device* dev) printk("none.\n"); return -ENODEV; } + commslot = 1; } printk("yes\n"); - /* Danger! My arms are flailing wildly! You *must* set this - before using sonic_read() */ - + /* Danger! My arms are flailing wildly! You *must* set lp->reg_offset + * and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */ dev->base_addr = ONBOARD_SONIC_REGISTERS; if (via_alt_mapping) dev->irq = IRQ_AUTO_3; @@ -379,84 +308,66 @@ int __init mac_onboard_sonic_probe(struct net_device* dev) sonic_version_printed = 1; } printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n", - dev->name, dev->base_addr); - - /* Now do a song and dance routine in an attempt to determine - the bus width */ + lp->device->bus_id, dev->base_addr); /* The PowerBook's SONIC is 16 bit always. */ if (macintosh_config->ident == MAC_MODEL_PB520) { - reg_offset = 0; - dma_bitmode = 0; - } else if (macintosh_config->ident == MAC_MODEL_C610) { - reg_offset = 0; - dma_bitmode = 1; - } else { + lp->reg_offset = 0; + lp->dma_bitmode = SONIC_BITMODE16; + sr = SONIC_READ(SONIC_SR); + } else if (commslot) { /* Some of the comm-slot cards are 16 bit. But some - of them are not. The 32-bit cards use offset 2 and - pad with zeroes or sometimes ones (I think...) - Therefore, if we try offset 0 and get a silicon - revision of 0, we assume 16 bit. */ - int sr; - - /* Technically this is not necessary since we zeroed - it above */ - reg_offset = 0; - dma_bitmode = 0; - sr = sonic_read(dev, SONIC_SR); - if (sr == 0 || sr == 0xffff) { - reg_offset = 2; - /* 83932 is 0x0004, 83934 is 0x0100 or 0x0101 */ - sr = sonic_read(dev, SONIC_SR); - dma_bitmode = 1; - + of them are not. The 32-bit cards use offset 2 and + have known revisions, we try reading the revision + register at offset 2, if we don't get a known revision + we assume 16 bit at offset 0. */ + lp->reg_offset = 2; + lp->dma_bitmode = SONIC_BITMODE16; + + sr = SONIC_READ(SONIC_SR); + if (sr == 0x0004 || sr == 0x0006 || sr == 0x0100 || sr == 0x0101) + /* 83932 is 0x0004 or 0x0006, 83934 is 0x0100 or 0x0101 */ + lp->dma_bitmode = SONIC_BITMODE32; + else { + lp->dma_bitmode = SONIC_BITMODE16; + lp->reg_offset = 0; + sr = SONIC_READ(SONIC_SR); } - printk(KERN_INFO - "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", - dev->name, sr, dma_bitmode?32:16, reg_offset); + } else { + /* All onboard cards are at offset 2 with 32 bit DMA. */ + lp->reg_offset = 2; + lp->dma_bitmode = SONIC_BITMODE32; + sr = SONIC_READ(SONIC_SR); } - + printk(KERN_INFO + "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", + lp->device->bus_id, sr, lp->dma_bitmode?32:16, lp->reg_offset); - /* this carries my sincere apologies -- by the time I got to updating - the driver, support for "reg_offsets" appeares nowhere in the sonic - code, going back for over a year. Fortunately, my Mac does't seem - to use whatever this was. +#if 0 /* This is sometimes useful to find out how MacOS configured the card. */ + printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", lp->device->bus_id, + SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff); +#endif - If you know how this is supposed to be implemented, either fix it, - or contact me (sammy@oh.verio.com) to explain what it is. --Sam */ - - if(reg_offset) { - printk("%s: register offset unsupported. please fix this if you know what it is.\n", dev->name); - return -ENODEV; - } - /* Software reset, then initialize control registers. */ - sonic_write(dev, SONIC_CMD, SONIC_CR_RST); - sonic_write(dev, SONIC_DCR, SONIC_DCR_BMS | - SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | - (dma_bitmode ? SONIC_DCR_DW : 0)); + SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); + + SONIC_WRITE(SONIC_DCR, SONIC_DCR_EXBUS | SONIC_DCR_BMS | + SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | + (lp->dma_bitmode ? SONIC_DCR_DW : 0)); /* This *must* be written back to in order to restore the - extended programmable output bits */ - sonic_write(dev, SONIC_DCR2, 0); + * extended programmable output bits, as it may not have been + * initialised since the hardware reset. */ + SONIC_WRITE(SONIC_DCR2, 0); /* Clear *and* disable interrupts to be on the safe side */ - sonic_write(dev, SONIC_ISR,0x7fff); - sonic_write(dev, SONIC_IMR,0); + SONIC_WRITE(SONIC_IMR, 0); + SONIC_WRITE(SONIC_ISR, 0x7fff); /* Now look for the MAC address. */ if (mac_onboard_sonic_ethernet_addr(dev) != 0) return -ENODEV; - printk(KERN_INFO "MAC "); - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - - printk(" IRQ %d\n", dev->irq); - /* Shared init code */ return macsonic_init(dev); } @@ -468,8 +379,10 @@ int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev, int i; for(i = 0; i < 6; i++) dev->dev_addr[i] = SONIC_READ_PROM(i); - /* For now we are going to assume that they're all bit-reversed */ - bit_reverse_addr(dev->dev_addr); + + /* Some of the addresses are bit-reversed */ + if (id != MACSONIC_DAYNA) + bit_reverse_addr(dev->dev_addr); return 0; } @@ -487,6 +400,15 @@ int __init macsonic_ident(struct nubus_dev* ndev) else return MACSONIC_APPLE; } + + if (ndev->dr_hw == NUBUS_DRHW_SMC9194 && + ndev->dr_sw == NUBUS_DRSW_DAYNA) + return MACSONIC_DAYNA; + + if (ndev->dr_hw == NUBUS_DRHW_SONIC_LC && + ndev->dr_sw == 0) { /* huh? */ + return MACSONIC_APPLE16; + } return -1; } @@ -494,12 +416,12 @@ int __init mac_nubus_sonic_probe(struct net_device* dev) { static int slots; struct nubus_dev* ndev = NULL; + struct sonic_local* lp = netdev_priv(dev); unsigned long base_addr, prom_addr; u16 sonic_dcr; - int id; - int i; - int dma_bitmode; - + int id = -1; + int reg_offset, dma_bitmode; + /* Find the first SONIC that hasn't been initialized already */ while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev)) != NULL) @@ -521,51 +443,52 @@ int __init mac_nubus_sonic_probe(struct net_device* dev) case MACSONIC_DUODOCK: base_addr = ndev->board->slot_addr + DUODOCK_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + DUODOCK_SONIC_PROM_BASE; - sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 - | SONIC_DCR_TFT0; + sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 | + SONIC_DCR_TFT0; reg_offset = 2; - dma_bitmode = 1; + dma_bitmode = SONIC_BITMODE32; break; case MACSONIC_APPLE: base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0; reg_offset = 0; - dma_bitmode = 1; + dma_bitmode = SONIC_BITMODE32; break; case MACSONIC_APPLE16: base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; - sonic_dcr = SONIC_DCR_EXBUS - | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 - | SONIC_DCR_PO1 | SONIC_DCR_BMS; + sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | + SONIC_DCR_PO1 | SONIC_DCR_BMS; reg_offset = 0; - dma_bitmode = 0; + dma_bitmode = SONIC_BITMODE16; break; case MACSONIC_DAYNALINK: base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE; - sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 - | SONIC_DCR_PO1 | SONIC_DCR_BMS; + sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | + SONIC_DCR_PO1 | SONIC_DCR_BMS; reg_offset = 0; - dma_bitmode = 0; + dma_bitmode = SONIC_BITMODE16; break; case MACSONIC_DAYNA: base_addr = ndev->board->slot_addr + DAYNA_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + DAYNA_SONIC_MAC_ADDR; - sonic_dcr = SONIC_DCR_BMS - | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1; + sonic_dcr = SONIC_DCR_BMS | + SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1; reg_offset = 0; - dma_bitmode = 0; + dma_bitmode = SONIC_BITMODE16; break; default: printk(KERN_ERR "macsonic: WTF, id is %d\n", id); return -ENODEV; } - /* Danger! My arms are flailing wildly! You *must* set this - before using sonic_read() */ + /* Danger! My arms are flailing wildly! You *must* set lp->reg_offset + * and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */ dev->base_addr = base_addr; + lp->reg_offset = reg_offset; + lp->dma_bitmode = dma_bitmode; dev->irq = SLOT2IRQ(ndev->board->slot); if (!sonic_version_printed) { @@ -573,29 +496,66 @@ int __init mac_nubus_sonic_probe(struct net_device* dev) sonic_version_printed = 1; } printk(KERN_INFO "%s: %s in slot %X\n", - dev->name, ndev->board->name, ndev->board->slot); + lp->device->bus_id, ndev->board->name, ndev->board->slot); printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", - dev->name, sonic_read(dev, SONIC_SR), dma_bitmode?32:16, reg_offset); + lp->device->bus_id, SONIC_READ(SONIC_SR), dma_bitmode?32:16, reg_offset); - if(reg_offset) { - printk("%s: register offset unsupported. please fix this if you know what it is.\n", dev->name); - return -ENODEV; - } +#if 0 /* This is sometimes useful to find out how MacOS configured the card. */ + printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", lp->device->bus_id, + SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff); +#endif /* Software reset, then initialize control registers. */ - sonic_write(dev, SONIC_CMD, SONIC_CR_RST); - sonic_write(dev, SONIC_DCR, sonic_dcr - | (dma_bitmode ? SONIC_DCR_DW : 0)); + SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); + SONIC_WRITE(SONIC_DCR, sonic_dcr | (dma_bitmode ? SONIC_DCR_DW : 0)); + /* This *must* be written back to in order to restore the + * extended programmable output bits, since it may not have been + * initialised since the hardware reset. */ + SONIC_WRITE(SONIC_DCR2, 0); /* Clear *and* disable interrupts to be on the safe side */ - sonic_write(dev, SONIC_ISR,0x7fff); - sonic_write(dev, SONIC_IMR,0); + SONIC_WRITE(SONIC_IMR, 0); + SONIC_WRITE(SONIC_ISR, 0x7fff); /* Now look for the MAC address. */ if (mac_nubus_sonic_ethernet_addr(dev, prom_addr, id) != 0) return -ENODEV; - printk(KERN_INFO "MAC "); + /* Shared init code */ + return macsonic_init(dev); +} + +static int __init mac_sonic_probe(struct device *device) +{ + struct net_device *dev; + struct sonic_local *lp; + int err; + int i; + + dev = alloc_etherdev(sizeof(struct sonic_local)); + if (!dev) + return -ENOMEM; + + lp = netdev_priv(dev); + lp->device = device; + SET_NETDEV_DEV(dev, device); + SET_MODULE_OWNER(dev); + + /* This will catch fatal stuff like -ENOMEM as well as success */ + err = mac_onboard_sonic_probe(dev); + if (err == 0) + goto found; + if (err != -ENODEV) + goto out; + err = mac_nubus_sonic_probe(dev); + if (err) + goto out; +found: + err = register_netdev(dev); + if (err) + goto out; + + printk("%s: MAC ", dev->name); for (i = 0; i < 6; i++) { printk("%2.2x", dev->dev_addr[i]); if (i < 5) @@ -603,55 +563,95 @@ int __init mac_nubus_sonic_probe(struct net_device* dev) } printk(" IRQ %d\n", dev->irq); - /* Shared init code */ - return macsonic_init(dev); -} + return 0; -#ifdef MODULE -static struct net_device *dev_macsonic; +out: + free_netdev(dev); -MODULE_PARM(sonic_debug, "i"); + return err; +} + +MODULE_DESCRIPTION("Macintosh SONIC ethernet driver"); +module_param(sonic_debug, int, 0); MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)"); -int -init_module(void) +#define SONIC_IRQ_FLAG IRQ_FLG_FAST + +#include "sonic.c" + +static int __devexit mac_sonic_device_remove (struct device *device) { - dev_macsonic = macsonic_probe(-1); - if (IS_ERR(dev_macsonic)) { - printk(KERN_WARNING "macsonic.c: No card found\n"); - return PTR_ERR(dev_macsonic); - } + struct net_device *dev = device->driver_data; + struct sonic_local* lp = netdev_priv(dev); + + unregister_netdev (dev); + dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), + lp->descriptors, lp->descriptors_laddr); + free_netdev (dev); + return 0; } -void -cleanup_module(void) +static struct device_driver mac_sonic_driver = { + .name = mac_sonic_string, + .bus = &platform_bus_type, + .probe = mac_sonic_probe, + .remove = __devexit_p(mac_sonic_device_remove), +}; + +static void mac_sonic_platform_release(struct device *device) { - unregister_netdev(dev_macsonic); - kfree(dev_macsonic->priv); - free_netdev(dev_macsonic); + struct platform_device *pldev; + + /* free device */ + pldev = to_platform_device (device); + kfree (pldev); } -#endif /* MODULE */ +static int __init mac_sonic_init_module(void) +{ + struct platform_device *pldev; + int err; -#define vdma_alloc(foo, bar) ((u32)foo) -#define vdma_free(baz) -#define sonic_chiptomem(bat) (bat) -#define PHYSADDR(quux) (quux) -#define CPHYSADDR(quux) (quux) + if ((err = driver_register(&mac_sonic_driver))) { + printk(KERN_ERR "Driver registration failed\n"); + return err; + } -#define sonic_request_irq request_irq -#define sonic_free_irq free_irq + mac_sonic_device = NULL; -#include "sonic.c" + if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) { + goto out_unregister; + } -/* - * Local variables: - * compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o macsonic.o macsonic.c" - * version-control: t - * kept-new-versions: 5 - * c-indent-level: 8 - * tab-width: 8 - * End: - * - */ + memset(pldev, 0, sizeof (*pldev)); + pldev->name = mac_sonic_string; + pldev->id = 0; + pldev->dev.release = mac_sonic_platform_release; + mac_sonic_device = pldev; + + if (platform_device_register (pldev)) { + kfree(pldev); + mac_sonic_device = NULL; + } + + return 0; + +out_unregister: + platform_device_unregister(pldev); + + return -ENOMEM; +} + +static void __exit mac_sonic_cleanup_module(void) +{ + driver_unregister(&mac_sonic_driver); + + if (mac_sonic_device) { + platform_device_unregister(mac_sonic_device); + mac_sonic_device = NULL; + } +} + +module_init(mac_sonic_init_module); +module_exit(mac_sonic_cleanup_module); diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 0405e1f0d3d..fb6b232069d 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1157,16 +1157,20 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!skb_shinfo(skb)->nr_frags) { linear: if (skb->ip_summed != CHECKSUM_HW) { + /* Errata BTS #50, IHL must be 5 if no HW checksum */ pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | - ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC; + ETH_TX_FIRST_DESC | + ETH_TX_LAST_DESC | + 5 << ETH_TX_IHL_SHIFT; pkt_info.l4i_chk = 0; } else { - u32 ipheader = skb->nh.iph->ihl << 11; pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | - ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC | - ETH_GEN_TCP_UDP_CHECKSUM | - ETH_GEN_IP_V_4_CHECKSUM | ipheader; + ETH_TX_FIRST_DESC | + ETH_TX_LAST_DESC | + ETH_GEN_TCP_UDP_CHECKSUM | + ETH_GEN_IP_V_4_CHECKSUM | + skb->nh.iph->ihl << ETH_TX_IHL_SHIFT; /* CPU already calculated pseudo header checksum. */ if (skb->nh.iph->protocol == IPPROTO_UDP) { pkt_info.cmd_sts |= ETH_UDP_FRAME; @@ -1193,7 +1197,6 @@ linear: stats->tx_bytes += pkt_info.byte_cnt; } else { unsigned int frag; - u32 ipheader; /* Since hardware can't handle unaligned fragments smaller * than 9 bytes, if we find any, we linearize the skb @@ -1222,12 +1225,16 @@ linear: DMA_TO_DEVICE); pkt_info.l4i_chk = 0; pkt_info.return_info = 0; - pkt_info.cmd_sts = ETH_TX_FIRST_DESC; - if (skb->ip_summed == CHECKSUM_HW) { - ipheader = skb->nh.iph->ihl << 11; - pkt_info.cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM | - ETH_GEN_IP_V_4_CHECKSUM | ipheader; + if (skb->ip_summed != CHECKSUM_HW) + /* Errata BTS #50, IHL must be 5 if no HW checksum */ + pkt_info.cmd_sts = ETH_TX_FIRST_DESC | + 5 << ETH_TX_IHL_SHIFT; + else { + pkt_info.cmd_sts = ETH_TX_FIRST_DESC | + ETH_GEN_TCP_UDP_CHECKSUM | + ETH_GEN_IP_V_4_CHECKSUM | + skb->nh.iph->ihl << ETH_TX_IHL_SHIFT; /* CPU already calculated pseudo header checksum. */ if (skb->nh.iph->protocol == IPPROTO_UDP) { pkt_info.cmd_sts |= ETH_UDP_FRAME; diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index 57c4f8fbfdb..7678b59c295 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -49,7 +49,7 @@ /* Checksum offload for Tx works for most packets, but * fails if previous packet sent did not use hw csum */ -#undef MV643XX_CHECKSUM_OFFLOAD_TX +#define MV643XX_CHECKSUM_OFFLOAD_TX #define MV643XX_NAPI #define MV643XX_TX_FAST_REFILL #undef MV643XX_RX_QUEUE_FILL_ON_TASK /* Does not work, yet */ @@ -217,6 +217,8 @@ #define ETH_TX_ENABLE_INTERRUPT (BIT23) #define ETH_AUTO_MODE (BIT30) +#define ETH_TX_IHL_SHIFT 11 + /* typedefs */ typedef enum _eth_func_ret_status { diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 4a391ea0f58..a1ac4bd1696 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -486,9 +486,9 @@ struct netdrv_private { MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>"); MODULE_DESCRIPTION ("Skeleton for a PCI Fast Ethernet driver"); MODULE_LICENSE("GPL"); -MODULE_PARM (multicast_filter_limit, "i"); -MODULE_PARM (max_interrupt_work, "i"); -MODULE_PARM (media, "1-" __MODULE_STRING(8) "i"); +module_param(multicast_filter_limit, int, 0); +module_param(max_interrupt_work, int, 0); +module_param_array(media, int, NULL, 0); MODULE_PARM_DESC (multicast_filter_limit, "pci-skeleton maximum number of filtered multicast addresses"); MODULE_PARM_DESC (max_interrupt_work, "pci-skeleton maximum events handled per interrupt"); MODULE_PARM_DESC (media, "pci-skeleton: Bits 0-3: media type, bit 17: full duplex"); diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 9d8197bb293..384a736a0d2 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -134,7 +134,7 @@ typedef struct local_info_t { u_char mc_filter[8]; } local_info_t; -#define MC_FILTERBREAK 64 +#define MC_FILTERBREAK 8 /*====================================================================*/ /* @@ -1012,7 +1012,7 @@ static void fjn_reset(struct net_device *dev) outb(BANK_1U, ioaddr + CONFIG_1); /* set the multicast table to accept none. */ - for (i = 0; i < 6; i++) + for (i = 0; i < 8; i++) outb(0x00, ioaddr + MAR_ADR + i); /* Switch to bank 2 (runtime mode) */ @@ -1269,6 +1269,16 @@ static void set_rx_mode(struct net_device *dev) u_long flags; int i; + int saved_config_0 = inb(ioaddr + CONFIG_0); + + local_irq_save(flags); + + /* Disable Tx and Rx */ + if (sram_config == 0) + outb(CONFIG0_RST, ioaddr + CONFIG_0); + else + outb(CONFIG0_RST_1, ioaddr + CONFIG_0); + if (dev->flags & IFF_PROMISC) { /* Unconditionally log net taps. */ printk("%s: Promiscuous mode enabled.\n", dev->name); @@ -1290,20 +1300,23 @@ static void set_rx_mode(struct net_device *dev) for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { unsigned int bit = - ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f; - mc_filter[bit >> 3] |= (1 << bit); + ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26; + mc_filter[bit >> 3] |= (1 << (bit & 7)); } + outb(2, ioaddr + RX_MODE); /* Use normal mode. */ } - local_irq_save(flags); if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) { int saved_bank = inb(ioaddr + CONFIG_1); /* Switch to bank 1 and set the multicast table. */ outb(0xe4, ioaddr + CONFIG_1); for (i = 0; i < 8; i++) - outb(mc_filter[i], ioaddr + 8 + i); + outb(mc_filter[i], ioaddr + MAR_ADR + i); memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter)); outb(saved_bank, ioaddr + CONFIG_1); } + + outb(saved_config_0, ioaddr + CONFIG_0); + local_irq_restore(flags); } diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig new file mode 100644 index 00000000000..6a2fe358347 --- /dev/null +++ b/drivers/net/phy/Kconfig @@ -0,0 +1,57 @@ +# +# PHY Layer Configuration +# + +menu "PHY device support" + +config PHYLIB + tristate "PHY Device support and infrastructure" + depends on NET_ETHERNET + help + Ethernet controllers are usually attached to PHY + devices. This option provides infrastructure for + managing PHY devices. + +config PHYCONTROL + bool " Support for automatically handling PHY state changes" + depends on PHYLIB + help + Adds code to perform all the work for keeping PHY link + state (speed/duplex/etc) up-to-date. Also handles + interrupts. + +comment "MII PHY device drivers" + depends on PHYLIB + +config MARVELL_PHY + tristate "Drivers for Marvell PHYs" + depends on PHYLIB + ---help--- + Currently has a driver for the 88E1011S + +config DAVICOM_PHY + tristate "Drivers for Davicom PHYs" + depends on PHYLIB + ---help--- + Currently supports dm9161e and dm9131 + +config QSEMI_PHY + tristate "Drivers for Quality Semiconductor PHYs" + depends on PHYLIB + ---help--- + Currently supports the qs6612 + +config LXT_PHY + tristate "Drivers for the Intel LXT PHYs" + depends on PHYLIB + ---help--- + Currently supports the lxt970, lxt971 + +config CICADA_PHY + tristate "Drivers for the Cicada PHYs" + depends on PHYLIB + ---help--- + Currently supports the cis8204 + +endmenu + diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile new file mode 100644 index 00000000000..e4116a5fbb4 --- /dev/null +++ b/drivers/net/phy/Makefile @@ -0,0 +1,10 @@ +# Makefile for Linux PHY drivers + +libphy-objs := phy.o phy_device.o mdio_bus.o + +obj-$(CONFIG_PHYLIB) += libphy.o +obj-$(CONFIG_MARVELL_PHY) += marvell.o +obj-$(CONFIG_DAVICOM_PHY) += davicom.o +obj-$(CONFIG_CICADA_PHY) += cicada.o +obj-$(CONFIG_LXT_PHY) += lxt.o +obj-$(CONFIG_QSEMI_PHY) += qsemi.o diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c new file mode 100644 index 00000000000..c47fb2ecd14 --- /dev/null +++ b/drivers/net/phy/cicada.c @@ -0,0 +1,134 @@ +/* + * drivers/net/phy/cicada.c + * + * Driver for Cicada PHYs + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +/* Cicada Extended Control Register 1 */ +#define MII_CIS8201_EXT_CON1 0x17 +#define MII_CIS8201_EXTCON1_INIT 0x0000 + +/* Cicada Interrupt Mask Register */ +#define MII_CIS8201_IMASK 0x19 +#define MII_CIS8201_IMASK_IEN 0x8000 +#define MII_CIS8201_IMASK_SPEED 0x4000 +#define MII_CIS8201_IMASK_LINK 0x2000 +#define MII_CIS8201_IMASK_DUPLEX 0x1000 +#define MII_CIS8201_IMASK_MASK 0xf000 + +/* Cicada Interrupt Status Register */ +#define MII_CIS8201_ISTAT 0x1a +#define MII_CIS8201_ISTAT_STATUS 0x8000 +#define MII_CIS8201_ISTAT_SPEED 0x4000 +#define MII_CIS8201_ISTAT_LINK 0x2000 +#define MII_CIS8201_ISTAT_DUPLEX 0x1000 + +/* Cicada Auxiliary Control/Status Register */ +#define MII_CIS8201_AUX_CONSTAT 0x1c +#define MII_CIS8201_AUXCONSTAT_INIT 0x0004 +#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 +#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 +#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 +#define MII_CIS8201_AUXCONSTAT_100 0x0008 + +MODULE_DESCRIPTION("Cicadia PHY driver"); +MODULE_AUTHOR("Andy Fleming"); +MODULE_LICENSE("GPL"); + +static int cis820x_config_init(struct phy_device *phydev) +{ + int err; + + err = phy_write(phydev, MII_CIS8201_AUX_CONSTAT, + MII_CIS8201_AUXCONSTAT_INIT); + + if (err < 0) + return err; + + err = phy_write(phydev, MII_CIS8201_EXT_CON1, + MII_CIS8201_EXTCON1_INIT); + + return err; +} + +static int cis820x_ack_interrupt(struct phy_device *phydev) +{ + int err = phy_read(phydev, MII_CIS8201_ISTAT); + + return (err < 0) ? err : 0; +} + +static int cis820x_config_intr(struct phy_device *phydev) +{ + int err; + + if(phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, MII_CIS8201_IMASK, + MII_CIS8201_IMASK_MASK); + else + err = phy_write(phydev, MII_CIS8201_IMASK, 0); + + return err; +} + +/* Cicada 820x */ +static struct phy_driver cis8204_driver = { + .phy_id = 0x000fc440, + .name = "Cicada Cis8204", + .phy_id_mask = 0x000fffc0, + .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,}, +}; + +static int __init cis8204_init(void) +{ + return phy_driver_register(&cis8204_driver); +} + +static void __exit cis8204_exit(void) +{ + phy_driver_unregister(&cis8204_driver); +} + +module_init(cis8204_init); +module_exit(cis8204_exit); diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c new file mode 100644 index 00000000000..6caf499fae3 --- /dev/null +++ b/drivers/net/phy/davicom.c @@ -0,0 +1,195 @@ +/* + * drivers/net/phy/davicom.c + * + * Driver for Davicom PHYs + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +#define MII_DM9161_SCR 0x10 +#define MII_DM9161_SCR_INIT 0x0610 + +/* DM9161 Interrupt Register */ +#define MII_DM9161_INTR 0x15 +#define MII_DM9161_INTR_PEND 0x8000 +#define MII_DM9161_INTR_DPLX_MASK 0x0800 +#define MII_DM9161_INTR_SPD_MASK 0x0400 +#define MII_DM9161_INTR_LINK_MASK 0x0200 +#define MII_DM9161_INTR_MASK 0x0100 +#define MII_DM9161_INTR_DPLX_CHANGE 0x0010 +#define MII_DM9161_INTR_SPD_CHANGE 0x0008 +#define MII_DM9161_INTR_LINK_CHANGE 0x0004 +#define MII_DM9161_INTR_INIT 0x0000 +#define MII_DM9161_INTR_STOP \ +(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ + | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) + +/* DM9161 10BT Configuration/Status */ +#define MII_DM9161_10BTCSR 0x12 +#define MII_DM9161_10BTCSR_INIT 0x7800 + +MODULE_DESCRIPTION("Davicom PHY driver"); +MODULE_AUTHOR("Andy Fleming"); +MODULE_LICENSE("GPL"); + + +#define DM9161_DELAY 1 +static int dm9161_config_intr(struct phy_device *phydev) +{ + int temp; + + temp = phy_read(phydev, MII_DM9161_INTR); + + if (temp < 0) + return temp; + + if(PHY_INTERRUPT_ENABLED == phydev->interrupts ) + temp &= ~(MII_DM9161_INTR_STOP); + else + temp |= MII_DM9161_INTR_STOP; + + temp = phy_write(phydev, MII_DM9161_INTR, temp); + + return temp; +} + +static int dm9161_config_aneg(struct phy_device *phydev) +{ + int err; + + /* Isolate the PHY */ + err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE); + + if (err < 0) + return err; + + /* Configure the new settings */ + err = genphy_config_aneg(phydev); + + if (err < 0) + return err; + + return 0; +} + +static int dm9161_config_init(struct phy_device *phydev) +{ + int err; + + /* Isolate the PHY */ + err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE); + + if (err < 0) + return err; + + /* Do not bypass the scrambler/descrambler */ + err = phy_write(phydev, MII_DM9161_SCR, MII_DM9161_SCR_INIT); + + if (err < 0) + return err; + + /* Clear 10BTCSR to default */ + err = phy_write(phydev, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT); + + if (err < 0) + return err; + + /* Reconnect the PHY, and enable Autonegotiation */ + err = phy_write(phydev, MII_BMCR, BMCR_ANENABLE); + + if (err < 0) + return err; + + return 0; +} + +static int dm9161_ack_interrupt(struct phy_device *phydev) +{ + int err = phy_read(phydev, MII_DM9161_INTR); + + return (err < 0) ? err : 0; +} + +static struct phy_driver dm9161_driver = { + .phy_id = 0x0181b880, + .name = "Davicom DM9161E", + .phy_id_mask = 0x0ffffff0, + .features = PHY_BASIC_FEATURES, + .config_init = dm9161_config_init, + .config_aneg = dm9161_config_aneg, + .read_status = genphy_read_status, + .driver = { .owner = THIS_MODULE,}, +}; + +static struct phy_driver dm9131_driver = { + .phy_id = 0x00181b80, + .name = "Davicom DM9131", + .phy_id_mask = 0x0ffffff0, + .features = PHY_BASIC_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = dm9161_ack_interrupt, + .config_intr = dm9161_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init davicom_init(void) +{ + int ret; + + ret = phy_driver_register(&dm9161_driver); + if (ret) + goto err1; + + ret = phy_driver_register(&dm9131_driver); + if (ret) + goto err2; + return 0; + + err2: + phy_driver_unregister(&dm9161_driver); + err1: + return ret; +} + +static void __exit davicom_exit(void) +{ + phy_driver_unregister(&dm9161_driver); + phy_driver_unregister(&dm9131_driver); +} + +module_init(davicom_init); +module_exit(davicom_exit); diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c new file mode 100644 index 00000000000..4c840448ec8 --- /dev/null +++ b/drivers/net/phy/lxt.c @@ -0,0 +1,179 @@ +/* + * drivers/net/phy/lxt.c + * + * Driver for Intel LXT PHYs + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +/* The Level one LXT970 is used by many boards */ + +#define MII_LXT970_IER 17 /* Interrupt Enable Register */ + +#define MII_LXT970_IER_IEN 0x0002 + +#define MII_LXT970_ISR 18 /* Interrupt Status Register */ + +#define MII_LXT970_CONFIG 19 /* Configuration Register */ + +/* ------------------------------------------------------------------------- */ +/* The Level one LXT971 is used on some of my custom boards */ + +/* register definitions for the 971 */ +#define MII_LXT971_IER 18 /* Interrupt Enable Register */ +#define MII_LXT971_IER_IEN 0x00f2 + +#define MII_LXT971_ISR 19 /* Interrupt Status Register */ + + +MODULE_DESCRIPTION("Intel LXT PHY driver"); +MODULE_AUTHOR("Andy Fleming"); +MODULE_LICENSE("GPL"); + +static int lxt970_ack_interrupt(struct phy_device *phydev) +{ + int err; + + err = phy_read(phydev, MII_BMSR); + + if (err < 0) + return err; + + err = phy_read(phydev, MII_LXT970_ISR); + + if (err < 0) + return err; + + return 0; +} + +static int lxt970_config_intr(struct phy_device *phydev) +{ + int err; + + if(phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, MII_LXT970_IER, MII_LXT970_IER_IEN); + else + err = phy_write(phydev, MII_LXT970_IER, 0); + + return err; +} + +static int lxt970_config_init(struct phy_device *phydev) +{ + int err; + + err = phy_write(phydev, MII_LXT970_CONFIG, 0); + + return err; +} + + +static int lxt971_ack_interrupt(struct phy_device *phydev) +{ + int err = phy_read(phydev, MII_LXT971_ISR); + + if (err < 0) + return err; + + return 0; +} + +static int lxt971_config_intr(struct phy_device *phydev) +{ + int err; + + if(phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, MII_LXT971_IER, MII_LXT971_IER_IEN); + else + err = phy_write(phydev, MII_LXT971_IER, 0); + + return err; +} + +static struct phy_driver lxt970_driver = { + .phy_id = 0x07810000, + .name = "LXT970", + .phy_id_mask = 0x0fffffff, + .features = PHY_BASIC_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_init = lxt970_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = lxt970_ack_interrupt, + .config_intr = lxt970_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; + +static struct phy_driver lxt971_driver = { + .phy_id = 0x0001378e, + .name = "LXT971", + .phy_id_mask = 0x0fffffff, + .features = PHY_BASIC_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = lxt971_ack_interrupt, + .config_intr = lxt971_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init lxt_init(void) +{ + int ret; + + ret = phy_driver_register(&lxt970_driver); + if (ret) + goto err1; + + ret = phy_driver_register(&lxt971_driver); + if (ret) + goto err2; + return 0; + + err2: + phy_driver_unregister(&lxt970_driver); + err1: + return ret; +} + +static void __exit lxt_exit(void) +{ + phy_driver_unregister(&lxt970_driver); + phy_driver_unregister(&lxt971_driver); +} + +module_init(lxt_init); +module_exit(lxt_exit); diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c new file mode 100644 index 00000000000..4a72b025006 --- /dev/null +++ b/drivers/net/phy/marvell.c @@ -0,0 +1,140 @@ +/* + * drivers/net/phy/marvell.c + * + * Driver for Marvell PHYs + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +#define MII_M1011_IEVENT 0x13 +#define MII_M1011_IEVENT_CLEAR 0x0000 + +#define MII_M1011_IMASK 0x12 +#define MII_M1011_IMASK_INIT 0x6400 +#define MII_M1011_IMASK_CLEAR 0x0000 + +MODULE_DESCRIPTION("Marvell PHY driver"); +MODULE_AUTHOR("Andy Fleming"); +MODULE_LICENSE("GPL"); + +static int marvell_ack_interrupt(struct phy_device *phydev) +{ + int err; + + /* Clear the interrupts by reading the reg */ + err = phy_read(phydev, MII_M1011_IEVENT); + + if (err < 0) + return err; + + return 0; +} + +static int marvell_config_intr(struct phy_device *phydev) +{ + int err; + + if(phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); + else + err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + + return err; +} + +static int marvell_config_aneg(struct phy_device *phydev) +{ + int err; + + /* The Marvell PHY has an errata which requires + * that certain registers get written in order + * to restart autonegotiation */ + err = phy_write(phydev, MII_BMCR, BMCR_RESET); + + if (err < 0) + return err; + + err = phy_write(phydev, 0x1d, 0x1f); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0x200c); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1d, 0x5); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0x100); + if (err < 0) + return err; + + + err = genphy_config_aneg(phydev); + + return err; +} + + +static struct phy_driver m88e1101_driver = { + .phy_id = 0x01410c00, + .phy_id_mask = 0xffffff00, + .name = "Marvell 88E1101", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &marvell_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init marvell_init(void) +{ + return phy_driver_register(&m88e1101_driver); +} + +static void __exit marvell_exit(void) +{ + phy_driver_unregister(&m88e1101_driver); +} + +module_init(marvell_init); +module_exit(marvell_exit); diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c new file mode 100644 index 00000000000..41f62c0c5fc --- /dev/null +++ b/drivers/net/phy/mdio_bus.c @@ -0,0 +1,176 @@ +/* + * drivers/net/phy/mdio_bus.c + * + * MDIO Bus interface + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +/* mdiobus_register + * + * description: Called by a bus driver to bring up all the PHYs + * on a given bus, and attach them to the bus + */ +int mdiobus_register(struct mii_bus *bus) +{ + int i; + int err = 0; + + spin_lock_init(&bus->mdio_lock); + + if (NULL == bus || NULL == bus->name || + NULL == bus->read || + NULL == bus->write) + return -EINVAL; + + if (bus->reset) + bus->reset(bus); + + for (i = 0; i < PHY_MAX_ADDR; i++) { + struct phy_device *phydev; + + phydev = get_phy_device(bus, i); + + if (IS_ERR(phydev)) + return PTR_ERR(phydev); + + /* There's a PHY at this address + * We need to set: + * 1) IRQ + * 2) bus_id + * 3) parent + * 4) bus + * 5) mii_bus + * And, we need to register it */ + if (phydev) { + phydev->irq = bus->irq[i]; + + phydev->dev.parent = bus->dev; + phydev->dev.bus = &mdio_bus_type; + sprintf(phydev->dev.bus_id, "phy%d:%d", bus->id, i); + + phydev->bus = bus; + + err = device_register(&phydev->dev); + + if (err) + printk(KERN_ERR "phy %d failed to register\n", + i); + } + + bus->phy_map[i] = phydev; + } + + pr_info("%s: probed\n", bus->name); + + return err; +} +EXPORT_SYMBOL(mdiobus_register); + +void mdiobus_unregister(struct mii_bus *bus) +{ + int i; + + for (i = 0; i < PHY_MAX_ADDR; i++) { + if (bus->phy_map[i]) { + device_unregister(&bus->phy_map[i]->dev); + kfree(bus->phy_map[i]); + } + } +} +EXPORT_SYMBOL(mdiobus_unregister); + +/* mdio_bus_match + * + * description: Given a PHY device, and a PHY driver, return 1 if + * the driver supports the device. Otherwise, return 0 + */ +static int mdio_bus_match(struct device *dev, struct device_driver *drv) +{ + struct phy_device *phydev = to_phy_device(dev); + struct phy_driver *phydrv = to_phy_driver(drv); + + return (phydrv->phy_id == (phydev->phy_id & phydrv->phy_id_mask)); +} + +/* Suspend and resume. Copied from platform_suspend and + * platform_resume + */ +static int mdio_bus_suspend(struct device * dev, u32 state) +{ + int ret = 0; + struct device_driver *drv = dev->driver; + + if (drv && drv->suspend) { + ret = drv->suspend(dev, state, SUSPEND_DISABLE); + if (ret == 0) + ret = drv->suspend(dev, state, SUSPEND_SAVE_STATE); + if (ret == 0) + ret = drv->suspend(dev, state, SUSPEND_POWER_DOWN); + } + return ret; +} + +static int mdio_bus_resume(struct device * dev) +{ + int ret = 0; + struct device_driver *drv = dev->driver; + + if (drv && drv->resume) { + ret = drv->resume(dev, RESUME_POWER_ON); + if (ret == 0) + ret = drv->resume(dev, RESUME_RESTORE_STATE); + if (ret == 0) + ret = drv->resume(dev, RESUME_ENABLE); + } + return ret; +} + +struct bus_type mdio_bus_type = { + .name = "mdio_bus", + .match = mdio_bus_match, + .suspend = mdio_bus_suspend, + .resume = mdio_bus_resume, +}; + +int __init mdio_bus_init(void) +{ + return bus_register(&mdio_bus_type); +} + +void __exit mdio_bus_exit(void) +{ + bus_unregister(&mdio_bus_type); +} diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c new file mode 100644 index 00000000000..d9e11f93bf3 --- /dev/null +++ b/drivers/net/phy/phy.c @@ -0,0 +1,871 @@ +/* + * drivers/net/phy/phy.c + * + * Framework for configuring and reading PHY devices + * Based on code in sungem_phy.c and gianfar_phy.c + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +/* Convenience function to print out the current phy status + */ +void phy_print_status(struct phy_device *phydev) +{ + pr_info("%s: Link is %s", phydev->dev.bus_id, + phydev->link ? "Up" : "Down"); + if (phydev->link) + printk(" - %d/%s", phydev->speed, + DUPLEX_FULL == phydev->duplex ? + "Full" : "Half"); + + printk("\n"); +} +EXPORT_SYMBOL(phy_print_status); + + +/* Convenience functions for reading/writing a given PHY + * register. They MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. */ +int phy_read(struct phy_device *phydev, u16 regnum) +{ + int retval; + struct mii_bus *bus = phydev->bus; + + spin_lock_bh(&bus->mdio_lock); + retval = bus->read(bus, phydev->addr, regnum); + spin_unlock_bh(&bus->mdio_lock); + + return retval; +} +EXPORT_SYMBOL(phy_read); + +int phy_write(struct phy_device *phydev, u16 regnum, u16 val) +{ + int err; + struct mii_bus *bus = phydev->bus; + + spin_lock_bh(&bus->mdio_lock); + err = bus->write(bus, phydev->addr, regnum, val); + spin_unlock_bh(&bus->mdio_lock); + + return err; +} +EXPORT_SYMBOL(phy_write); + + +int phy_clear_interrupt(struct phy_device *phydev) +{ + int err = 0; + + if (phydev->drv->ack_interrupt) + err = phydev->drv->ack_interrupt(phydev); + + return err; +} + + +int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) +{ + int err = 0; + + phydev->interrupts = interrupts; + if (phydev->drv->config_intr) + err = phydev->drv->config_intr(phydev); + + return err; +} + + +/* phy_aneg_done + * + * description: Reads the status register and returns 0 either if + * auto-negotiation is incomplete, or if there was an error. + * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. + */ +static inline int phy_aneg_done(struct phy_device *phydev) +{ + int retval; + + retval = phy_read(phydev, MII_BMSR); + + return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); +} + +/* A structure for mapping a particular speed and duplex + * combination to a particular SUPPORTED and ADVERTISED value */ +struct phy_setting { + int speed; + int duplex; + u32 setting; +}; + +/* A mapping of all SUPPORTED settings to speed/duplex */ +static struct phy_setting settings[] = { + { + .speed = 10000, + .duplex = DUPLEX_FULL, + .setting = SUPPORTED_10000baseT_Full, + }, + { + .speed = SPEED_1000, + .duplex = DUPLEX_FULL, + .setting = SUPPORTED_1000baseT_Full, + }, + { + .speed = SPEED_1000, + .duplex = DUPLEX_HALF, + .setting = SUPPORTED_1000baseT_Half, + }, + { + .speed = SPEED_100, + .duplex = DUPLEX_FULL, + .setting = SUPPORTED_100baseT_Full, + }, + { + .speed = SPEED_100, + .duplex = DUPLEX_HALF, + .setting = SUPPORTED_100baseT_Half, + }, + { + .speed = SPEED_10, + .duplex = DUPLEX_FULL, + .setting = SUPPORTED_10baseT_Full, + }, + { + .speed = SPEED_10, + .duplex = DUPLEX_HALF, + .setting = SUPPORTED_10baseT_Half, + }, +}; + +#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting)) + +/* phy_find_setting + * + * description: Searches the settings array for the setting which + * matches the desired speed and duplex, and returns the index + * of that setting. Returns the index of the last setting if + * none of the others match. + */ +static inline int phy_find_setting(int speed, int duplex) +{ + int idx = 0; + + while (idx < ARRAY_SIZE(settings) && + (settings[idx].speed != speed || + settings[idx].duplex != duplex)) + idx++; + + return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; +} + +/* phy_find_valid + * idx: The first index in settings[] to search + * features: A mask of the valid settings + * + * description: Returns the index of the first valid setting less + * than or equal to the one pointed to by idx, as determined by + * the mask in features. Returns the index of the last setting + * if nothing else matches. + */ +static inline int phy_find_valid(int idx, u32 features) +{ + while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features)) + idx++; + + return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; +} + +/* phy_sanitize_settings + * + * description: Make sure the PHY is set to supported speeds and + * duplexes. Drop down by one in this order: 1000/FULL, + * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF + */ +void phy_sanitize_settings(struct phy_device *phydev) +{ + u32 features = phydev->supported; + int idx; + + /* Sanitize settings based on PHY capabilities */ + if ((features & SUPPORTED_Autoneg) == 0) + phydev->autoneg = 0; + + idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex), + features); + + phydev->speed = settings[idx].speed; + phydev->duplex = settings[idx].duplex; +} +EXPORT_SYMBOL(phy_sanitize_settings); + +/* phy_ethtool_sset: + * A generic ethtool sset function. Handles all the details + * + * A few notes about parameter checking: + * - We don't set port or transceiver, so we don't care what they + * were set to. + * - phy_start_aneg() will make sure forced settings are sane, and + * choose the next best ones from the ones selected, so we don't + * care if ethtool tries to give us bad values + * + * A note about the PHYCONTROL Layer. If you turn off + * CONFIG_PHYCONTROL, you will need to read the PHY status + * registers after this function completes, and update your + * controller manually. + */ +int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) +{ + if (cmd->phy_address != phydev->addr) + return -EINVAL; + + /* We make sure that we don't pass unsupported + * values in to the PHY */ + cmd->advertising &= phydev->supported; + + /* Verify the settings we care about. */ + if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE) + return -EINVAL; + + if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) + return -EINVAL; + + if (cmd->autoneg == AUTONEG_DISABLE + && ((cmd->speed != SPEED_1000 + && cmd->speed != SPEED_100 + && cmd->speed != SPEED_10) + || (cmd->duplex != DUPLEX_HALF + && cmd->duplex != DUPLEX_FULL))) + return -EINVAL; + + phydev->autoneg = cmd->autoneg; + + phydev->speed = cmd->speed; + + phydev->advertising = cmd->advertising; + + if (AUTONEG_ENABLE == cmd->autoneg) + phydev->advertising |= ADVERTISED_Autoneg; + else + phydev->advertising &= ~ADVERTISED_Autoneg; + + phydev->duplex = cmd->duplex; + + /* Restart the PHY */ + phy_start_aneg(phydev); + + return 0; +} + +int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) +{ + cmd->supported = phydev->supported; + + cmd->advertising = phydev->advertising; + + cmd->speed = phydev->speed; + cmd->duplex = phydev->duplex; + cmd->port = PORT_MII; + cmd->phy_address = phydev->addr; + cmd->transceiver = XCVR_EXTERNAL; + cmd->autoneg = phydev->autoneg; + + return 0; +} + + +/* Note that this function is currently incompatible with the + * PHYCONTROL layer. It changes registers without regard to + * current state. Use at own risk + */ +int phy_mii_ioctl(struct phy_device *phydev, + struct mii_ioctl_data *mii_data, int cmd) +{ + u16 val = mii_data->val_in; + + switch (cmd) { + case SIOCGMIIPHY: + mii_data->phy_id = phydev->addr; + break; + case SIOCGMIIREG: + mii_data->val_out = phy_read(phydev, mii_data->reg_num); + break; + + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (mii_data->phy_id == phydev->addr) { + switch(mii_data->reg_num) { + case MII_BMCR: + if (val & (BMCR_RESET|BMCR_ANENABLE)) + phydev->autoneg = AUTONEG_DISABLE; + else + phydev->autoneg = AUTONEG_ENABLE; + if ((!phydev->autoneg) && (val & BMCR_FULLDPLX)) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + break; + case MII_ADVERTISE: + phydev->advertising = val; + break; + default: + /* do nothing */ + break; + } + } + + phy_write(phydev, mii_data->reg_num, val); + + if (mii_data->reg_num == MII_BMCR + && val & BMCR_RESET + && phydev->drv->config_init) + phydev->drv->config_init(phydev); + break; + } + + return 0; +} + +/* phy_start_aneg + * + * description: Sanitizes the settings (if we're not + * autonegotiating them), and then calls the driver's + * config_aneg function. If the PHYCONTROL Layer is operating, + * we change the state to reflect the beginning of + * Auto-negotiation or forcing. + */ +int phy_start_aneg(struct phy_device *phydev) +{ + int err; + + spin_lock(&phydev->lock); + + if (AUTONEG_DISABLE == phydev->autoneg) + phy_sanitize_settings(phydev); + + err = phydev->drv->config_aneg(phydev); + +#ifdef CONFIG_PHYCONTROL + if (err < 0) + goto out_unlock; + + if (phydev->state != PHY_HALTED) { + if (AUTONEG_ENABLE == phydev->autoneg) { + phydev->state = PHY_AN; + phydev->link_timeout = PHY_AN_TIMEOUT; + } else { + phydev->state = PHY_FORCING; + phydev->link_timeout = PHY_FORCE_TIMEOUT; + } + } + +out_unlock: +#endif + spin_unlock(&phydev->lock); + return err; +} +EXPORT_SYMBOL(phy_start_aneg); + + +#ifdef CONFIG_PHYCONTROL +static void phy_change(void *data); +static void phy_timer(unsigned long data); + +/* phy_start_machine: + * + * description: The PHY infrastructure can run a state machine + * which tracks whether the PHY is starting up, negotiating, + * etc. This function starts the timer which tracks the state + * of the PHY. If you want to be notified when the state + * changes, pass in the callback, otherwise, pass NULL. If you + * want to maintain your own state machine, do not call this + * function. */ +void phy_start_machine(struct phy_device *phydev, + void (*handler)(struct net_device *)) +{ + phydev->adjust_state = handler; + + init_timer(&phydev->phy_timer); + phydev->phy_timer.function = &phy_timer; + phydev->phy_timer.data = (unsigned long) phydev; + mod_timer(&phydev->phy_timer, jiffies + HZ); +} + +/* phy_stop_machine + * + * description: Stops the state machine timer, sets the state to + * UP (unless it wasn't up yet), and then frees the interrupt, + * if it is in use. This function must be called BEFORE + * phy_detach. + */ +void phy_stop_machine(struct phy_device *phydev) +{ + del_timer_sync(&phydev->phy_timer); + + spin_lock(&phydev->lock); + if (phydev->state > PHY_UP) + phydev->state = PHY_UP; + spin_unlock(&phydev->lock); + + if (phydev->irq != PHY_POLL) + phy_stop_interrupts(phydev); + + phydev->adjust_state = NULL; +} + +/* phy_force_reduction + * + * description: Reduces the speed/duplex settings by + * one notch. The order is so: + * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, + * 10/FULL, 10/HALF. The function bottoms out at 10/HALF. + */ +static void phy_force_reduction(struct phy_device *phydev) +{ + int idx; + + idx = phy_find_setting(phydev->speed, phydev->duplex); + + idx++; + + idx = phy_find_valid(idx, phydev->supported); + + phydev->speed = settings[idx].speed; + phydev->duplex = settings[idx].duplex; + + pr_info("Trying %d/%s\n", phydev->speed, + DUPLEX_FULL == phydev->duplex ? + "FULL" : "HALF"); +} + + +/* phy_error: + * + * Moves the PHY to the HALTED state in response to a read + * or write error, and tells the controller the link is down. + * Must not be called from interrupt context, or while the + * phydev->lock is held. + */ +void phy_error(struct phy_device *phydev) +{ + spin_lock(&phydev->lock); + phydev->state = PHY_HALTED; + spin_unlock(&phydev->lock); +} + +/* phy_interrupt + * + * description: When a PHY interrupt occurs, the handler disables + * interrupts, and schedules a work task to clear the interrupt. + */ +static irqreturn_t phy_interrupt(int irq, void *phy_dat, struct pt_regs *regs) +{ + struct phy_device *phydev = phy_dat; + + /* The MDIO bus is not allowed to be written in interrupt + * context, so we need to disable the irq here. A work + * queue will write the PHY to disable and clear the + * interrupt, and then reenable the irq line. */ + disable_irq_nosync(irq); + + schedule_work(&phydev->phy_queue); + + return IRQ_HANDLED; +} + +/* Enable the interrupts from the PHY side */ +int phy_enable_interrupts(struct phy_device *phydev) +{ + int err; + + err = phy_clear_interrupt(phydev); + + if (err < 0) + return err; + + err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); + + return err; +} +EXPORT_SYMBOL(phy_enable_interrupts); + +/* Disable the PHY interrupts from the PHY side */ +int phy_disable_interrupts(struct phy_device *phydev) +{ + int err; + + /* Disable PHY interrupts */ + err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); + + if (err) + goto phy_err; + + /* Clear the interrupt */ + err = phy_clear_interrupt(phydev); + + if (err) + goto phy_err; + + return 0; + +phy_err: + phy_error(phydev); + + return err; +} +EXPORT_SYMBOL(phy_disable_interrupts); + +/* phy_start_interrupts + * + * description: Request the interrupt for the given PHY. If + * this fails, then we set irq to PHY_POLL. + * Otherwise, we enable the interrupts in the PHY. + * Returns 0 on success. + * This should only be called with a valid IRQ number. + */ +int phy_start_interrupts(struct phy_device *phydev) +{ + int err = 0; + + INIT_WORK(&phydev->phy_queue, phy_change, phydev); + + if (request_irq(phydev->irq, phy_interrupt, + SA_SHIRQ, + "phy_interrupt", + phydev) < 0) { + printk(KERN_WARNING "%s: Can't get IRQ %d (PHY)\n", + phydev->bus->name, + phydev->irq); + phydev->irq = PHY_POLL; + return 0; + } + + err = phy_enable_interrupts(phydev); + + return err; +} +EXPORT_SYMBOL(phy_start_interrupts); + +int phy_stop_interrupts(struct phy_device *phydev) +{ + int err; + + err = phy_disable_interrupts(phydev); + + if (err) + phy_error(phydev); + + free_irq(phydev->irq, phydev); + + return err; +} +EXPORT_SYMBOL(phy_stop_interrupts); + + +/* Scheduled by the phy_interrupt/timer to handle PHY changes */ +static void phy_change(void *data) +{ + int err; + struct phy_device *phydev = data; + + err = phy_disable_interrupts(phydev); + + if (err) + goto phy_err; + + spin_lock(&phydev->lock); + if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state)) + phydev->state = PHY_CHANGELINK; + spin_unlock(&phydev->lock); + + enable_irq(phydev->irq); + + /* Reenable interrupts */ + err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); + + if (err) + goto irq_enable_err; + + return; + +irq_enable_err: + disable_irq(phydev->irq); +phy_err: + phy_error(phydev); +} + +/* Bring down the PHY link, and stop checking the status. */ +void phy_stop(struct phy_device *phydev) +{ + spin_lock(&phydev->lock); + + if (PHY_HALTED == phydev->state) + goto out_unlock; + + if (phydev->irq != PHY_POLL) { + /* Clear any pending interrupts */ + phy_clear_interrupt(phydev); + + /* Disable PHY Interrupts */ + phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); + } + + phydev->state = PHY_HALTED; + +out_unlock: + spin_unlock(&phydev->lock); +} + + +/* phy_start + * + * description: Indicates the attached device's readiness to + * handle PHY-related work. Used during startup to start the + * PHY, and after a call to phy_stop() to resume operation. + * Also used to indicate the MDIO bus has cleared an error + * condition. + */ +void phy_start(struct phy_device *phydev) +{ + spin_lock(&phydev->lock); + + switch (phydev->state) { + case PHY_STARTING: + phydev->state = PHY_PENDING; + break; + case PHY_READY: + phydev->state = PHY_UP; + break; + case PHY_HALTED: + phydev->state = PHY_RESUMING; + default: + break; + } + spin_unlock(&phydev->lock); +} +EXPORT_SYMBOL(phy_stop); +EXPORT_SYMBOL(phy_start); + +/* PHY timer which handles the state machine */ +static void phy_timer(unsigned long data) +{ + struct phy_device *phydev = (struct phy_device *)data; + int needs_aneg = 0; + int err = 0; + + spin_lock(&phydev->lock); + + if (phydev->adjust_state) + phydev->adjust_state(phydev->attached_dev); + + switch(phydev->state) { + case PHY_DOWN: + case PHY_STARTING: + case PHY_READY: + case PHY_PENDING: + break; + case PHY_UP: + needs_aneg = 1; + + phydev->link_timeout = PHY_AN_TIMEOUT; + + break; + case PHY_AN: + /* Check if negotiation is done. Break + * if there's an error */ + err = phy_aneg_done(phydev); + if (err < 0) + break; + + /* If auto-negotiation is done, we change to + * either RUNNING, or NOLINK */ + if (err > 0) { + err = phy_read_status(phydev); + + if (err) + break; + + if (phydev->link) { + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + } else { + phydev->state = PHY_NOLINK; + netif_carrier_off(phydev->attached_dev); + } + + phydev->adjust_link(phydev->attached_dev); + + } else if (0 == phydev->link_timeout--) { + /* The counter expired, so either we + * switch to forced mode, or the + * magic_aneg bit exists, and we try aneg + * again */ + if (!(phydev->drv->flags & PHY_HAS_MAGICANEG)) { + int idx; + + /* We'll start from the + * fastest speed, and work + * our way down */ + idx = phy_find_valid(0, + phydev->supported); + + phydev->speed = settings[idx].speed; + phydev->duplex = settings[idx].duplex; + + phydev->autoneg = AUTONEG_DISABLE; + phydev->state = PHY_FORCING; + phydev->link_timeout = + PHY_FORCE_TIMEOUT; + + pr_info("Trying %d/%s\n", + phydev->speed, + DUPLEX_FULL == + phydev->duplex ? + "FULL" : "HALF"); + } + + needs_aneg = 1; + } + break; + case PHY_NOLINK: + err = phy_read_status(phydev); + + if (err) + break; + + if (phydev->link) { + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + } + break; + case PHY_FORCING: + err = phy_read_status(phydev); + + if (err) + break; + + if (phydev->link) { + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + } else { + if (0 == phydev->link_timeout--) { + phy_force_reduction(phydev); + needs_aneg = 1; + } + } + + phydev->adjust_link(phydev->attached_dev); + break; + case PHY_RUNNING: + /* Only register a CHANGE if we are + * polling */ + if (PHY_POLL == phydev->irq) + phydev->state = PHY_CHANGELINK; + break; + case PHY_CHANGELINK: + err = phy_read_status(phydev); + + if (err) + break; + + if (phydev->link) { + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + } else { + phydev->state = PHY_NOLINK; + netif_carrier_off(phydev->attached_dev); + } + + phydev->adjust_link(phydev->attached_dev); + + if (PHY_POLL != phydev->irq) + err = phy_config_interrupt(phydev, + PHY_INTERRUPT_ENABLED); + break; + case PHY_HALTED: + if (phydev->link) { + phydev->link = 0; + netif_carrier_off(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + } + break; + case PHY_RESUMING: + + err = phy_clear_interrupt(phydev); + + if (err) + break; + + err = phy_config_interrupt(phydev, + PHY_INTERRUPT_ENABLED); + + if (err) + break; + + if (AUTONEG_ENABLE == phydev->autoneg) { + err = phy_aneg_done(phydev); + if (err < 0) + break; + + /* err > 0 if AN is done. + * Otherwise, it's 0, and we're + * still waiting for AN */ + if (err > 0) { + phydev->state = PHY_RUNNING; + } else { + phydev->state = PHY_AN; + phydev->link_timeout = PHY_AN_TIMEOUT; + } + } else + phydev->state = PHY_RUNNING; + break; + } + + spin_unlock(&phydev->lock); + + if (needs_aneg) + err = phy_start_aneg(phydev); + + if (err < 0) + phy_error(phydev); + + mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ); +} + +#endif /* CONFIG_PHYCONTROL */ diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c new file mode 100644 index 00000000000..33f7bdb5857 --- /dev/null +++ b/drivers/net/phy/phy_device.c @@ -0,0 +1,696 @@ +/* + * drivers/net/phy/phy_device.c + * + * Framework for finding and configuring PHYs. + * Also contains generic PHY driver + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +static struct phy_driver genphy_driver; +extern int mdio_bus_init(void); +extern void mdio_bus_exit(void); + +/* get_phy_device + * + * description: Reads the ID registers of the PHY at addr on the + * bus, then allocates and returns the phy_device to + * represent it. + */ +struct phy_device * get_phy_device(struct mii_bus *bus, int addr) +{ + int phy_reg; + u32 phy_id; + struct phy_device *dev = NULL; + + /* Grab the bits from PHYIR1, and put them + * in the upper half */ + phy_reg = bus->read(bus, addr, MII_PHYSID1); + + if (phy_reg < 0) + return ERR_PTR(phy_reg); + + phy_id = (phy_reg & 0xffff) << 16; + + /* Grab the bits from PHYIR2, and put them in the lower half */ + phy_reg = bus->read(bus, addr, MII_PHYSID2); + + if (phy_reg < 0) + return ERR_PTR(phy_reg); + + phy_id |= (phy_reg & 0xffff); + + /* If the phy_id is all Fs, there is no device there */ + if (0xffffffff == phy_id) + return NULL; + + /* Otherwise, we allocate the device, and initialize the + * default values */ + dev = kcalloc(1, sizeof(*dev), GFP_KERNEL); + + if (NULL == dev) + return ERR_PTR(-ENOMEM); + + dev->speed = 0; + dev->duplex = -1; + dev->pause = dev->asym_pause = 0; + dev->link = 1; + + dev->autoneg = AUTONEG_ENABLE; + + dev->addr = addr; + dev->phy_id = phy_id; + dev->bus = bus; + + dev->state = PHY_DOWN; + + spin_lock_init(&dev->lock); + + return dev; +} + +#ifdef CONFIG_PHYCONTROL +/* phy_prepare_link: + * + * description: Tells the PHY infrastructure to handle the + * gory details on monitoring link status (whether through + * polling or an interrupt), and to call back to the + * connected device driver when the link status changes. + * If you want to monitor your own link state, don't call + * this function */ +void phy_prepare_link(struct phy_device *phydev, + void (*handler)(struct net_device *)) +{ + phydev->adjust_link = handler; +} + +/* phy_connect: + * + * description: Convenience function for connecting ethernet + * devices to PHY devices. The default behavior is for + * the PHY infrastructure to handle everything, and only notify + * the connected driver when the link status changes. If you + * don't want, or can't use the provided functionality, you may + * choose to call only the subset of functions which provide + * the desired functionality. + */ +struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, + void (*handler)(struct net_device *), u32 flags) +{ + struct phy_device *phydev; + + phydev = phy_attach(dev, phy_id, flags); + + if (IS_ERR(phydev)) + return phydev; + + phy_prepare_link(phydev, handler); + + phy_start_machine(phydev, NULL); + + if (phydev->irq > 0) + phy_start_interrupts(phydev); + + return phydev; +} +EXPORT_SYMBOL(phy_connect); + +void phy_disconnect(struct phy_device *phydev) +{ + if (phydev->irq > 0) + phy_stop_interrupts(phydev); + + phy_stop_machine(phydev); + + phydev->adjust_link = NULL; + + phy_detach(phydev); +} +EXPORT_SYMBOL(phy_disconnect); + +#endif /* CONFIG_PHYCONTROL */ + +/* phy_attach: + * + * description: Called by drivers to attach to a particular PHY + * device. The phy_device is found, and properly hooked up + * to the phy_driver. If no driver is attached, then the + * genphy_driver is used. The phy_device is given a ptr to + * the attaching device, and given a callback for link status + * change. The phy_device is returned to the attaching + * driver. + */ +static int phy_compare_id(struct device *dev, void *data) +{ + return strcmp((char *)data, dev->bus_id) ? 0 : 1; +} + +struct phy_device *phy_attach(struct net_device *dev, + const char *phy_id, u32 flags) +{ + struct bus_type *bus = &mdio_bus_type; + struct phy_device *phydev; + struct device *d; + + /* Search the list of PHY devices on the mdio bus for the + * PHY with the requested name */ + d = bus_find_device(bus, NULL, (void *)phy_id, phy_compare_id); + + if (d) { + phydev = to_phy_device(d); + } else { + printk(KERN_ERR "%s not found\n", phy_id); + return ERR_PTR(-ENODEV); + } + + /* Assume that if there is no driver, that it doesn't + * exist, and we should use the genphy driver. */ + if (NULL == d->driver) { + int err; + down_write(&d->bus->subsys.rwsem); + d->driver = &genphy_driver.driver; + + err = d->driver->probe(d); + + if (err < 0) + return ERR_PTR(err); + + device_bind_driver(d); + up_write(&d->bus->subsys.rwsem); + } + + if (phydev->attached_dev) { + printk(KERN_ERR "%s: %s already attached\n", + dev->name, phy_id); + return ERR_PTR(-EBUSY); + } + + phydev->attached_dev = dev; + + phydev->dev_flags = flags; + + return phydev; +} +EXPORT_SYMBOL(phy_attach); + +void phy_detach(struct phy_device *phydev) +{ + phydev->attached_dev = NULL; + + /* If the device had no specific driver before (i.e. - it + * was using the generic driver), we unbind the device + * from the generic driver so that there's a chance a + * real driver could be loaded */ + if (phydev->dev.driver == &genphy_driver.driver) { + down_write(&phydev->dev.bus->subsys.rwsem); + device_release_driver(&phydev->dev); + up_write(&phydev->dev.bus->subsys.rwsem); + } +} +EXPORT_SYMBOL(phy_detach); + + +/* Generic PHY support and helper functions */ + +/* genphy_config_advert + * + * description: Writes MII_ADVERTISE with the appropriate values, + * after sanitizing the values to make sure we only advertise + * what is supported + */ +int genphy_config_advert(struct phy_device *phydev) +{ + u32 advertise; + int adv; + int err; + + /* Only allow advertising what + * this PHY supports */ + phydev->advertising &= phydev->supported; + advertise = phydev->advertising; + + /* Setup standard advertisement */ + adv = phy_read(phydev, MII_ADVERTISE); + + if (adv < 0) + return adv; + + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | + ADVERTISE_PAUSE_ASYM); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + if (advertise & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; + + err = phy_write(phydev, MII_ADVERTISE, adv); + + if (err < 0) + return err; + + /* Configure gigabit if it's supported */ + if (phydev->supported & (SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full)) { + adv = phy_read(phydev, MII_CTRL1000); + + if (adv < 0) + return adv; + + adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + if (advertise & SUPPORTED_1000baseT_Half) + adv |= ADVERTISE_1000HALF; + if (advertise & SUPPORTED_1000baseT_Full) + adv |= ADVERTISE_1000FULL; + err = phy_write(phydev, MII_CTRL1000, adv); + + if (err < 0) + return err; + } + + return adv; +} +EXPORT_SYMBOL(genphy_config_advert); + +/* genphy_setup_forced + * + * description: Configures MII_BMCR to force speed/duplex + * to the values in phydev. Assumes that the values are valid. + * Please see phy_sanitize_settings() */ +int genphy_setup_forced(struct phy_device *phydev) +{ + int ctl = BMCR_RESET; + + phydev->pause = phydev->asym_pause = 0; + + if (SPEED_1000 == phydev->speed) + ctl |= BMCR_SPEED1000; + else if (SPEED_100 == phydev->speed) + ctl |= BMCR_SPEED100; + + if (DUPLEX_FULL == phydev->duplex) + ctl |= BMCR_FULLDPLX; + + ctl = phy_write(phydev, MII_BMCR, ctl); + + if (ctl < 0) + return ctl; + + /* We just reset the device, so we'd better configure any + * settings the PHY requires to operate */ + if (phydev->drv->config_init) + ctl = phydev->drv->config_init(phydev); + + return ctl; +} + + +/* Enable and Restart Autonegotiation */ +int genphy_restart_aneg(struct phy_device *phydev) +{ + int ctl; + + ctl = phy_read(phydev, MII_BMCR); + + if (ctl < 0) + return ctl; + + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + + /* Don't isolate the PHY if we're negotiating */ + ctl &= ~(BMCR_ISOLATE); + + ctl = phy_write(phydev, MII_BMCR, ctl); + + return ctl; +} + + +/* genphy_config_aneg + * + * description: If auto-negotiation is enabled, we configure the + * advertising, and then restart auto-negotiation. If it is not + * enabled, then we write the BMCR + */ +int genphy_config_aneg(struct phy_device *phydev) +{ + int err = 0; + + if (AUTONEG_ENABLE == phydev->autoneg) { + err = genphy_config_advert(phydev); + + if (err < 0) + return err; + + err = genphy_restart_aneg(phydev); + } else + err = genphy_setup_forced(phydev); + + return err; +} +EXPORT_SYMBOL(genphy_config_aneg); + +/* genphy_update_link + * + * description: Update the value in phydev->link to reflect the + * current link value. In order to do this, we need to read + * the status register twice, keeping the second value + */ +int genphy_update_link(struct phy_device *phydev) +{ + int status; + + /* Do a fake read */ + status = phy_read(phydev, MII_BMSR); + + if (status < 0) + return status; + + /* Read link and autonegotiation status */ + status = phy_read(phydev, MII_BMSR); + + if (status < 0) + return status; + + if ((status & BMSR_LSTATUS) == 0) + phydev->link = 0; + else + phydev->link = 1; + + return 0; +} + +/* genphy_read_status + * + * description: Check the link, then figure out the current state + * by comparing what we advertise with what the link partner + * advertises. Start by checking the gigabit possibilities, + * then move on to 10/100. + */ +int genphy_read_status(struct phy_device *phydev) +{ + int adv; + int err; + int lpa; + int lpagb = 0; + + /* Update the link, but return if there + * was an error */ + err = genphy_update_link(phydev); + if (err) + return err; + + if (AUTONEG_ENABLE == phydev->autoneg) { + if (phydev->supported & (SUPPORTED_1000baseT_Half + | SUPPORTED_1000baseT_Full)) { + lpagb = phy_read(phydev, MII_STAT1000); + + if (lpagb < 0) + return lpagb; + + adv = phy_read(phydev, MII_CTRL1000); + + if (adv < 0) + return adv; + + lpagb &= adv << 2; + } + + lpa = phy_read(phydev, MII_LPA); + + if (lpa < 0) + return lpa; + + adv = phy_read(phydev, MII_ADVERTISE); + + if (adv < 0) + return adv; + + lpa &= adv; + + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + phydev->pause = phydev->asym_pause = 0; + + if (lpagb & (LPA_1000FULL | LPA_1000HALF)) { + phydev->speed = SPEED_1000; + + if (lpagb & LPA_1000FULL) + phydev->duplex = DUPLEX_FULL; + } else if (lpa & (LPA_100FULL | LPA_100HALF)) { + phydev->speed = SPEED_100; + + if (lpa & LPA_100FULL) + phydev->duplex = DUPLEX_FULL; + } else + if (lpa & LPA_10FULL) + phydev->duplex = DUPLEX_FULL; + + if (phydev->duplex == DUPLEX_FULL){ + phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; + phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; + } + } else { + int bmcr = phy_read(phydev, MII_BMCR); + if (bmcr < 0) + return bmcr; + + if (bmcr & BMCR_FULLDPLX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + if (bmcr & BMCR_SPEED1000) + phydev->speed = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + phydev->speed = SPEED_100; + else + phydev->speed = SPEED_10; + + phydev->pause = phydev->asym_pause = 0; + } + + return 0; +} +EXPORT_SYMBOL(genphy_read_status); + +static int genphy_config_init(struct phy_device *phydev) +{ + u32 val; + u32 features; + + /* For now, I'll claim that the generic driver supports + * all possible port types */ + features = (SUPPORTED_TP | SUPPORTED_MII + | SUPPORTED_AUI | SUPPORTED_FIBRE | + SUPPORTED_BNC); + + /* Do we support autonegotiation? */ + val = phy_read(phydev, MII_BMSR); + + if (val < 0) + return val; + + if (val & BMSR_ANEGCAPABLE) + features |= SUPPORTED_Autoneg; + + if (val & BMSR_100FULL) + features |= SUPPORTED_100baseT_Full; + if (val & BMSR_100HALF) + features |= SUPPORTED_100baseT_Half; + if (val & BMSR_10FULL) + features |= SUPPORTED_10baseT_Full; + if (val & BMSR_10HALF) + features |= SUPPORTED_10baseT_Half; + + if (val & BMSR_ESTATEN) { + val = phy_read(phydev, MII_ESTATUS); + + if (val < 0) + return val; + + if (val & ESTATUS_1000_TFULL) + features |= SUPPORTED_1000baseT_Full; + if (val & ESTATUS_1000_THALF) + features |= SUPPORTED_1000baseT_Half; + } + + phydev->supported = features; + phydev->advertising = features; + + return 0; +} + + +/* phy_probe + * + * description: Take care of setting up the phy_device structure, + * set the state to READY (the driver's init function should + * set it to STARTING if needed). + */ +static int phy_probe(struct device *dev) +{ + struct phy_device *phydev; + struct phy_driver *phydrv; + struct device_driver *drv; + int err = 0; + + phydev = to_phy_device(dev); + + /* Make sure the driver is held. + * XXX -- Is this correct? */ + drv = get_driver(phydev->dev.driver); + phydrv = to_phy_driver(drv); + phydev->drv = phydrv; + + /* Disable the interrupt if the PHY doesn't support it */ + if (!(phydrv->flags & PHY_HAS_INTERRUPT)) + phydev->irq = PHY_POLL; + + spin_lock(&phydev->lock); + + /* Start out supporting everything. Eventually, + * a controller will attach, and may modify one + * or both of these values */ + phydev->supported = phydrv->features; + phydev->advertising = phydrv->features; + + /* Set the state to READY by default */ + phydev->state = PHY_READY; + + if (phydev->drv->probe) + err = phydev->drv->probe(phydev); + + spin_unlock(&phydev->lock); + + if (err < 0) + return err; + + if (phydev->drv->config_init) + err = phydev->drv->config_init(phydev); + + return err; +} + +static int phy_remove(struct device *dev) +{ + struct phy_device *phydev; + + phydev = to_phy_device(dev); + + spin_lock(&phydev->lock); + phydev->state = PHY_DOWN; + spin_unlock(&phydev->lock); + + if (phydev->drv->remove) + phydev->drv->remove(phydev); + + put_driver(dev->driver); + phydev->drv = NULL; + + return 0; +} + +int phy_driver_register(struct phy_driver *new_driver) +{ + int retval; + + memset(&new_driver->driver, 0, sizeof(new_driver->driver)); + new_driver->driver.name = new_driver->name; + new_driver->driver.bus = &mdio_bus_type; + new_driver->driver.probe = phy_probe; + new_driver->driver.remove = phy_remove; + + retval = driver_register(&new_driver->driver); + + if (retval) { + printk(KERN_ERR "%s: Error %d in registering driver\n", + new_driver->name, retval); + + return retval; + } + + pr_info("%s: Registered new driver\n", new_driver->name); + + return 0; +} +EXPORT_SYMBOL(phy_driver_register); + +void phy_driver_unregister(struct phy_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL(phy_driver_unregister); + +static struct phy_driver genphy_driver = { + .phy_id = 0xffffffff, + .phy_id_mask = 0xffffffff, + .name = "Generic PHY", + .config_init = genphy_config_init, + .features = 0, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .driver = {.owner= THIS_MODULE, }, +}; + +static int __init phy_init(void) +{ + int rc; + + rc = mdio_bus_init(); + if (rc) + return rc; + + rc = phy_driver_register(&genphy_driver); + if (rc) + mdio_bus_exit(); + + return rc; +} + +static void __exit phy_exit(void) +{ + phy_driver_unregister(&genphy_driver); + mdio_bus_exit(); +} + +subsys_initcall(phy_init); +module_exit(phy_exit); diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c new file mode 100644 index 00000000000..d461ba45763 --- /dev/null +++ b/drivers/net/phy/qsemi.c @@ -0,0 +1,143 @@ +/* + * drivers/net/phy/qsemi.c + * + * Driver for Quality Semiconductor PHYs + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +/* ------------------------------------------------------------------------- */ +/* The Quality Semiconductor QS6612 is used on the RPX CLLF */ + +/* register definitions */ + +#define MII_QS6612_MCR 17 /* Mode Control Register */ +#define MII_QS6612_FTR 27 /* Factory Test Register */ +#define MII_QS6612_MCO 28 /* Misc. Control Register */ +#define MII_QS6612_ISR 29 /* Interrupt Source Register */ +#define MII_QS6612_IMR 30 /* Interrupt Mask Register */ +#define MII_QS6612_IMR_INIT 0x003a +#define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */ + +#define QS6612_PCR_AN_COMPLETE 0x1000 +#define QS6612_PCR_RLBEN 0x0200 +#define QS6612_PCR_DCREN 0x0100 +#define QS6612_PCR_4B5BEN 0x0040 +#define QS6612_PCR_TX_ISOLATE 0x0020 +#define QS6612_PCR_MLT3_DIS 0x0002 +#define QS6612_PCR_SCRM_DESCRM 0x0001 + +MODULE_DESCRIPTION("Quality Semiconductor PHY driver"); +MODULE_AUTHOR("Andy Fleming"); +MODULE_LICENSE("GPL"); + +/* Returns 0, unless there's a write error */ +static int qs6612_config_init(struct phy_device *phydev) +{ + /* The PHY powers up isolated on the RPX, + * so send a command to allow operation. + * XXX - My docs indicate this should be 0x0940 + * ...or something. The current value sets three + * reserved bits, bit 11, which specifies it should be + * set to one, bit 10, which specifies it should be set + * to 0, and bit 7, which doesn't specify. However, my + * docs are preliminary, and I will leave it like this + * until someone more knowledgable corrects me or it. + * -- Andy Fleming + */ + return phy_write(phydev, MII_QS6612_PCR, 0x0dc0); +} + +static int qs6612_ack_interrupt(struct phy_device *phydev) +{ + int err; + + err = phy_read(phydev, MII_QS6612_ISR); + + if (err < 0) + return err; + + err = phy_read(phydev, MII_BMSR); + + if (err < 0) + return err; + + err = phy_read(phydev, MII_EXPANSION); + + if (err < 0) + return err; + + return 0; +} + +static int qs6612_config_intr(struct phy_device *phydev) +{ + int err; + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, MII_QS6612_IMR, + MII_QS6612_IMR_INIT); + else + err = phy_write(phydev, MII_QS6612_IMR, 0); + + return err; + +} + +static struct phy_driver qs6612_driver = { + .phy_id = 0x00181440, + .name = "QS6612", + .phy_id_mask = 0xfffffff0, + .features = PHY_BASIC_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_init = qs6612_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = qs6612_ack_interrupt, + .config_intr = qs6612_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init qs6612_init(void) +{ + return phy_driver_register(&qs6612_driver); +} + +static void __exit qs6612_exit(void) +{ + phy_driver_unregister(&qs6612_driver); +} + +module_init(qs6612_init); +module_exit(qs6612_exit); diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index d5afe05cd82..f0471d102e3 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -187,6 +187,7 @@ static struct pci_device_id rtl8169_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), }, { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), }, { PCI_DEVICE(0x16ec, 0x0116), }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024, }, {0,}, }; diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index 7092ca6b277..2234a8f05eb 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -62,6 +62,7 @@ typedef struct _XENA_dev_config { #define ADAPTER_STATUS_RMAC_REMOTE_FAULT BIT(6) #define ADAPTER_STATUS_RMAC_LOCAL_FAULT BIT(7) #define ADAPTER_STATUS_RMAC_PCC_IDLE vBIT(0xFF,8,8) +#define ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE vBIT(0x0F,8,8) #define ADAPTER_STATUS_RC_PRC_QUIESCENT vBIT(0xFF,16,8) #define ADAPTER_STATUS_MC_DRAM_READY BIT(24) #define ADAPTER_STATUS_MC_QUEUES_READY BIT(25) @@ -77,21 +78,34 @@ typedef struct _XENA_dev_config { #define ADAPTER_ECC_EN BIT(55) u64 serr_source; -#define SERR_SOURCE_PIC BIT(0) -#define SERR_SOURCE_TXDMA BIT(1) -#define SERR_SOURCE_RXDMA BIT(2) +#define SERR_SOURCE_PIC BIT(0) +#define SERR_SOURCE_TXDMA BIT(1) +#define SERR_SOURCE_RXDMA BIT(2) #define SERR_SOURCE_MAC BIT(3) #define SERR_SOURCE_MC BIT(4) #define SERR_SOURCE_XGXS BIT(5) -#define SERR_SOURCE_ANY (SERR_SOURCE_PIC | \ - SERR_SOURCE_TXDMA | \ - SERR_SOURCE_RXDMA | \ - SERR_SOURCE_MAC | \ - SERR_SOURCE_MC | \ - SERR_SOURCE_XGXS) - - - u8 unused_0[0x800 - 0x120]; +#define SERR_SOURCE_ANY (SERR_SOURCE_PIC | \ + SERR_SOURCE_TXDMA | \ + SERR_SOURCE_RXDMA | \ + SERR_SOURCE_MAC | \ + SERR_SOURCE_MC | \ + SERR_SOURCE_XGXS) + + u64 pci_mode; +#define GET_PCI_MODE(val) ((val & vBIT(0xF, 0, 4)) >> 60) +#define PCI_MODE_PCI_33 0 +#define PCI_MODE_PCI_66 0x1 +#define PCI_MODE_PCIX_M1_66 0x2 +#define PCI_MODE_PCIX_M1_100 0x3 +#define PCI_MODE_PCIX_M1_133 0x4 +#define PCI_MODE_PCIX_M2_66 0x5 +#define PCI_MODE_PCIX_M2_100 0x6 +#define PCI_MODE_PCIX_M2_133 0x7 +#define PCI_MODE_UNSUPPORTED BIT(0) +#define PCI_MODE_32_BITS BIT(8) +#define PCI_MODE_UNKNOWN_MODE BIT(9) + + u8 unused_0[0x800 - 0x128]; /* PCI-X Controller registers */ u64 pic_int_status; @@ -153,7 +167,11 @@ typedef struct _XENA_dev_config { u8 unused4[0x08]; u64 gpio_int_reg; +#define GPIO_INT_REG_LINK_DOWN BIT(1) +#define GPIO_INT_REG_LINK_UP BIT(2) u64 gpio_int_mask; +#define GPIO_INT_MASK_LINK_DOWN BIT(1) +#define GPIO_INT_MASK_LINK_UP BIT(2) u64 gpio_alarms; u8 unused5[0x38]; @@ -223,19 +241,16 @@ typedef struct _XENA_dev_config { u64 xmsi_data; u64 rx_mat; +#define RX_MAT_SET(ring, msi) vBIT(msi, (8 * ring), 8) u8 unused6[0x8]; - u64 tx_mat0_7; - u64 tx_mat8_15; - u64 tx_mat16_23; - u64 tx_mat24_31; - u64 tx_mat32_39; - u64 tx_mat40_47; - u64 tx_mat48_55; - u64 tx_mat56_63; + u64 tx_mat0_n[0x8]; +#define TX_MAT_SET(fifo, msi) vBIT(msi, (8 * fifo), 8) - u8 unused_1[0x10]; + u8 unused_1[0x8]; + u64 stat_byte_cnt; +#define STAT_BC(n) vBIT(n,4,12) /* Automated statistics collection */ u64 stat_cfg; @@ -246,6 +261,7 @@ typedef struct _XENA_dev_config { #define STAT_TRSF_PER(n) TBD #define PER_SEC 0x208d5 #define SET_UPDT_PERIOD(n) vBIT((PER_SEC*n),32,32) +#define SET_UPDT_CLICKS(val) vBIT(val, 32, 32) u64 stat_addr; @@ -267,8 +283,15 @@ typedef struct _XENA_dev_config { u64 gpio_control; #define GPIO_CTRL_GPIO_0 BIT(8) + u64 misc_control; +#define MISC_LINK_STABILITY_PRD(val) vBIT(val,29,3) + + u8 unused7_1[0x240 - 0x208]; + + u64 wreq_split_mask; +#define WREQ_SPLIT_MASK_SET_MASK(val) vBIT(val, 52, 12) - u8 unused7[0x600]; + u8 unused7_2[0x800 - 0x248]; /* TxDMA registers */ u64 txdma_int_status; @@ -290,6 +313,7 @@ typedef struct _XENA_dev_config { u64 pcc_err_reg; #define PCC_FB_ECC_DB_ERR vBIT(0xFF, 16, 8) +#define PCC_ENABLE_FOUR vBIT(0x0F,0,8) u64 pcc_err_mask; u64 pcc_err_alarm; @@ -468,6 +492,7 @@ typedef struct _XENA_dev_config { #define PRC_CTRL_NO_SNOOP (BIT(22)|BIT(23)) #define PRC_CTRL_NO_SNOOP_DESC BIT(22) #define PRC_CTRL_NO_SNOOP_BUFF BIT(23) +#define PRC_CTRL_BIMODAL_INTERRUPT BIT(37) #define PRC_CTRL_RXD_BACKOFF_INTERVAL(val) vBIT(val,40,24) u64 prc_alarm_action; @@ -691,6 +716,10 @@ typedef struct _XENA_dev_config { #define MC_ERR_REG_MIRI_CRI_ERR_0 BIT(22) #define MC_ERR_REG_MIRI_CRI_ERR_1 BIT(23) #define MC_ERR_REG_SM_ERR BIT(31) +#define MC_ERR_REG_ECC_ALL_SNG (BIT(6) | \ + BIT(7) | BIT(17) | BIT(19)) +#define MC_ERR_REG_ECC_ALL_DBL (BIT(14) | \ + BIT(15) | BIT(18) | BIT(20)) u64 mc_err_mask; u64 mc_err_alarm; @@ -736,7 +765,19 @@ typedef struct _XENA_dev_config { u64 mc_rldram_test_d1; u8 unused24[0x300 - 0x288]; u64 mc_rldram_test_d2; - u8 unused25[0x700 - 0x308]; + + u8 unused24_1[0x360 - 0x308]; + u64 mc_rldram_ctrl; +#define MC_RLDRAM_ENABLE_ODT BIT(7) + + u8 unused24_2[0x640 - 0x368]; + u64 mc_rldram_ref_per_herc; +#define MC_RLDRAM_SET_REF_PERIOD(val) vBIT(val, 0, 16) + + u8 unused24_3[0x660 - 0x648]; + u64 mc_rldram_mrs_herc; + + u8 unused25[0x700 - 0x668]; u64 mc_debug_ctrl; u8 unused26[0x3000 - 0x2f08]; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index ea638b162d3..7ca78228b10 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -11,29 +11,28 @@ * See the file COPYING in this distribution for more information. * * Credits: - * Jeff Garzik : For pointing out the improper error condition - * check in the s2io_xmit routine and also some - * issues in the Tx watch dog function. Also for - * patiently answering all those innumerable + * Jeff Garzik : For pointing out the improper error condition + * check in the s2io_xmit routine and also some + * issues in the Tx watch dog function. Also for + * patiently answering all those innumerable * questions regaring the 2.6 porting issues. * Stephen Hemminger : Providing proper 2.6 porting mechanism for some * macros available only in 2.6 Kernel. - * Francois Romieu : For pointing out all code part that were + * Francois Romieu : For pointing out all code part that were * deprecated and also styling related comments. - * Grant Grundler : For helping me get rid of some Architecture + * Grant Grundler : For helping me get rid of some Architecture * dependent code. * Christopher Hellwig : Some more 2.6 specific issues in the driver. - * + * * The module loadable parameters that are supported by the driver and a brief * explaination of all the variables. - * rx_ring_num : This can be used to program the number of receive rings used - * in the driver. - * rx_ring_len: This defines the number of descriptors each ring can have. This + * rx_ring_num : This can be used to program the number of receive rings used + * in the driver. + * rx_ring_len: This defines the number of descriptors each ring can have. This * is also an array of size 8. * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver. - * tx_fifo_len: This too is an array of 8. Each element defines the number of + * tx_fifo_len: This too is an array of 8. Each element defines the number of * Tx descriptors that can be associated with each corresponding FIFO. - * in PCI Configuration space. ************************************************************************/ #include <linux/config.h> @@ -56,27 +55,39 @@ #include <linux/ethtool.h> #include <linux/version.h> #include <linux/workqueue.h> +#include <linux/if_vlan.h> -#include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h> +#include <asm/io.h> /* local include */ #include "s2io.h" #include "s2io-regs.h" /* S2io Driver name & version. */ -static char s2io_driver_name[] = "s2io"; -static char s2io_driver_version[] = "Version 1.7.7.1"; +static char s2io_driver_name[] = "Neterion"; +static char s2io_driver_version[] = "Version 2.0.3.1"; + +static inline int RXD_IS_UP2DT(RxD_t *rxdp) +{ + int ret; + + ret = ((!(rxdp->Control_1 & RXD_OWN_XENA)) && + (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK)); -/* + return ret; +} + +/* * Cards with following subsystem_id have a link state indication * problem, 600B, 600C, 600D, 640B, 640C and 640D. * macro below identifies these cards given the subsystem_id. */ -#define CARDS_WITH_FAULTY_LINK_INDICATORS(subid) \ - (((subid >= 0x600B) && (subid <= 0x600D)) || \ - ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0 +#define CARDS_WITH_FAULTY_LINK_INDICATORS(dev_type, subid) \ + (dev_type == XFRAME_I_DEVICE) ? \ + ((((subid >= 0x600B) && (subid <= 0x600D)) || \ + ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0) : 0 #define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \ ADAPTER_STATUS_RMAC_LOCAL_FAULT))) @@ -86,9 +97,12 @@ static char s2io_driver_version[] = "Version 1.7.7.1"; static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring) { int level = 0; - if ((sp->pkt_cnt[ring] - rxb_size) > 16) { + mac_info_t *mac_control; + + mac_control = &sp->mac_control; + if ((mac_control->rings[ring].pkt_cnt - rxb_size) > 16) { level = LOW; - if ((sp->pkt_cnt[ring] - rxb_size) < MAX_RXDS_PER_BLOCK) { + if (rxb_size <= MAX_RXDS_PER_BLOCK) { level = PANIC; } } @@ -145,6 +159,9 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { {"rmac_pause_cnt"}, {"rmac_accepted_ip"}, {"rmac_err_tcp"}, + {"\n DRIVER STATISTICS"}, + {"single_bit_ecc_errs"}, + {"double_bit_ecc_errs"}, }; #define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN @@ -153,8 +170,37 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { #define S2IO_TEST_LEN sizeof(s2io_gstrings) / ETH_GSTRING_LEN #define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN +#define S2IO_TIMER_CONF(timer, handle, arg, exp) \ + init_timer(&timer); \ + timer.function = handle; \ + timer.data = (unsigned long) arg; \ + mod_timer(&timer, (jiffies + exp)) \ + +/* Add the vlan */ +static void s2io_vlan_rx_register(struct net_device *dev, + struct vlan_group *grp) +{ + nic_t *nic = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&nic->tx_lock, flags); + nic->vlgrp = grp; + spin_unlock_irqrestore(&nic->tx_lock, flags); +} + +/* Unregister the vlan */ +static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) +{ + nic_t *nic = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&nic->tx_lock, flags); + if (nic->vlgrp) + nic->vlgrp->vlan_devices[vid] = NULL; + spin_unlock_irqrestore(&nic->tx_lock, flags); +} -/* +/* * Constants to be programmed into the Xena's registers, to configure * the XAUI. */ @@ -162,7 +208,28 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { #define SWITCH_SIGN 0xA5A5A5A5A5A5A5A5ULL #define END_SIGN 0x0 -static u64 default_mdio_cfg[] = { +static u64 herc_act_dtx_cfg[] = { + /* Set address */ + 0x8000051536750000ULL, 0x80000515367500E0ULL, + /* Write data */ + 0x8000051536750004ULL, 0x80000515367500E4ULL, + /* Set address */ + 0x80010515003F0000ULL, 0x80010515003F00E0ULL, + /* Write data */ + 0x80010515003F0004ULL, 0x80010515003F00E4ULL, + /* Set address */ + 0x801205150D440000ULL, 0x801205150D4400E0ULL, + /* Write data */ + 0x801205150D440004ULL, 0x801205150D4400E4ULL, + /* Set address */ + 0x80020515F2100000ULL, 0x80020515F21000E0ULL, + /* Write data */ + 0x80020515F2100004ULL, 0x80020515F21000E4ULL, + /* Done */ + END_SIGN +}; + +static u64 xena_mdio_cfg[] = { /* Reset PMA PLL */ 0xC001010000000000ULL, 0xC0010100000000E0ULL, 0xC0010100008000E4ULL, @@ -172,7 +239,7 @@ static u64 default_mdio_cfg[] = { END_SIGN }; -static u64 default_dtx_cfg[] = { +static u64 xena_dtx_cfg[] = { 0x8000051500000000ULL, 0x80000515000000E0ULL, 0x80000515D93500E4ULL, 0x8001051500000000ULL, 0x80010515000000E0ULL, 0x80010515001E00E4ULL, @@ -196,8 +263,7 @@ static u64 default_dtx_cfg[] = { END_SIGN }; - -/* +/* * Constants for Fixing the MacAddress problem seen mostly on * Alpha machines. */ @@ -226,20 +292,25 @@ static unsigned int tx_fifo_len[MAX_TX_FIFOS] = static unsigned int rx_ring_num = 1; static unsigned int rx_ring_sz[MAX_RX_RINGS] = {[0 ...(MAX_RX_RINGS - 1)] = 0 }; -static unsigned int Stats_refresh_time = 4; +static unsigned int rts_frm_len[MAX_RX_RINGS] = + {[0 ...(MAX_RX_RINGS - 1)] = 0 }; +static unsigned int use_continuous_tx_intrs = 1; static unsigned int rmac_pause_time = 65535; static unsigned int mc_pause_threshold_q0q3 = 187; static unsigned int mc_pause_threshold_q4q7 = 187; static unsigned int shared_splits; static unsigned int tmac_util_period = 5; static unsigned int rmac_util_period = 5; +static unsigned int bimodal = 0; #ifndef CONFIG_S2IO_NAPI static unsigned int indicate_max_pkts; #endif +/* Frequency of Rx desc syncs expressed as power of 2 */ +static unsigned int rxsync_frequency = 3; -/* +/* * S2IO device table. - * This table lists all the devices that this driver supports. + * This table lists all the devices that this driver supports. */ static struct pci_device_id s2io_tbl[] __devinitdata = { {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN, @@ -247,9 +318,9 @@ static struct pci_device_id s2io_tbl[] __devinitdata = { {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI, PCI_ANY_ID, PCI_ANY_ID}, {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN, - PCI_ANY_ID, PCI_ANY_ID}, - {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI, - PCI_ANY_ID, PCI_ANY_ID}, + PCI_ANY_ID, PCI_ANY_ID}, + {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI, + PCI_ANY_ID, PCI_ANY_ID}, {0,} }; @@ -268,8 +339,8 @@ static struct pci_driver s2io_driver = { /** * init_shared_mem - Allocation and Initialization of Memory * @nic: Device private variable. - * Description: The function allocates all the memory areas shared - * between the NIC and the driver. This includes Tx descriptors, + * Description: The function allocates all the memory areas shared + * between the NIC and the driver. This includes Tx descriptors, * Rx descriptors and the statistics block. */ @@ -279,11 +350,11 @@ static int init_shared_mem(struct s2io_nic *nic) void *tmp_v_addr, *tmp_v_addr_next; dma_addr_t tmp_p_addr, tmp_p_addr_next; RxD_block_t *pre_rxd_blk = NULL; - int i, j, blk_cnt; + int i, j, blk_cnt, rx_sz, tx_sz; int lst_size, lst_per_page; struct net_device *dev = nic->dev; #ifdef CONFIG_2BUFF_MODE - unsigned long tmp; + u64 tmp; buffAdd_t *ba; #endif @@ -300,36 +371,41 @@ static int init_shared_mem(struct s2io_nic *nic) size += config->tx_cfg[i].fifo_len; } if (size > MAX_AVAILABLE_TXDS) { - DBG_PRINT(ERR_DBG, "%s: Total number of Tx FIFOs ", - dev->name); - DBG_PRINT(ERR_DBG, "exceeds the maximum value "); - DBG_PRINT(ERR_DBG, "that can be used\n"); + DBG_PRINT(ERR_DBG, "%s: Requested TxDs too high, ", + __FUNCTION__); + DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size); return FAILURE; } lst_size = (sizeof(TxD_t) * config->max_txds); + tx_sz = lst_size * size; lst_per_page = PAGE_SIZE / lst_size; for (i = 0; i < config->tx_fifo_num; i++) { int fifo_len = config->tx_cfg[i].fifo_len; int list_holder_size = fifo_len * sizeof(list_info_hold_t); - nic->list_info[i] = kmalloc(list_holder_size, GFP_KERNEL); - if (!nic->list_info[i]) { + mac_control->fifos[i].list_info = kmalloc(list_holder_size, + GFP_KERNEL); + if (!mac_control->fifos[i].list_info) { DBG_PRINT(ERR_DBG, "Malloc failed for list_info\n"); return -ENOMEM; } - memset(nic->list_info[i], 0, list_holder_size); + memset(mac_control->fifos[i].list_info, 0, list_holder_size); } for (i = 0; i < config->tx_fifo_num; i++) { int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len, lst_per_page); - mac_control->tx_curr_put_info[i].offset = 0; - mac_control->tx_curr_put_info[i].fifo_len = + mac_control->fifos[i].tx_curr_put_info.offset = 0; + mac_control->fifos[i].tx_curr_put_info.fifo_len = config->tx_cfg[i].fifo_len - 1; - mac_control->tx_curr_get_info[i].offset = 0; - mac_control->tx_curr_get_info[i].fifo_len = + mac_control->fifos[i].tx_curr_get_info.offset = 0; + mac_control->fifos[i].tx_curr_get_info.fifo_len = config->tx_cfg[i].fifo_len - 1; + mac_control->fifos[i].fifo_no = i; + mac_control->fifos[i].nic = nic; + mac_control->fifos[i].max_txds = MAX_SKB_FRAGS; + for (j = 0; j < page_num; j++) { int k = 0; dma_addr_t tmp_p; @@ -345,16 +421,15 @@ static int init_shared_mem(struct s2io_nic *nic) while (k < lst_per_page) { int l = (j * lst_per_page) + k; if (l == config->tx_cfg[i].fifo_len) - goto end_txd_alloc; - nic->list_info[i][l].list_virt_addr = + break; + mac_control->fifos[i].list_info[l].list_virt_addr = tmp_v + (k * lst_size); - nic->list_info[i][l].list_phy_addr = + mac_control->fifos[i].list_info[l].list_phy_addr = tmp_p + (k * lst_size); k++; } } } - end_txd_alloc: /* Allocation and initialization of RXDs in Rings */ size = 0; @@ -367,21 +442,26 @@ static int init_shared_mem(struct s2io_nic *nic) return FAILURE; } size += config->rx_cfg[i].num_rxd; - nic->block_count[i] = + mac_control->rings[i].block_count = config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1); - nic->pkt_cnt[i] = - config->rx_cfg[i].num_rxd - nic->block_count[i]; + mac_control->rings[i].pkt_cnt = + config->rx_cfg[i].num_rxd - mac_control->rings[i].block_count; } + size = (size * (sizeof(RxD_t))); + rx_sz = size; for (i = 0; i < config->rx_ring_num; i++) { - mac_control->rx_curr_get_info[i].block_index = 0; - mac_control->rx_curr_get_info[i].offset = 0; - mac_control->rx_curr_get_info[i].ring_len = + mac_control->rings[i].rx_curr_get_info.block_index = 0; + mac_control->rings[i].rx_curr_get_info.offset = 0; + mac_control->rings[i].rx_curr_get_info.ring_len = config->rx_cfg[i].num_rxd - 1; - mac_control->rx_curr_put_info[i].block_index = 0; - mac_control->rx_curr_put_info[i].offset = 0; - mac_control->rx_curr_put_info[i].ring_len = + mac_control->rings[i].rx_curr_put_info.block_index = 0; + mac_control->rings[i].rx_curr_put_info.offset = 0; + mac_control->rings[i].rx_curr_put_info.ring_len = config->rx_cfg[i].num_rxd - 1; + mac_control->rings[i].nic = nic; + mac_control->rings[i].ring_no = i; + blk_cnt = config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1); /* Allocating all the Rx blocks */ @@ -395,32 +475,36 @@ static int init_shared_mem(struct s2io_nic *nic) &tmp_p_addr); if (tmp_v_addr == NULL) { /* - * In case of failure, free_shared_mem() - * is called, which should free any - * memory that was alloced till the + * In case of failure, free_shared_mem() + * is called, which should free any + * memory that was alloced till the * failure happened. */ - nic->rx_blocks[i][j].block_virt_addr = + mac_control->rings[i].rx_blocks[j].block_virt_addr = tmp_v_addr; return -ENOMEM; } memset(tmp_v_addr, 0, size); - nic->rx_blocks[i][j].block_virt_addr = tmp_v_addr; - nic->rx_blocks[i][j].block_dma_addr = tmp_p_addr; + mac_control->rings[i].rx_blocks[j].block_virt_addr = + tmp_v_addr; + mac_control->rings[i].rx_blocks[j].block_dma_addr = + tmp_p_addr; } /* Interlinking all Rx Blocks */ for (j = 0; j < blk_cnt; j++) { - tmp_v_addr = nic->rx_blocks[i][j].block_virt_addr; + tmp_v_addr = + mac_control->rings[i].rx_blocks[j].block_virt_addr; tmp_v_addr_next = - nic->rx_blocks[i][(j + 1) % + mac_control->rings[i].rx_blocks[(j + 1) % blk_cnt].block_virt_addr; - tmp_p_addr = nic->rx_blocks[i][j].block_dma_addr; + tmp_p_addr = + mac_control->rings[i].rx_blocks[j].block_dma_addr; tmp_p_addr_next = - nic->rx_blocks[i][(j + 1) % + mac_control->rings[i].rx_blocks[(j + 1) % blk_cnt].block_dma_addr; pre_rxd_blk = (RxD_block_t *) tmp_v_addr; - pre_rxd_blk->reserved_1 = END_OF_BLOCK; /* last RxD + pre_rxd_blk->reserved_1 = END_OF_BLOCK; /* last RxD * marker. */ #ifndef CONFIG_2BUFF_MODE @@ -433,43 +517,43 @@ static int init_shared_mem(struct s2io_nic *nic) } #ifdef CONFIG_2BUFF_MODE - /* + /* * Allocation of Storages for buffer addresses in 2BUFF mode * and the buffers as well. */ for (i = 0; i < config->rx_ring_num; i++) { blk_cnt = config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1); - nic->ba[i] = kmalloc((sizeof(buffAdd_t *) * blk_cnt), + mac_control->rings[i].ba = kmalloc((sizeof(buffAdd_t *) * blk_cnt), GFP_KERNEL); - if (!nic->ba[i]) + if (!mac_control->rings[i].ba) return -ENOMEM; for (j = 0; j < blk_cnt; j++) { int k = 0; - nic->ba[i][j] = kmalloc((sizeof(buffAdd_t) * + mac_control->rings[i].ba[j] = kmalloc((sizeof(buffAdd_t) * (MAX_RXDS_PER_BLOCK + 1)), GFP_KERNEL); - if (!nic->ba[i][j]) + if (!mac_control->rings[i].ba[j]) return -ENOMEM; while (k != MAX_RXDS_PER_BLOCK) { - ba = &nic->ba[i][j][k]; + ba = &mac_control->rings[i].ba[j][k]; - ba->ba_0_org = kmalloc + ba->ba_0_org = (void *) kmalloc (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL); if (!ba->ba_0_org) return -ENOMEM; - tmp = (unsigned long) ba->ba_0_org; + tmp = (u64) ba->ba_0_org; tmp += ALIGN_SIZE; - tmp &= ~((unsigned long) ALIGN_SIZE); + tmp &= ~((u64) ALIGN_SIZE); ba->ba_0 = (void *) tmp; - ba->ba_1_org = kmalloc + ba->ba_1_org = (void *) kmalloc (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL); if (!ba->ba_1_org) return -ENOMEM; - tmp = (unsigned long) ba->ba_1_org; + tmp = (u64) ba->ba_1_org; tmp += ALIGN_SIZE; - tmp &= ~((unsigned long) ALIGN_SIZE); + tmp &= ~((u64) ALIGN_SIZE); ba->ba_1 = (void *) tmp; k++; } @@ -483,9 +567,9 @@ static int init_shared_mem(struct s2io_nic *nic) (nic->pdev, size, &mac_control->stats_mem_phy); if (!mac_control->stats_mem) { - /* - * In case of failure, free_shared_mem() is called, which - * should free any memory that was alloced till the + /* + * In case of failure, free_shared_mem() is called, which + * should free any memory that was alloced till the * failure happened. */ return -ENOMEM; @@ -495,15 +579,14 @@ static int init_shared_mem(struct s2io_nic *nic) tmp_v_addr = mac_control->stats_mem; mac_control->stats_info = (StatInfo_t *) tmp_v_addr; memset(tmp_v_addr, 0, size); - DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name, (unsigned long long) tmp_p_addr); return SUCCESS; } -/** - * free_shared_mem - Free the allocated Memory +/** + * free_shared_mem - Free the allocated Memory * @nic: Device private variable. * Description: This function is to free all memory locations allocated by * the init_shared_mem() function and return it to the kernel. @@ -533,15 +616,19 @@ static void free_shared_mem(struct s2io_nic *nic) lst_per_page); for (j = 0; j < page_num; j++) { int mem_blks = (j * lst_per_page); - if (!nic->list_info[i][mem_blks].list_virt_addr) + if ((!mac_control->fifos[i].list_info) || + (!mac_control->fifos[i].list_info[mem_blks]. + list_virt_addr)) break; pci_free_consistent(nic->pdev, PAGE_SIZE, - nic->list_info[i][mem_blks]. + mac_control->fifos[i]. + list_info[mem_blks]. list_virt_addr, - nic->list_info[i][mem_blks]. + mac_control->fifos[i]. + list_info[mem_blks]. list_phy_addr); } - kfree(nic->list_info[i]); + kfree(mac_control->fifos[i].list_info); } #ifndef CONFIG_2BUFF_MODE @@ -550,10 +637,12 @@ static void free_shared_mem(struct s2io_nic *nic) size = SIZE_OF_BLOCK; #endif for (i = 0; i < config->rx_ring_num; i++) { - blk_cnt = nic->block_count[i]; + blk_cnt = mac_control->rings[i].block_count; for (j = 0; j < blk_cnt; j++) { - tmp_v_addr = nic->rx_blocks[i][j].block_virt_addr; - tmp_p_addr = nic->rx_blocks[i][j].block_dma_addr; + tmp_v_addr = mac_control->rings[i].rx_blocks[j]. + block_virt_addr; + tmp_p_addr = mac_control->rings[i].rx_blocks[j]. + block_dma_addr; if (tmp_v_addr == NULL) break; pci_free_consistent(nic->pdev, size, @@ -566,35 +655,21 @@ static void free_shared_mem(struct s2io_nic *nic) for (i = 0; i < config->rx_ring_num; i++) { blk_cnt = config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1); - if (!nic->ba[i]) - goto end_free; for (j = 0; j < blk_cnt; j++) { int k = 0; - if (!nic->ba[i][j]) { - kfree(nic->ba[i]); - goto end_free; - } + if (!mac_control->rings[i].ba[j]) + continue; while (k != MAX_RXDS_PER_BLOCK) { - buffAdd_t *ba = &nic->ba[i][j][k]; - if (!ba || !ba->ba_0_org || !ba->ba_1_org) - { - kfree(nic->ba[i]); - kfree(nic->ba[i][j]); - if(ba->ba_0_org) - kfree(ba->ba_0_org); - if(ba->ba_1_org) - kfree(ba->ba_1_org); - goto end_free; - } + buffAdd_t *ba = &mac_control->rings[i].ba[j][k]; kfree(ba->ba_0_org); kfree(ba->ba_1_org); k++; } - kfree(nic->ba[i][j]); + kfree(mac_control->rings[i].ba[j]); } - kfree(nic->ba[i]); + if (mac_control->rings[i].ba) + kfree(mac_control->rings[i].ba); } -end_free: #endif if (mac_control->stats_mem) { @@ -605,12 +680,93 @@ end_free: } } -/** - * init_nic - Initialization of hardware +/** + * s2io_verify_pci_mode - + */ + +static int s2io_verify_pci_mode(nic_t *nic) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + register u64 val64 = 0; + int mode; + + val64 = readq(&bar0->pci_mode); + mode = (u8)GET_PCI_MODE(val64); + + if ( val64 & PCI_MODE_UNKNOWN_MODE) + return -1; /* Unknown PCI mode */ + return mode; +} + + +/** + * s2io_print_pci_mode - + */ +static int s2io_print_pci_mode(nic_t *nic) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + register u64 val64 = 0; + int mode; + struct config_param *config = &nic->config; + + val64 = readq(&bar0->pci_mode); + mode = (u8)GET_PCI_MODE(val64); + + if ( val64 & PCI_MODE_UNKNOWN_MODE) + return -1; /* Unknown PCI mode */ + + if (val64 & PCI_MODE_32_BITS) { + DBG_PRINT(ERR_DBG, "%s: Device is on 32 bit ", nic->dev->name); + } else { + DBG_PRINT(ERR_DBG, "%s: Device is on 64 bit ", nic->dev->name); + } + + switch(mode) { + case PCI_MODE_PCI_33: + DBG_PRINT(ERR_DBG, "33MHz PCI bus\n"); + config->bus_speed = 33; + break; + case PCI_MODE_PCI_66: + DBG_PRINT(ERR_DBG, "66MHz PCI bus\n"); + config->bus_speed = 133; + break; + case PCI_MODE_PCIX_M1_66: + DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n"); + config->bus_speed = 133; /* Herc doubles the clock rate */ + break; + case PCI_MODE_PCIX_M1_100: + DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n"); + config->bus_speed = 200; + break; + case PCI_MODE_PCIX_M1_133: + DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n"); + config->bus_speed = 266; + break; + case PCI_MODE_PCIX_M2_66: + DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n"); + config->bus_speed = 133; + break; + case PCI_MODE_PCIX_M2_100: + DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n"); + config->bus_speed = 200; + break; + case PCI_MODE_PCIX_M2_133: + DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n"); + config->bus_speed = 266; + break; + default: + return -1; /* Unsupported bus speed */ + } + + return mode; +} + +/** + * init_nic - Initialization of hardware * @nic: device peivate variable - * Description: The function sequentially configures every block - * of the H/W from their reset values. - * Return Value: SUCCESS on success and + * Description: The function sequentially configures every block + * of the H/W from their reset values. + * Return Value: SUCCESS on success and * '-1' on failure (endian settings incorrect). */ @@ -626,21 +782,32 @@ static int init_nic(struct s2io_nic *nic) struct config_param *config; int mdio_cnt = 0, dtx_cnt = 0; unsigned long long mem_share; + int mem_size; mac_control = &nic->mac_control; config = &nic->config; - /* Initialize swapper control register */ - if (s2io_set_swapper(nic)) { + /* to set the swapper controle on the card */ + if(s2io_set_swapper(nic)) { DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n"); return -1; } + /* + * Herc requires EOI to be removed from reset before XGXS, so.. + */ + if (nic->device_type & XFRAME_II_DEVICE) { + val64 = 0xA500000000ULL; + writeq(val64, &bar0->sw_reset); + msleep(500); + val64 = readq(&bar0->sw_reset); + } + /* Remove XGXS from reset state */ val64 = 0; writeq(val64, &bar0->sw_reset); - val64 = readq(&bar0->sw_reset); msleep(500); + val64 = readq(&bar0->sw_reset); /* Enable Receiving broadcasts */ add = &bar0->mac_cfg; @@ -660,48 +827,58 @@ static int init_nic(struct s2io_nic *nic) val64 = dev->mtu; writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len); - /* - * Configuring the XAUI Interface of Xena. + /* + * Configuring the XAUI Interface of Xena. * *************************************** - * To Configure the Xena's XAUI, one has to write a series - * of 64 bit values into two registers in a particular - * sequence. Hence a macro 'SWITCH_SIGN' has been defined - * which will be defined in the array of configuration values - * (default_dtx_cfg & default_mdio_cfg) at appropriate places - * to switch writing from one regsiter to another. We continue + * To Configure the Xena's XAUI, one has to write a series + * of 64 bit values into two registers in a particular + * sequence. Hence a macro 'SWITCH_SIGN' has been defined + * which will be defined in the array of configuration values + * (xena_dtx_cfg & xena_mdio_cfg) at appropriate places + * to switch writing from one regsiter to another. We continue * writing these values until we encounter the 'END_SIGN' macro. - * For example, After making a series of 21 writes into - * dtx_control register the 'SWITCH_SIGN' appears and hence we + * For example, After making a series of 21 writes into + * dtx_control register the 'SWITCH_SIGN' appears and hence we * start writing into mdio_control until we encounter END_SIGN. */ - while (1) { - dtx_cfg: - while (default_dtx_cfg[dtx_cnt] != END_SIGN) { - if (default_dtx_cfg[dtx_cnt] == SWITCH_SIGN) { - dtx_cnt++; - goto mdio_cfg; - } - SPECIAL_REG_WRITE(default_dtx_cfg[dtx_cnt], + if (nic->device_type & XFRAME_II_DEVICE) { + while (herc_act_dtx_cfg[dtx_cnt] != END_SIGN) { + SPECIAL_REG_WRITE(herc_act_dtx_cfg[dtx_cnt], &bar0->dtx_control, UF); - val64 = readq(&bar0->dtx_control); + if (dtx_cnt & 0x1) + msleep(1); /* Necessary!! */ dtx_cnt++; } - mdio_cfg: - while (default_mdio_cfg[mdio_cnt] != END_SIGN) { - if (default_mdio_cfg[mdio_cnt] == SWITCH_SIGN) { + } else { + while (1) { + dtx_cfg: + while (xena_dtx_cfg[dtx_cnt] != END_SIGN) { + if (xena_dtx_cfg[dtx_cnt] == SWITCH_SIGN) { + dtx_cnt++; + goto mdio_cfg; + } + SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt], + &bar0->dtx_control, UF); + val64 = readq(&bar0->dtx_control); + dtx_cnt++; + } + mdio_cfg: + while (xena_mdio_cfg[mdio_cnt] != END_SIGN) { + if (xena_mdio_cfg[mdio_cnt] == SWITCH_SIGN) { + mdio_cnt++; + goto dtx_cfg; + } + SPECIAL_REG_WRITE(xena_mdio_cfg[mdio_cnt], + &bar0->mdio_control, UF); + val64 = readq(&bar0->mdio_control); mdio_cnt++; + } + if ((xena_dtx_cfg[dtx_cnt] == END_SIGN) && + (xena_mdio_cfg[mdio_cnt] == END_SIGN)) { + break; + } else { goto dtx_cfg; } - SPECIAL_REG_WRITE(default_mdio_cfg[mdio_cnt], - &bar0->mdio_control, UF); - val64 = readq(&bar0->mdio_control); - mdio_cnt++; - } - if ((default_dtx_cfg[dtx_cnt] == END_SIGN) && - (default_mdio_cfg[mdio_cnt] == END_SIGN)) { - break; - } else { - goto dtx_cfg; } } @@ -748,12 +925,20 @@ static int init_nic(struct s2io_nic *nic) val64 |= BIT(0); /* To enable the FIFO partition. */ writeq(val64, &bar0->tx_fifo_partition_0); + /* + * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug + * SXE-008 TRANSMIT DMA ARBITRATION ISSUE. + */ + if ((nic->device_type == XFRAME_I_DEVICE) && + (get_xena_rev_id(nic->pdev) < 4)) + writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable); + val64 = readq(&bar0->tx_fifo_partition_0); DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n", &bar0->tx_fifo_partition_0, (unsigned long long) val64); - /* - * Initialization of Tx_PA_CONFIG register to ignore packet + /* + * Initialization of Tx_PA_CONFIG register to ignore packet * integrity checking. */ val64 = readq(&bar0->tx_pa_cfg); @@ -770,85 +955,304 @@ static int init_nic(struct s2io_nic *nic) } writeq(val64, &bar0->rx_queue_priority); - /* - * Allocating equal share of memory to all the + /* + * Allocating equal share of memory to all the * configured Rings. */ val64 = 0; + if (nic->device_type & XFRAME_II_DEVICE) + mem_size = 32; + else + mem_size = 64; + for (i = 0; i < config->rx_ring_num; i++) { switch (i) { case 0: - mem_share = (64 / config->rx_ring_num + - 64 % config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num + + mem_size % config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q0_SZ(mem_share); continue; case 1: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q1_SZ(mem_share); continue; case 2: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q2_SZ(mem_share); continue; case 3: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q3_SZ(mem_share); continue; case 4: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q4_SZ(mem_share); continue; case 5: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q5_SZ(mem_share); continue; case 6: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q6_SZ(mem_share); continue; case 7: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q7_SZ(mem_share); continue; } } writeq(val64, &bar0->rx_queue_cfg); - /* - * Initializing the Tx round robin registers to 0. - * Filling Tx and Rx round robin registers as per the - * number of FIFOs and Rings is still TODO. - */ - writeq(0, &bar0->tx_w_round_robin_0); - writeq(0, &bar0->tx_w_round_robin_1); - writeq(0, &bar0->tx_w_round_robin_2); - writeq(0, &bar0->tx_w_round_robin_3); - writeq(0, &bar0->tx_w_round_robin_4); - - /* - * TODO - * Disable Rx steering. Hard coding all packets be steered to - * Queue 0 for now. + /* + * Filling Tx round robin registers + * as per the number of FIFOs */ - val64 = 0x8080808080808080ULL; - writeq(val64, &bar0->rts_qos_steering); + switch (config->tx_fifo_num) { + case 1: + val64 = 0x0000000000000000ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + writeq(val64, &bar0->tx_w_round_robin_1); + writeq(val64, &bar0->tx_w_round_robin_2); + writeq(val64, &bar0->tx_w_round_robin_3); + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 2: + val64 = 0x0000010000010000ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0100000100000100ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0001000001000001ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0000010000010000ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0100000000000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 3: + val64 = 0x0001000102000001ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0001020000010001ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0200000100010200ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0001000102000001ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0001020000000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 4: + val64 = 0x0001020300010200ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0100000102030001ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0200010000010203ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0001020001000001ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0203000100000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 5: + val64 = 0x0001000203000102ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0001020001030004ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0001000203000102ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0001020001030004ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0001000000000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 6: + val64 = 0x0001020304000102ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0304050001020001ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0203000100000102ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0304000102030405ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0001000200000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 7: + val64 = 0x0001020001020300ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0102030400010203ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0405060001020001ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0304050000010200ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0102030000000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 8: + val64 = 0x0001020300040105ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0200030106000204ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0103000502010007ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0304010002060500ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0103020400000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + } + + /* Filling the Rx round robin registers as per the + * number of Rings and steering based on QoS. + */ + switch (config->rx_ring_num) { + case 1: + val64 = 0x8080808080808080ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 2: + val64 = 0x0000010000010000ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0100000100000100ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0001000001000001ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0000010000010000ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0100000000000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8080808040404040ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 3: + val64 = 0x0001000102000001ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0001020000010001ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0200000100010200ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0001000102000001ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0001020000000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8080804040402020ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 4: + val64 = 0x0001020300010200ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0100000102030001ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0200010000010203ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0001020001000001ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0203000100000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8080404020201010ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 5: + val64 = 0x0001000203000102ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0001020001030004ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0001000203000102ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0001020001030004ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0001000000000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8080404020201008ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 6: + val64 = 0x0001020304000102ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0304050001020001ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0203000100000102ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0304000102030405ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0001000200000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8080404020100804ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 7: + val64 = 0x0001020001020300ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0102030400010203ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0405060001020001ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0304050000010200ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0102030000000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8080402010080402ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 8: + val64 = 0x0001020300040105ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0200030106000204ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0103000502010007ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0304010002060500ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0103020400000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8040201008040201ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + } /* UDP Fix */ val64 = 0; - for (i = 1; i < 8; i++) + for (i = 0; i < 8; i++) + writeq(val64, &bar0->rts_frm_len_n[i]); + + /* Set the default rts frame length for the rings configured */ + val64 = MAC_RTS_FRM_LEN_SET(dev->mtu+22); + for (i = 0 ; i < config->rx_ring_num ; i++) writeq(val64, &bar0->rts_frm_len_n[i]); - /* Set rts_frm_len register for fifo 0 */ - writeq(MAC_RTS_FRM_LEN_SET(dev->mtu + 22), - &bar0->rts_frm_len_n[0]); + /* Set the frame length for the configured rings + * desired by the user + */ + for (i = 0; i < config->rx_ring_num; i++) { + /* If rts_frm_len[i] == 0 then it is assumed that user not + * specified frame length steering. + * If the user provides the frame length then program + * the rts_frm_len register for those values or else + * leave it as it is. + */ + if (rts_frm_len[i] != 0) { + writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]), + &bar0->rts_frm_len_n[i]); + } + } - /* Enable statistics */ + /* Program statistics memory */ writeq(mac_control->stats_mem_phy, &bar0->stat_addr); - val64 = SET_UPDT_PERIOD(Stats_refresh_time) | - STAT_CFG_STAT_RO | STAT_CFG_STAT_EN; - writeq(val64, &bar0->stat_cfg); - /* + if (nic->device_type == XFRAME_II_DEVICE) { + val64 = STAT_BC(0x320); + writeq(val64, &bar0->stat_byte_cnt); + } + + /* * Initializing the sampling rate for the device to calculate the * bandwidth utilization. */ @@ -857,30 +1261,38 @@ static int init_nic(struct s2io_nic *nic) writeq(val64, &bar0->mac_link_util); - /* - * Initializing the Transmit and Receive Traffic Interrupt + /* + * Initializing the Transmit and Receive Traffic Interrupt * Scheme. */ - /* TTI Initialization. Default Tx timer gets us about + /* + * TTI Initialization. Default Tx timer gets us about * 250 interrupts per sec. Continuous interrupts are enabled * by default. */ - val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078) | - TTI_DATA1_MEM_TX_URNG_A(0xA) | + if (nic->device_type == XFRAME_II_DEVICE) { + int count = (nic->config.bus_speed * 125)/2; + val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count); + } else { + + val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078); + } + val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) | TTI_DATA1_MEM_TX_URNG_B(0x10) | - TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN | - TTI_DATA1_MEM_TX_TIMER_CI_EN; + TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN; + if (use_continuous_tx_intrs) + val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN; writeq(val64, &bar0->tti_data1_mem); val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) | TTI_DATA2_MEM_TX_UFC_B(0x20) | - TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80); + TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80); writeq(val64, &bar0->tti_data2_mem); val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD; writeq(val64, &bar0->tti_command_mem); - /* + /* * Once the operation completes, the Strobe bit of the command * register will be reset. We poll for this particular condition * We wait for a maximum of 500ms for the operation to complete, @@ -901,52 +1313,97 @@ static int init_nic(struct s2io_nic *nic) time++; } - /* RTI Initialization */ - val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF) | - RTI_DATA1_MEM_RX_URNG_A(0xA) | - RTI_DATA1_MEM_RX_URNG_B(0x10) | - RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN; + if (nic->config.bimodal) { + int k = 0; + for (k = 0; k < config->rx_ring_num; k++) { + val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD; + val64 |= TTI_CMD_MEM_OFFSET(0x38+k); + writeq(val64, &bar0->tti_command_mem); + + /* + * Once the operation completes, the Strobe bit of the command + * register will be reset. We poll for this particular condition + * We wait for a maximum of 500ms for the operation to complete, + * if it's not complete by then we return error. + */ + time = 0; + while (TRUE) { + val64 = readq(&bar0->tti_command_mem); + if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) { + break; + } + if (time > 10) { + DBG_PRINT(ERR_DBG, + "%s: TTI init Failed\n", + dev->name); + return -1; + } + time++; + msleep(50); + } + } + } else { - writeq(val64, &bar0->rti_data1_mem); + /* RTI Initialization */ + if (nic->device_type == XFRAME_II_DEVICE) { + /* + * Programmed to generate Apprx 500 Intrs per + * second + */ + int count = (nic->config.bus_speed * 125)/4; + val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count); + } else { + val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF); + } + val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) | + RTI_DATA1_MEM_RX_URNG_B(0x10) | + RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN; - val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | - RTI_DATA2_MEM_RX_UFC_B(0x2) | - RTI_DATA2_MEM_RX_UFC_C(0x40) | RTI_DATA2_MEM_RX_UFC_D(0x80); - writeq(val64, &bar0->rti_data2_mem); + writeq(val64, &bar0->rti_data1_mem); - val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD; - writeq(val64, &bar0->rti_command_mem); + val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | + RTI_DATA2_MEM_RX_UFC_B(0x2) | + RTI_DATA2_MEM_RX_UFC_C(0x40) | RTI_DATA2_MEM_RX_UFC_D(0x80); + writeq(val64, &bar0->rti_data2_mem); - /* - * Once the operation completes, the Strobe bit of the command - * register will be reset. We poll for this particular condition - * We wait for a maximum of 500ms for the operation to complete, - * if it's not complete by then we return error. - */ - time = 0; - while (TRUE) { - val64 = readq(&bar0->rti_command_mem); - if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) { - break; - } - if (time > 10) { - DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n", - dev->name); - return -1; + for (i = 0; i < config->rx_ring_num; i++) { + val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD + | RTI_CMD_MEM_OFFSET(i); + writeq(val64, &bar0->rti_command_mem); + + /* + * Once the operation completes, the Strobe bit of the + * command register will be reset. We poll for this + * particular condition. We wait for a maximum of 500ms + * for the operation to complete, if it's not complete + * by then we return error. + */ + time = 0; + while (TRUE) { + val64 = readq(&bar0->rti_command_mem); + if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) { + break; + } + if (time > 10) { + DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n", + dev->name); + return -1; + } + time++; + msleep(50); + } } - time++; - msleep(50); } - /* - * Initializing proper values as Pause threshold into all + /* + * Initializing proper values as Pause threshold into all * the 8 Queues on Rx side. */ writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q0q3); writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7); /* Disable RMAC PAD STRIPPING */ - add = &bar0->mac_cfg; + add = (void *) &bar0->mac_cfg; val64 = readq(&bar0->mac_cfg); val64 &= ~(MAC_CFG_RMAC_STRIP_PAD); writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); @@ -955,8 +1412,8 @@ static int init_nic(struct s2io_nic *nic) writel((u32) (val64 >> 32), (add + 4)); val64 = readq(&bar0->mac_cfg); - /* - * Set the time value to be inserted in the pause frame + /* + * Set the time value to be inserted in the pause frame * generated by xena. */ val64 = readq(&bar0->rmac_pause_cfg); @@ -964,7 +1421,7 @@ static int init_nic(struct s2io_nic *nic) val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time); writeq(val64, &bar0->rmac_pause_cfg); - /* + /* * Set the Threshold Limit for Generating the pause frame * If the amount of data in any Queue exceeds ratio of * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256 @@ -988,25 +1445,54 @@ static int init_nic(struct s2io_nic *nic) } writeq(val64, &bar0->mc_pause_thresh_q4q7); - /* - * TxDMA will stop Read request if the number of read split has + /* + * TxDMA will stop Read request if the number of read split has * exceeded the limit pointed by shared_splits */ val64 = readq(&bar0->pic_control); val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits); writeq(val64, &bar0->pic_control); + /* + * Programming the Herc to split every write transaction + * that does not start on an ADB to reduce disconnects. + */ + if (nic->device_type == XFRAME_II_DEVICE) { + val64 = WREQ_SPLIT_MASK_SET_MASK(255); + writeq(val64, &bar0->wreq_split_mask); + } + + /* Setting Link stability period to 64 ms */ + if (nic->device_type == XFRAME_II_DEVICE) { + val64 = MISC_LINK_STABILITY_PRD(3); + writeq(val64, &bar0->misc_control); + } + return SUCCESS; } +#define LINK_UP_DOWN_INTERRUPT 1 +#define MAC_RMAC_ERR_TIMER 2 -/** - * en_dis_able_nic_intrs - Enable or Disable the interrupts +#if defined(CONFIG_MSI_MODE) || defined(CONFIG_MSIX_MODE) +#define s2io_link_fault_indication(x) MAC_RMAC_ERR_TIMER +#else +int s2io_link_fault_indication(nic_t *nic) +{ + if (nic->device_type == XFRAME_II_DEVICE) + return LINK_UP_DOWN_INTERRUPT; + else + return MAC_RMAC_ERR_TIMER; +} +#endif + +/** + * en_dis_able_nic_intrs - Enable or Disable the interrupts * @nic: device private variable, * @mask: A mask indicating which Intr block must be modified and, * @flag: A flag indicating whether to enable or disable the Intrs. * Description: This function will either disable or enable the interrupts - * depending on the flag argument. The mask argument can be used to - * enable/disable any Intr block. + * depending on the flag argument. The mask argument can be used to + * enable/disable any Intr block. * Return Value: NONE. */ @@ -1024,20 +1510,31 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* - * Disabled all PCIX, Flash, MDIO, IIC and GPIO - * interrupts for now. - * TODO + /* + * If Hercules adapter enable GPIO otherwise + * disabled all PCIX, Flash, MDIO, IIC and GPIO + * interrupts for now. + * TODO */ - writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); - /* + if (s2io_link_fault_indication(nic) == + LINK_UP_DOWN_INTERRUPT ) { + temp64 = readq(&bar0->pic_int_mask); + temp64 &= ~((u64) PIC_INT_GPIO); + writeq(temp64, &bar0->pic_int_mask); + temp64 = readq(&bar0->gpio_int_mask); + temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP); + writeq(temp64, &bar0->gpio_int_mask); + } else { + writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); + } + /* * No MSI Support is available presently, so TTI and * RTI interrupts are also disabled. */ } else if (flag == DISABLE_INTRS) { - /* - * Disable PIC Intrs in the general - * intr mask register + /* + * Disable PIC Intrs in the general + * intr mask register */ writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); temp64 = readq(&bar0->general_int_mask); @@ -1055,27 +1552,27 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* - * Keep all interrupts other than PFC interrupt + /* + * Keep all interrupts other than PFC interrupt * and PCC interrupt disabled in DMA level. */ val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M | TXDMA_PCC_INT_M); writeq(val64, &bar0->txdma_int_mask); - /* - * Enable only the MISC error 1 interrupt in PFC block + /* + * Enable only the MISC error 1 interrupt in PFC block */ val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1); writeq(val64, &bar0->pfc_err_mask); - /* - * Enable only the FB_ECC error interrupt in PCC block + /* + * Enable only the FB_ECC error interrupt in PCC block */ val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR); writeq(val64, &bar0->pcc_err_mask); } else if (flag == DISABLE_INTRS) { - /* - * Disable TxDMA Intrs in the general intr mask - * register + /* + * Disable TxDMA Intrs in the general intr mask + * register */ writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask); writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask); @@ -1093,15 +1590,15 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* - * All RxDMA block interrupts are disabled for now - * TODO + /* + * All RxDMA block interrupts are disabled for now + * TODO */ writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask); } else if (flag == DISABLE_INTRS) { - /* - * Disable RxDMA Intrs in the general intr mask - * register + /* + * Disable RxDMA Intrs in the general intr mask + * register */ writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask); temp64 = readq(&bar0->general_int_mask); @@ -1118,22 +1615,13 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* - * All MAC block error interrupts are disabled for now - * except the link status change interrupt. + /* + * All MAC block error interrupts are disabled for now * TODO */ - val64 = MAC_INT_STATUS_RMAC_INT; - temp64 = readq(&bar0->mac_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->mac_int_mask); - - val64 = readq(&bar0->mac_rmac_err_mask); - val64 &= ~((u64) RMAC_LINK_STATE_CHANGE_INT); - writeq(val64, &bar0->mac_rmac_err_mask); } else if (flag == DISABLE_INTRS) { - /* - * Disable MAC Intrs in the general intr mask register + /* + * Disable MAC Intrs in the general intr mask register */ writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask); writeq(DISABLE_ALL_INTRS, @@ -1152,14 +1640,14 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* + /* * All XGXS block error interrupts are disabled for now - * TODO + * TODO */ writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask); } else if (flag == DISABLE_INTRS) { - /* - * Disable MC Intrs in the general intr mask register + /* + * Disable MC Intrs in the general intr mask register */ writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask); temp64 = readq(&bar0->general_int_mask); @@ -1175,11 +1663,11 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* - * All MC block error interrupts are disabled for now - * TODO + /* + * Enable all MC Intrs. */ - writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask); + writeq(0x0, &bar0->mc_int_mask); + writeq(0x0, &bar0->mc_err_mask); } else if (flag == DISABLE_INTRS) { /* * Disable MC Intrs in the general intr mask register @@ -1199,14 +1687,14 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* + /* * Enable all the Tx side interrupts - * writing 0 Enables all 64 TX interrupt levels + * writing 0 Enables all 64 TX interrupt levels */ writeq(0x0, &bar0->tx_traffic_mask); } else if (flag == DISABLE_INTRS) { - /* - * Disable Tx Traffic Intrs in the general intr mask + /* + * Disable Tx Traffic Intrs in the general intr mask * register. */ writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask); @@ -1226,8 +1714,8 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) /* writing 0 Enables all 8 RX interrupt levels */ writeq(0x0, &bar0->rx_traffic_mask); } else if (flag == DISABLE_INTRS) { - /* - * Disable Rx Traffic Intrs in the general intr mask + /* + * Disable Rx Traffic Intrs in the general intr mask * register. */ writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask); @@ -1238,24 +1726,66 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) } } -/** - * verify_xena_quiescence - Checks whether the H/W is ready +static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc) +{ + int ret = 0; + + if (flag == FALSE) { + if ((!herc && (rev_id >= 4)) || herc) { + if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) && + ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == + ADAPTER_STATUS_RC_PRC_QUIESCENT)) { + ret = 1; + } + }else { + if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) && + ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == + ADAPTER_STATUS_RC_PRC_QUIESCENT)) { + ret = 1; + } + } + } else { + if ((!herc && (rev_id >= 4)) || herc) { + if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) == + ADAPTER_STATUS_RMAC_PCC_IDLE) && + (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) || + ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == + ADAPTER_STATUS_RC_PRC_QUIESCENT))) { + ret = 1; + } + } else { + if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) == + ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) && + (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) || + ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == + ADAPTER_STATUS_RC_PRC_QUIESCENT))) { + ret = 1; + } + } + } + + return ret; +} +/** + * verify_xena_quiescence - Checks whether the H/W is ready * @val64 : Value read from adapter status register. * @flag : indicates if the adapter enable bit was ever written once * before. * Description: Returns whether the H/W is ready to go or not. Depending - * on whether adapter enable bit was written or not the comparison + * on whether adapter enable bit was written or not the comparison * differs and the calling function passes the input argument flag to * indicate this. - * Return: 1 If xena is quiescence + * Return: 1 If xena is quiescence * 0 If Xena is not quiescence */ -static int verify_xena_quiescence(u64 val64, int flag) +static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag) { - int ret = 0; + int ret = 0, herc; u64 tmp64 = ~((u64) val64); + int rev_id = get_xena_rev_id(sp->pdev); + herc = (sp->device_type == XFRAME_II_DEVICE); if (! (tmp64 & (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY | @@ -1263,25 +1793,7 @@ static int verify_xena_quiescence(u64 val64, int flag) ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY | ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK | ADAPTER_STATUS_P_PLL_LOCK))) { - if (flag == FALSE) { - if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) && - ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT)) { - - ret = 1; - - } - } else { - if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) == - ADAPTER_STATUS_RMAC_PCC_IDLE) && - (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) || - ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT))) { - - ret = 1; - - } - } + ret = check_prc_pcc_state(val64, flag, rev_id, herc); } return ret; @@ -1290,12 +1802,12 @@ static int verify_xena_quiescence(u64 val64, int flag) /** * fix_mac_address - Fix for Mac addr problem on Alpha platforms * @sp: Pointer to device specifc structure - * Description : + * Description : * New procedure to clear mac address reading problems on Alpha platforms * */ -static void fix_mac_address(nic_t * sp) +void fix_mac_address(nic_t * sp) { XENA_dev_config_t __iomem *bar0 = sp->bar0; u64 val64; @@ -1303,20 +1815,21 @@ static void fix_mac_address(nic_t * sp) while (fix_mac[i] != END_SIGN) { writeq(fix_mac[i++], &bar0->gpio_control); + udelay(10); val64 = readq(&bar0->gpio_control); } } /** - * start_nic - Turns the device on + * start_nic - Turns the device on * @nic : device private variable. - * Description: - * This function actually turns the device on. Before this function is - * called,all Registers are configured from their reset states - * and shared memory is allocated but the NIC is still quiescent. On + * Description: + * This function actually turns the device on. Before this function is + * called,all Registers are configured from their reset states + * and shared memory is allocated but the NIC is still quiescent. On * calling this function, the device interrupts are cleared and the NIC is * literally switched on by writing into the adapter control register. - * Return Value: + * Return Value: * SUCCESS on success and -1 on failure. */ @@ -1325,8 +1838,8 @@ static int start_nic(struct s2io_nic *nic) XENA_dev_config_t __iomem *bar0 = nic->bar0; struct net_device *dev = nic->dev; register u64 val64 = 0; - u16 interruptible, i; - u16 subid; + u16 interruptible; + u16 subid, i; mac_info_t *mac_control; struct config_param *config; @@ -1335,10 +1848,12 @@ static int start_nic(struct s2io_nic *nic) /* PRC Initialization and configuration */ for (i = 0; i < config->rx_ring_num; i++) { - writeq((u64) nic->rx_blocks[i][0].block_dma_addr, + writeq((u64) mac_control->rings[i].rx_blocks[0].block_dma_addr, &bar0->prc_rxd0_n[i]); val64 = readq(&bar0->prc_ctrl_n[i]); + if (nic->config.bimodal) + val64 |= PRC_CTRL_BIMODAL_INTERRUPT; #ifndef CONFIG_2BUFF_MODE val64 |= PRC_CTRL_RC_ENABLED; #else @@ -1354,7 +1869,7 @@ static int start_nic(struct s2io_nic *nic) writeq(val64, &bar0->rx_pa_cfg); #endif - /* + /* * Enabling MC-RLDRAM. After enabling the device, we timeout * for around 100ms, which is approximately the time required * for the device to be ready for operation. @@ -1364,27 +1879,27 @@ static int start_nic(struct s2io_nic *nic) SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF); val64 = readq(&bar0->mc_rldram_mrs); - msleep(100); /* Delay by around 100 ms. */ + msleep(100); /* Delay by around 100 ms. */ /* Enabling ECC Protection. */ val64 = readq(&bar0->adapter_control); val64 &= ~ADAPTER_ECC_EN; writeq(val64, &bar0->adapter_control); - /* - * Clearing any possible Link state change interrupts that + /* + * Clearing any possible Link state change interrupts that * could have popped up just before Enabling the card. */ val64 = readq(&bar0->mac_rmac_err_reg); if (val64) writeq(val64, &bar0->mac_rmac_err_reg); - /* - * Verify if the device is ready to be enabled, if so enable + /* + * Verify if the device is ready to be enabled, if so enable * it. */ val64 = readq(&bar0->adapter_status); - if (!verify_xena_quiescence(val64, nic->device_enabled_once)) { + if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) { DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name); DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n", (unsigned long long) val64); @@ -1392,16 +1907,18 @@ static int start_nic(struct s2io_nic *nic) } /* Enable select interrupts */ - interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR | TX_MAC_INTR | - RX_MAC_INTR; + interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; + interruptible |= TX_PIC_INTR | RX_PIC_INTR; + interruptible |= TX_MAC_INTR | RX_MAC_INTR; + en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS); - /* + /* * With some switches, link might be already up at this point. - * Because of this weird behavior, when we enable laser, - * we may not get link. We need to handle this. We cannot - * figure out which switch is misbehaving. So we are forced to - * make a global change. + * Because of this weird behavior, when we enable laser, + * we may not get link. We need to handle this. We cannot + * figure out which switch is misbehaving. So we are forced to + * make a global change. */ /* Enabling Laser. */ @@ -1411,44 +1928,30 @@ static int start_nic(struct s2io_nic *nic) /* SXE-002: Initialize link and activity LED */ subid = nic->pdev->subsystem_device; - if ((subid & 0xFF) >= 0x07) { + if (((subid & 0xFF) >= 0x07) && + (nic->device_type == XFRAME_I_DEVICE)) { val64 = readq(&bar0->gpio_control); val64 |= 0x0000800000000000ULL; writeq(val64, &bar0->gpio_control); val64 = 0x0411040400000000ULL; - writeq(val64, (void __iomem *) bar0 + 0x2700); + writeq(val64, (void __iomem *) ((u8 *) bar0 + 0x2700)); } - /* - * Don't see link state interrupts on certain switches, so + /* + * Don't see link state interrupts on certain switches, so * directly scheduling a link state task from here. */ schedule_work(&nic->set_link_task); - /* - * Here we are performing soft reset on XGXS to - * force link down. Since link is already up, we will get - * link state change interrupt after this reset - */ - SPECIAL_REG_WRITE(0x80010515001E0000ULL, &bar0->dtx_control, UF); - val64 = readq(&bar0->dtx_control); - udelay(50); - SPECIAL_REG_WRITE(0x80010515001E00E0ULL, &bar0->dtx_control, UF); - val64 = readq(&bar0->dtx_control); - udelay(50); - SPECIAL_REG_WRITE(0x80070515001F00E4ULL, &bar0->dtx_control, UF); - val64 = readq(&bar0->dtx_control); - udelay(50); - return SUCCESS; } -/** - * free_tx_buffers - Free all queued Tx buffers +/** + * free_tx_buffers - Free all queued Tx buffers * @nic : device private variable. - * Description: + * Description: * Free all queued Tx buffers. - * Return Value: void + * Return Value: void */ static void free_tx_buffers(struct s2io_nic *nic) @@ -1459,39 +1962,61 @@ static void free_tx_buffers(struct s2io_nic *nic) int i, j; mac_info_t *mac_control; struct config_param *config; - int cnt = 0; + int cnt = 0, frg_cnt; mac_control = &nic->mac_control; config = &nic->config; for (i = 0; i < config->tx_fifo_num; i++) { for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) { - txdp = (TxD_t *) nic->list_info[i][j]. + txdp = (TxD_t *) mac_control->fifos[i].list_info[j]. list_virt_addr; skb = (struct sk_buff *) ((unsigned long) txdp-> Host_Control); if (skb == NULL) { - memset(txdp, 0, sizeof(TxD_t)); + memset(txdp, 0, sizeof(TxD_t) * + config->max_txds); continue; } + frg_cnt = skb_shinfo(skb)->nr_frags; + pci_unmap_single(nic->pdev, (dma_addr_t) + txdp->Buffer_Pointer, + skb->len - skb->data_len, + PCI_DMA_TODEVICE); + if (frg_cnt) { + TxD_t *temp; + temp = txdp; + txdp++; + for (j = 0; j < frg_cnt; j++, txdp++) { + skb_frag_t *frag = + &skb_shinfo(skb)->frags[j]; + pci_unmap_page(nic->pdev, + (dma_addr_t) + txdp-> + Buffer_Pointer, + frag->size, + PCI_DMA_TODEVICE); + } + txdp = temp; + } dev_kfree_skb(skb); - memset(txdp, 0, sizeof(TxD_t)); + memset(txdp, 0, sizeof(TxD_t) * config->max_txds); cnt++; } DBG_PRINT(INTR_DBG, "%s:forcibly freeing %d skbs on FIFO%d\n", dev->name, cnt, i); - mac_control->tx_curr_get_info[i].offset = 0; - mac_control->tx_curr_put_info[i].offset = 0; + mac_control->fifos[i].tx_curr_get_info.offset = 0; + mac_control->fifos[i].tx_curr_put_info.offset = 0; } } -/** - * stop_nic - To stop the nic +/** + * stop_nic - To stop the nic * @nic ; device private variable. - * Description: - * This function does exactly the opposite of what the start_nic() + * Description: + * This function does exactly the opposite of what the start_nic() * function does. This function is called to stop the device. * Return Value: * void. @@ -1509,8 +2034,9 @@ static void stop_nic(struct s2io_nic *nic) config = &nic->config; /* Disable all interrupts */ - interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR | TX_MAC_INTR | - RX_MAC_INTR; + interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; + interruptible |= TX_PIC_INTR | RX_PIC_INTR; + interruptible |= TX_MAC_INTR | RX_MAC_INTR; en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS); /* Disable PRCs */ @@ -1521,11 +2047,11 @@ static void stop_nic(struct s2io_nic *nic) } } -/** - * fill_rx_buffers - Allocates the Rx side skbs +/** + * fill_rx_buffers - Allocates the Rx side skbs * @nic: device private variable - * @ring_no: ring number - * Description: + * @ring_no: ring number + * Description: * The function allocates Rx side skbs and puts the physical * address of these buffers into the RxD buffer pointers, so that the NIC * can DMA the received frame into these locations. @@ -1533,8 +2059,8 @@ static void stop_nic(struct s2io_nic *nic) * 1. single buffer, * 2. three buffer and * 3. Five buffer modes. - * Each mode defines how many fragments the received frame will be split - * up into by the NIC. The frame is split into L3 header, L4 Header, + * Each mode defines how many fragments the received frame will be split + * up into by the NIC. The frame is split into L3 header, L4 Header, * L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself * is split into 3 fragments. As of now only single buffer mode is * supported. @@ -1542,7 +2068,7 @@ static void stop_nic(struct s2io_nic *nic) * SUCCESS on success or an appropriate -ve value on failure. */ -static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) +int fill_rx_buffers(struct s2io_nic *nic, int ring_no) { struct net_device *dev = nic->dev; struct sk_buff *skb; @@ -1550,34 +2076,35 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) int off, off1, size, block_no, block_no1; int offset, offset1; u32 alloc_tab = 0; - u32 alloc_cnt = nic->pkt_cnt[ring_no] - - atomic_read(&nic->rx_bufs_left[ring_no]); + u32 alloc_cnt; mac_info_t *mac_control; struct config_param *config; #ifdef CONFIG_2BUFF_MODE RxD_t *rxdpnext; int nextblk; - unsigned long tmp; + u64 tmp; buffAdd_t *ba; dma_addr_t rxdpphys; #endif #ifndef CONFIG_S2IO_NAPI unsigned long flags; #endif + RxD_t *first_rxdp = NULL; mac_control = &nic->mac_control; config = &nic->config; - + alloc_cnt = mac_control->rings[ring_no].pkt_cnt - + atomic_read(&nic->rx_bufs_left[ring_no]); size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE + HEADER_802_2_SIZE + HEADER_SNAP_SIZE; while (alloc_tab < alloc_cnt) { - block_no = mac_control->rx_curr_put_info[ring_no]. + block_no = mac_control->rings[ring_no].rx_curr_put_info. block_index; - block_no1 = mac_control->rx_curr_get_info[ring_no]. + block_no1 = mac_control->rings[ring_no].rx_curr_get_info. block_index; - off = mac_control->rx_curr_put_info[ring_no].offset; - off1 = mac_control->rx_curr_get_info[ring_no].offset; + off = mac_control->rings[ring_no].rx_curr_put_info.offset; + off1 = mac_control->rings[ring_no].rx_curr_get_info.offset; #ifndef CONFIG_2BUFF_MODE offset = block_no * (MAX_RXDS_PER_BLOCK + 1) + off; offset1 = block_no1 * (MAX_RXDS_PER_BLOCK + 1) + off1; @@ -1586,7 +2113,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) offset1 = block_no1 * (MAX_RXDS_PER_BLOCK) + off1; #endif - rxdp = nic->rx_blocks[ring_no][block_no]. + rxdp = mac_control->rings[ring_no].rx_blocks[block_no]. block_virt_addr + off; if ((offset == offset1) && (rxdp->Host_Control)) { DBG_PRINT(INTR_DBG, "%s: Get and Put", dev->name); @@ -1595,15 +2122,15 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) } #ifndef CONFIG_2BUFF_MODE if (rxdp->Control_1 == END_OF_BLOCK) { - mac_control->rx_curr_put_info[ring_no]. + mac_control->rings[ring_no].rx_curr_put_info. block_index++; - mac_control->rx_curr_put_info[ring_no]. - block_index %= nic->block_count[ring_no]; - block_no = mac_control->rx_curr_put_info - [ring_no].block_index; + mac_control->rings[ring_no].rx_curr_put_info. + block_index %= mac_control->rings[ring_no].block_count; + block_no = mac_control->rings[ring_no].rx_curr_put_info. + block_index; off++; off %= (MAX_RXDS_PER_BLOCK + 1); - mac_control->rx_curr_put_info[ring_no].offset = + mac_control->rings[ring_no].rx_curr_put_info.offset = off; rxdp = (RxD_t *) ((unsigned long) rxdp->Control_2); DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n", @@ -1611,30 +2138,30 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) } #ifndef CONFIG_S2IO_NAPI spin_lock_irqsave(&nic->put_lock, flags); - nic->put_pos[ring_no] = + mac_control->rings[ring_no].put_pos = (block_no * (MAX_RXDS_PER_BLOCK + 1)) + off; spin_unlock_irqrestore(&nic->put_lock, flags); #endif #else if (rxdp->Host_Control == END_OF_BLOCK) { - mac_control->rx_curr_put_info[ring_no]. + mac_control->rings[ring_no].rx_curr_put_info. block_index++; - mac_control->rx_curr_put_info[ring_no]. - block_index %= nic->block_count[ring_no]; - block_no = mac_control->rx_curr_put_info - [ring_no].block_index; + mac_control->rings[ring_no].rx_curr_put_info.block_index + %= mac_control->rings[ring_no].block_count; + block_no = mac_control->rings[ring_no].rx_curr_put_info + .block_index; off = 0; DBG_PRINT(INTR_DBG, "%s: block%d at: 0x%llx\n", dev->name, block_no, (unsigned long long) rxdp->Control_1); - mac_control->rx_curr_put_info[ring_no].offset = + mac_control->rings[ring_no].rx_curr_put_info.offset = off; - rxdp = nic->rx_blocks[ring_no][block_no]. + rxdp = mac_control->rings[ring_no].rx_blocks[block_no]. block_virt_addr; } #ifndef CONFIG_S2IO_NAPI spin_lock_irqsave(&nic->put_lock, flags); - nic->put_pos[ring_no] = (block_no * + mac_control->rings[ring_no].put_pos = (block_no * (MAX_RXDS_PER_BLOCK + 1)) + off; spin_unlock_irqrestore(&nic->put_lock, flags); #endif @@ -1646,27 +2173,27 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) if (rxdp->Control_2 & BIT(0)) #endif { - mac_control->rx_curr_put_info[ring_no]. + mac_control->rings[ring_no].rx_curr_put_info. offset = off; goto end; } #ifdef CONFIG_2BUFF_MODE - /* - * RxDs Spanning cache lines will be replenished only - * if the succeeding RxD is also owned by Host. It - * will always be the ((8*i)+3) and ((8*i)+6) - * descriptors for the 48 byte descriptor. The offending + /* + * RxDs Spanning cache lines will be replenished only + * if the succeeding RxD is also owned by Host. It + * will always be the ((8*i)+3) and ((8*i)+6) + * descriptors for the 48 byte descriptor. The offending * decsriptor is of-course the 3rd descriptor. */ - rxdpphys = nic->rx_blocks[ring_no][block_no]. + rxdpphys = mac_control->rings[ring_no].rx_blocks[block_no]. block_dma_addr + (off * sizeof(RxD_t)); if (((u64) (rxdpphys)) % 128 > 80) { - rxdpnext = nic->rx_blocks[ring_no][block_no]. + rxdpnext = mac_control->rings[ring_no].rx_blocks[block_no]. block_virt_addr + (off + 1); if (rxdpnext->Host_Control == END_OF_BLOCK) { nextblk = (block_no + 1) % - (nic->block_count[ring_no]); - rxdpnext = nic->rx_blocks[ring_no] + (mac_control->rings[ring_no].block_count); + rxdpnext = mac_control->rings[ring_no].rx_blocks [nextblk].block_virt_addr; } if (rxdpnext->Control_2 & BIT(0)) @@ -1682,6 +2209,10 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) if (!skb) { DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name); DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n"); + if (first_rxdp) { + wmb(); + first_rxdp->Control_1 |= RXD_OWN_XENA; + } return -ENOMEM; } #ifndef CONFIG_2BUFF_MODE @@ -1692,12 +2223,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) rxdp->Control_2 &= (~MASK_BUFFER0_SIZE); rxdp->Control_2 |= SET_BUFFER0_SIZE(size); rxdp->Host_Control = (unsigned long) (skb); - rxdp->Control_1 |= RXD_OWN_XENA; + if (alloc_tab & ((1 << rxsync_frequency) - 1)) + rxdp->Control_1 |= RXD_OWN_XENA; off++; off %= (MAX_RXDS_PER_BLOCK + 1); - mac_control->rx_curr_put_info[ring_no].offset = off; + mac_control->rings[ring_no].rx_curr_put_info.offset = off; #else - ba = &nic->ba[ring_no][block_no][off]; + ba = &mac_control->rings[ring_no].ba[block_no][off]; skb_reserve(skb, BUF0_LEN); tmp = ((unsigned long) skb->data & ALIGN_SIZE); if (tmp) @@ -1719,22 +2251,41 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) rxdp->Control_2 |= SET_BUFFER1_SIZE(1); /* dummy. */ rxdp->Control_2 |= BIT(0); /* Set Buffer_Empty bit. */ rxdp->Host_Control = (u64) ((unsigned long) (skb)); - rxdp->Control_1 |= RXD_OWN_XENA; + if (alloc_tab & ((1 << rxsync_frequency) - 1)) + rxdp->Control_1 |= RXD_OWN_XENA; off++; - mac_control->rx_curr_put_info[ring_no].offset = off; + mac_control->rings[ring_no].rx_curr_put_info.offset = off; #endif + rxdp->Control_2 |= SET_RXD_MARKER; + + if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) { + if (first_rxdp) { + wmb(); + first_rxdp->Control_1 |= RXD_OWN_XENA; + } + first_rxdp = rxdp; + } atomic_inc(&nic->rx_bufs_left[ring_no]); alloc_tab++; } end: + /* Transfer ownership of first descriptor to adapter just before + * exiting. Before that, use memory barrier so that ownership + * and other fields are seen by adapter correctly. + */ + if (first_rxdp) { + wmb(); + first_rxdp->Control_1 |= RXD_OWN_XENA; + } + return SUCCESS; } /** - * free_rx_buffers - Frees all Rx buffers + * free_rx_buffers - Frees all Rx buffers * @sp: device private variable. - * Description: + * Description: * This function will free all Rx buffers allocated by host. * Return Value: * NONE. @@ -1758,7 +2309,8 @@ static void free_rx_buffers(struct s2io_nic *sp) for (i = 0; i < config->rx_ring_num; i++) { for (j = 0, blk = 0; j < config->rx_cfg[i].num_rxd; j++) { off = j % (MAX_RXDS_PER_BLOCK + 1); - rxdp = sp->rx_blocks[i][blk].block_virt_addr + off; + rxdp = mac_control->rings[i].rx_blocks[blk]. + block_virt_addr + off; #ifndef CONFIG_2BUFF_MODE if (rxdp->Control_1 == END_OF_BLOCK) { @@ -1793,7 +2345,7 @@ static void free_rx_buffers(struct s2io_nic *sp) HEADER_SNAP_SIZE, PCI_DMA_FROMDEVICE); #else - ba = &sp->ba[i][blk][off]; + ba = &mac_control->rings[i].ba[blk][off]; pci_unmap_single(sp->pdev, (dma_addr_t) rxdp->Buffer0_ptr, BUF0_LEN, @@ -1813,10 +2365,10 @@ static void free_rx_buffers(struct s2io_nic *sp) } memset(rxdp, 0, sizeof(RxD_t)); } - mac_control->rx_curr_put_info[i].block_index = 0; - mac_control->rx_curr_get_info[i].block_index = 0; - mac_control->rx_curr_put_info[i].offset = 0; - mac_control->rx_curr_get_info[i].offset = 0; + mac_control->rings[i].rx_curr_put_info.block_index = 0; + mac_control->rings[i].rx_curr_get_info.block_index = 0; + mac_control->rings[i].rx_curr_put_info.offset = 0; + mac_control->rings[i].rx_curr_get_info.offset = 0; atomic_set(&sp->rx_bufs_left[i], 0); DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n", dev->name, buf_cnt, i); @@ -1826,7 +2378,7 @@ static void free_rx_buffers(struct s2io_nic *sp) /** * s2io_poll - Rx interrupt handler for NAPI support * @dev : pointer to the device structure. - * @budget : The number of packets that were budgeted to be processed + * @budget : The number of packets that were budgeted to be processed * during one pass through the 'Poll" function. * Description: * Comes into picture only if NAPI support has been incorporated. It does @@ -1836,160 +2388,36 @@ static void free_rx_buffers(struct s2io_nic *sp) * 0 on success and 1 if there are No Rx packets to be processed. */ -#ifdef CONFIG_S2IO_NAPI +#if defined(CONFIG_S2IO_NAPI) static int s2io_poll(struct net_device *dev, int *budget) { nic_t *nic = dev->priv; - XENA_dev_config_t __iomem *bar0 = nic->bar0; - int pkts_to_process = *budget, pkt_cnt = 0; - register u64 val64 = 0; - rx_curr_get_info_t get_info, put_info; - int i, get_block, put_block, get_offset, put_offset, ring_bufs; -#ifndef CONFIG_2BUFF_MODE - u16 val16, cksum; -#endif - struct sk_buff *skb; - RxD_t *rxdp; + int pkt_cnt = 0, org_pkts_to_process; mac_info_t *mac_control; struct config_param *config; -#ifdef CONFIG_2BUFF_MODE - buffAdd_t *ba; -#endif + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + u64 val64; + int i; + atomic_inc(&nic->isr_cnt); mac_control = &nic->mac_control; config = &nic->config; - if (pkts_to_process > dev->quota) - pkts_to_process = dev->quota; + nic->pkts_to_process = *budget; + if (nic->pkts_to_process > dev->quota) + nic->pkts_to_process = dev->quota; + org_pkts_to_process = nic->pkts_to_process; val64 = readq(&bar0->rx_traffic_int); writeq(val64, &bar0->rx_traffic_int); for (i = 0; i < config->rx_ring_num; i++) { - get_info = mac_control->rx_curr_get_info[i]; - get_block = get_info.block_index; - put_info = mac_control->rx_curr_put_info[i]; - put_block = put_info.block_index; - ring_bufs = config->rx_cfg[i].num_rxd; - rxdp = nic->rx_blocks[i][get_block].block_virt_addr + - get_info.offset; -#ifndef CONFIG_2BUFF_MODE - get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) + - get_info.offset; - put_offset = (put_block * (MAX_RXDS_PER_BLOCK + 1)) + - put_info.offset; - while ((!(rxdp->Control_1 & RXD_OWN_XENA)) && - (((get_offset + 1) % ring_bufs) != put_offset)) { - if (--pkts_to_process < 0) { - goto no_rx; - } - if (rxdp->Control_1 == END_OF_BLOCK) { - rxdp = - (RxD_t *) ((unsigned long) rxdp-> - Control_2); - get_info.offset++; - get_info.offset %= - (MAX_RXDS_PER_BLOCK + 1); - get_block++; - get_block %= nic->block_count[i]; - mac_control->rx_curr_get_info[i]. - offset = get_info.offset; - mac_control->rx_curr_get_info[i]. - block_index = get_block; - continue; - } - get_offset = - (get_block * (MAX_RXDS_PER_BLOCK + 1)) + - get_info.offset; - skb = - (struct sk_buff *) ((unsigned long) rxdp-> - Host_Control); - if (skb == NULL) { - DBG_PRINT(ERR_DBG, "%s: The skb is ", - dev->name); - DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); - goto no_rx; - } - val64 = RXD_GET_BUFFER0_SIZE(rxdp->Control_2); - val16 = (u16) (val64 >> 48); - cksum = RXD_GET_L4_CKSUM(rxdp->Control_1); - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer0_ptr, - dev->mtu + - HEADER_ETHERNET_II_802_3_SIZE + - HEADER_802_2_SIZE + - HEADER_SNAP_SIZE, - PCI_DMA_FROMDEVICE); - rx_osm_handler(nic, val16, rxdp, i); - pkt_cnt++; - get_info.offset++; - get_info.offset %= (MAX_RXDS_PER_BLOCK + 1); - rxdp = - nic->rx_blocks[i][get_block].block_virt_addr + - get_info.offset; - mac_control->rx_curr_get_info[i].offset = - get_info.offset; + rx_intr_handler(&mac_control->rings[i]); + pkt_cnt = org_pkts_to_process - nic->pkts_to_process; + if (!nic->pkts_to_process) { + /* Quota for the current iteration has been met */ + goto no_rx; } -#else - get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) + - get_info.offset; - put_offset = (put_block * (MAX_RXDS_PER_BLOCK + 1)) + - put_info.offset; - while (((!(rxdp->Control_1 & RXD_OWN_XENA)) && - !(rxdp->Control_2 & BIT(0))) && - (((get_offset + 1) % ring_bufs) != put_offset)) { - if (--pkts_to_process < 0) { - goto no_rx; - } - skb = (struct sk_buff *) ((unsigned long) - rxdp->Host_Control); - if (skb == NULL) { - DBG_PRINT(ERR_DBG, "%s: The skb is ", - dev->name); - DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); - goto no_rx; - } - - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer0_ptr, - BUF0_LEN, PCI_DMA_FROMDEVICE); - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer1_ptr, - BUF1_LEN, PCI_DMA_FROMDEVICE); - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer2_ptr, - dev->mtu + BUF0_LEN + 4, - PCI_DMA_FROMDEVICE); - ba = &nic->ba[i][get_block][get_info.offset]; - - rx_osm_handler(nic, rxdp, i, ba); - - get_info.offset++; - mac_control->rx_curr_get_info[i].offset = - get_info.offset; - rxdp = - nic->rx_blocks[i][get_block].block_virt_addr + - get_info.offset; - - if (get_info.offset && - (!(get_info.offset % MAX_RXDS_PER_BLOCK))) { - get_info.offset = 0; - mac_control->rx_curr_get_info[i]. - offset = get_info.offset; - get_block++; - get_block %= nic->block_count[i]; - mac_control->rx_curr_get_info[i]. - block_index = get_block; - rxdp = - nic->rx_blocks[i][get_block]. - block_virt_addr; - } - get_offset = - (get_block * (MAX_RXDS_PER_BLOCK + 1)) + - get_info.offset; - pkt_cnt++; - } -#endif } if (!pkt_cnt) pkt_cnt = 1; @@ -2007,9 +2435,10 @@ static int s2io_poll(struct net_device *dev, int *budget) } /* Re enable the Rx interrupts. */ en_dis_able_nic_intrs(nic, RX_TRAFFIC_INTR, ENABLE_INTRS); + atomic_dec(&nic->isr_cnt); return 0; - no_rx: +no_rx: dev->quota -= pkt_cnt; *budget -= pkt_cnt; @@ -2020,279 +2449,204 @@ static int s2io_poll(struct net_device *dev, int *budget) break; } } + atomic_dec(&nic->isr_cnt); return 1; } -#else -/** +#endif + +/** * rx_intr_handler - Rx interrupt handler * @nic: device private variable. - * Description: - * If the interrupt is because of a received frame or if the + * Description: + * If the interrupt is because of a received frame or if the * receive ring contains fresh as yet un-processed frames,this function is - * called. It picks out the RxD at which place the last Rx processing had - * stopped and sends the skb to the OSM's Rx handler and then increments + * called. It picks out the RxD at which place the last Rx processing had + * stopped and sends the skb to the OSM's Rx handler and then increments * the offset. * Return Value: * NONE. */ - -static void rx_intr_handler(struct s2io_nic *nic) +static void rx_intr_handler(ring_info_t *ring_data) { + nic_t *nic = ring_data->nic; struct net_device *dev = (struct net_device *) nic->dev; - XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + int get_block, get_offset, put_block, put_offset, ring_bufs; rx_curr_get_info_t get_info, put_info; RxD_t *rxdp; struct sk_buff *skb; -#ifndef CONFIG_2BUFF_MODE - u16 val16, cksum; -#endif - register u64 val64 = 0; - int get_block, get_offset, put_block, put_offset, ring_bufs; - int i, pkt_cnt = 0; - mac_info_t *mac_control; - struct config_param *config; -#ifdef CONFIG_2BUFF_MODE - buffAdd_t *ba; +#ifndef CONFIG_S2IO_NAPI + int pkt_cnt = 0; #endif + spin_lock(&nic->rx_lock); + if (atomic_read(&nic->card_state) == CARD_DOWN) { + DBG_PRINT(ERR_DBG, "%s: %s going down for reset\n", + __FUNCTION__, dev->name); + spin_unlock(&nic->rx_lock); + } - mac_control = &nic->mac_control; - config = &nic->config; - - /* - * rx_traffic_int reg is an R1 register, hence we read and write back - * the samevalue in the register to clear it. - */ - val64 = readq(&bar0->rx_traffic_int); - writeq(val64, &bar0->rx_traffic_int); - - for (i = 0; i < config->rx_ring_num; i++) { - get_info = mac_control->rx_curr_get_info[i]; - get_block = get_info.block_index; - put_info = mac_control->rx_curr_put_info[i]; - put_block = put_info.block_index; - ring_bufs = config->rx_cfg[i].num_rxd; - rxdp = nic->rx_blocks[i][get_block].block_virt_addr + - get_info.offset; -#ifndef CONFIG_2BUFF_MODE - get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) + + get_info = ring_data->rx_curr_get_info; + get_block = get_info.block_index; + put_info = ring_data->rx_curr_put_info; + put_block = put_info.block_index; + ring_bufs = get_info.ring_len+1; + rxdp = ring_data->rx_blocks[get_block].block_virt_addr + get_info.offset; - spin_lock(&nic->put_lock); - put_offset = nic->put_pos[i]; - spin_unlock(&nic->put_lock); - while ((!(rxdp->Control_1 & RXD_OWN_XENA)) && - (((get_offset + 1) % ring_bufs) != put_offset)) { - if (rxdp->Control_1 == END_OF_BLOCK) { - rxdp = (RxD_t *) ((unsigned long) - rxdp->Control_2); - get_info.offset++; - get_info.offset %= - (MAX_RXDS_PER_BLOCK + 1); - get_block++; - get_block %= nic->block_count[i]; - mac_control->rx_curr_get_info[i]. - offset = get_info.offset; - mac_control->rx_curr_get_info[i]. - block_index = get_block; - continue; - } - get_offset = - (get_block * (MAX_RXDS_PER_BLOCK + 1)) + - get_info.offset; - skb = (struct sk_buff *) ((unsigned long) - rxdp->Host_Control); - if (skb == NULL) { - DBG_PRINT(ERR_DBG, "%s: The skb is ", - dev->name); - DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); - return; - } - val64 = RXD_GET_BUFFER0_SIZE(rxdp->Control_2); - val16 = (u16) (val64 >> 48); - cksum = RXD_GET_L4_CKSUM(rxdp->Control_1); - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer0_ptr, - dev->mtu + - HEADER_ETHERNET_II_802_3_SIZE + - HEADER_802_2_SIZE + - HEADER_SNAP_SIZE, - PCI_DMA_FROMDEVICE); - rx_osm_handler(nic, val16, rxdp, i); - get_info.offset++; - get_info.offset %= (MAX_RXDS_PER_BLOCK + 1); - rxdp = - nic->rx_blocks[i][get_block].block_virt_addr + - get_info.offset; - mac_control->rx_curr_get_info[i].offset = - get_info.offset; - pkt_cnt++; - if ((indicate_max_pkts) - && (pkt_cnt > indicate_max_pkts)) - break; + get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) + + get_info.offset; +#ifndef CONFIG_S2IO_NAPI + spin_lock(&nic->put_lock); + put_offset = ring_data->put_pos; + spin_unlock(&nic->put_lock); +#else + put_offset = (put_block * (MAX_RXDS_PER_BLOCK + 1)) + + put_info.offset; +#endif + while (RXD_IS_UP2DT(rxdp) && + (((get_offset + 1) % ring_bufs) != put_offset)) { + skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control); + if (skb == NULL) { + DBG_PRINT(ERR_DBG, "%s: The skb is ", + dev->name); + DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); + spin_unlock(&nic->rx_lock); + return; } +#ifndef CONFIG_2BUFF_MODE + pci_unmap_single(nic->pdev, (dma_addr_t) + rxdp->Buffer0_ptr, + dev->mtu + + HEADER_ETHERNET_II_802_3_SIZE + + HEADER_802_2_SIZE + + HEADER_SNAP_SIZE, + PCI_DMA_FROMDEVICE); #else - get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) + + pci_unmap_single(nic->pdev, (dma_addr_t) + rxdp->Buffer0_ptr, + BUF0_LEN, PCI_DMA_FROMDEVICE); + pci_unmap_single(nic->pdev, (dma_addr_t) + rxdp->Buffer1_ptr, + BUF1_LEN, PCI_DMA_FROMDEVICE); + pci_unmap_single(nic->pdev, (dma_addr_t) + rxdp->Buffer2_ptr, + dev->mtu + BUF0_LEN + 4, + PCI_DMA_FROMDEVICE); +#endif + rx_osm_handler(ring_data, rxdp); + get_info.offset++; + ring_data->rx_curr_get_info.offset = get_info.offset; - spin_lock(&nic->put_lock); - put_offset = nic->put_pos[i]; - spin_unlock(&nic->put_lock); - while (((!(rxdp->Control_1 & RXD_OWN_XENA)) && - !(rxdp->Control_2 & BIT(0))) && - (((get_offset + 1) % ring_bufs) != put_offset)) { - skb = (struct sk_buff *) ((unsigned long) - rxdp->Host_Control); - if (skb == NULL) { - DBG_PRINT(ERR_DBG, "%s: The skb is ", - dev->name); - DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); - return; - } - - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer0_ptr, - BUF0_LEN, PCI_DMA_FROMDEVICE); - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer1_ptr, - BUF1_LEN, PCI_DMA_FROMDEVICE); - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer2_ptr, - dev->mtu + BUF0_LEN + 4, - PCI_DMA_FROMDEVICE); - ba = &nic->ba[i][get_block][get_info.offset]; - - rx_osm_handler(nic, rxdp, i, ba); - - get_info.offset++; - mac_control->rx_curr_get_info[i].offset = - get_info.offset; - rxdp = - nic->rx_blocks[i][get_block].block_virt_addr + - get_info.offset; + rxdp = ring_data->rx_blocks[get_block].block_virt_addr + + get_info.offset; + if (get_info.offset && + (!(get_info.offset % MAX_RXDS_PER_BLOCK))) { + get_info.offset = 0; + ring_data->rx_curr_get_info.offset + = get_info.offset; + get_block++; + get_block %= ring_data->block_count; + ring_data->rx_curr_get_info.block_index + = get_block; + rxdp = ring_data->rx_blocks[get_block].block_virt_addr; + } - if (get_info.offset && - (!(get_info.offset % MAX_RXDS_PER_BLOCK))) { - get_info.offset = 0; - mac_control->rx_curr_get_info[i]. - offset = get_info.offset; - get_block++; - get_block %= nic->block_count[i]; - mac_control->rx_curr_get_info[i]. - block_index = get_block; - rxdp = - nic->rx_blocks[i][get_block]. - block_virt_addr; - } - get_offset = - (get_block * (MAX_RXDS_PER_BLOCK + 1)) + + get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) + get_info.offset; - pkt_cnt++; - if ((indicate_max_pkts) - && (pkt_cnt > indicate_max_pkts)) - break; - } -#endif +#ifdef CONFIG_S2IO_NAPI + nic->pkts_to_process -= 1; + if (!nic->pkts_to_process) + break; +#else + pkt_cnt++; if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts)) break; +#endif } + spin_unlock(&nic->rx_lock); } -#endif -/** + +/** * tx_intr_handler - Transmit interrupt handler * @nic : device private variable - * Description: - * If an interrupt was raised to indicate DMA complete of the - * Tx packet, this function is called. It identifies the last TxD - * whose buffer was freed and frees all skbs whose data have already + * Description: + * If an interrupt was raised to indicate DMA complete of the + * Tx packet, this function is called. It identifies the last TxD + * whose buffer was freed and frees all skbs whose data have already * DMA'ed into the NICs internal memory. * Return Value: * NONE */ -static void tx_intr_handler(struct s2io_nic *nic) +static void tx_intr_handler(fifo_info_t *fifo_data) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + nic_t *nic = fifo_data->nic; struct net_device *dev = (struct net_device *) nic->dev; tx_curr_get_info_t get_info, put_info; struct sk_buff *skb; TxD_t *txdlp; - register u64 val64 = 0; - int i; u16 j, frg_cnt; - mac_info_t *mac_control; - struct config_param *config; - mac_control = &nic->mac_control; - config = &nic->config; - - /* - * tx_traffic_int reg is an R1 register, hence we read and write - * back the samevalue in the register to clear it. - */ - val64 = readq(&bar0->tx_traffic_int); - writeq(val64, &bar0->tx_traffic_int); + get_info = fifo_data->tx_curr_get_info; + put_info = fifo_data->tx_curr_put_info; + txdlp = (TxD_t *) fifo_data->list_info[get_info.offset]. + list_virt_addr; + while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) && + (get_info.offset != put_info.offset) && + (txdlp->Host_Control)) { + /* Check for TxD errors */ + if (txdlp->Control_1 & TXD_T_CODE) { + unsigned long long err; + err = txdlp->Control_1 & TXD_T_CODE; + DBG_PRINT(ERR_DBG, "***TxD error %llx\n", + err); + } - for (i = 0; i < config->tx_fifo_num; i++) { - get_info = mac_control->tx_curr_get_info[i]; - put_info = mac_control->tx_curr_put_info[i]; - txdlp = (TxD_t *) nic->list_info[i][get_info.offset]. - list_virt_addr; - while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) && - (get_info.offset != put_info.offset) && - (txdlp->Host_Control)) { - /* Check for TxD errors */ - if (txdlp->Control_1 & TXD_T_CODE) { - unsigned long long err; - err = txdlp->Control_1 & TXD_T_CODE; - DBG_PRINT(ERR_DBG, "***TxD error %llx\n", - err); - } + skb = (struct sk_buff *) ((unsigned long) + txdlp->Host_Control); + if (skb == NULL) { + DBG_PRINT(ERR_DBG, "%s: Null skb ", + __FUNCTION__); + DBG_PRINT(ERR_DBG, "in Tx Free Intr\n"); + return; + } - skb = (struct sk_buff *) ((unsigned long) - txdlp->Host_Control); - if (skb == NULL) { - DBG_PRINT(ERR_DBG, "%s: Null skb ", - dev->name); - DBG_PRINT(ERR_DBG, "in Tx Free Intr\n"); - return; + frg_cnt = skb_shinfo(skb)->nr_frags; + nic->tx_pkt_count++; + + pci_unmap_single(nic->pdev, (dma_addr_t) + txdlp->Buffer_Pointer, + skb->len - skb->data_len, + PCI_DMA_TODEVICE); + if (frg_cnt) { + TxD_t *temp; + temp = txdlp; + txdlp++; + for (j = 0; j < frg_cnt; j++, txdlp++) { + skb_frag_t *frag = + &skb_shinfo(skb)->frags[j]; + if (!txdlp->Buffer_Pointer) + break; + pci_unmap_page(nic->pdev, + (dma_addr_t) + txdlp-> + Buffer_Pointer, + frag->size, + PCI_DMA_TODEVICE); } - nic->tx_pkt_count++; - - frg_cnt = skb_shinfo(skb)->nr_frags; - - /* For unfragmented skb */ - pci_unmap_single(nic->pdev, (dma_addr_t) - txdlp->Buffer_Pointer, - skb->len - skb->data_len, - PCI_DMA_TODEVICE); - if (frg_cnt) { - TxD_t *temp = txdlp; - txdlp++; - for (j = 0; j < frg_cnt; j++, txdlp++) { - skb_frag_t *frag = - &skb_shinfo(skb)->frags[j]; - pci_unmap_page(nic->pdev, - (dma_addr_t) - txdlp-> - Buffer_Pointer, - frag->size, - PCI_DMA_TODEVICE); - } - txdlp = temp; - } - memset(txdlp, 0, - (sizeof(TxD_t) * config->max_txds)); - - /* Updating the statistics block */ - nic->stats.tx_packets++; - nic->stats.tx_bytes += skb->len; - dev_kfree_skb_irq(skb); - - get_info.offset++; - get_info.offset %= get_info.fifo_len + 1; - txdlp = (TxD_t *) nic->list_info[i] - [get_info.offset].list_virt_addr; - mac_control->tx_curr_get_info[i].offset = - get_info.offset; + txdlp = temp; } + memset(txdlp, 0, + (sizeof(TxD_t) * fifo_data->max_txds)); + + /* Updating the statistics block */ + nic->stats.tx_bytes += skb->len; + dev_kfree_skb_irq(skb); + + get_info.offset++; + get_info.offset %= get_info.fifo_len + 1; + txdlp = (TxD_t *) fifo_data->list_info + [get_info.offset].list_virt_addr; + fifo_data->tx_curr_get_info.offset = + get_info.offset; } spin_lock(&nic->tx_lock); @@ -2301,13 +2655,13 @@ static void tx_intr_handler(struct s2io_nic *nic) spin_unlock(&nic->tx_lock); } -/** +/** * alarm_intr_handler - Alarm Interrrupt handler * @nic: device private variable - * Description: If the interrupt was neither because of Rx packet or Tx + * Description: If the interrupt was neither because of Rx packet or Tx * complete, this function is called. If the interrupt was to indicate - * a loss of link, the OSM link status handler is invoked for any other - * alarm interrupt the block that raised the interrupt is displayed + * a loss of link, the OSM link status handler is invoked for any other + * alarm interrupt the block that raised the interrupt is displayed * and a H/W reset is issued. * Return Value: * NONE @@ -2320,10 +2674,32 @@ static void alarm_intr_handler(struct s2io_nic *nic) register u64 val64 = 0, err_reg = 0; /* Handling link status change error Intr */ - err_reg = readq(&bar0->mac_rmac_err_reg); - writeq(err_reg, &bar0->mac_rmac_err_reg); - if (err_reg & RMAC_LINK_STATE_CHANGE_INT) { - schedule_work(&nic->set_link_task); + if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) { + err_reg = readq(&bar0->mac_rmac_err_reg); + writeq(err_reg, &bar0->mac_rmac_err_reg); + if (err_reg & RMAC_LINK_STATE_CHANGE_INT) { + schedule_work(&nic->set_link_task); + } + } + + /* Handling Ecc errors */ + val64 = readq(&bar0->mc_err_reg); + writeq(val64, &bar0->mc_err_reg); + if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) { + if (val64 & MC_ERR_REG_ECC_ALL_DBL) { + nic->mac_control.stats_info->sw_stat. + double_ecc_errs++; + DBG_PRINT(ERR_DBG, "%s: Device indicates ", + dev->name); + DBG_PRINT(ERR_DBG, "double ECC error!!\n"); + if (nic->device_type != XFRAME_II_DEVICE) { + netif_stop_queue(dev); + schedule_work(&nic->rst_timer_task); + } + } else { + nic->mac_control.stats_info->sw_stat. + single_ecc_errs++; + } } /* In case of a serious error, the device will be Reset. */ @@ -2338,7 +2714,7 @@ static void alarm_intr_handler(struct s2io_nic *nic) /* * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC * Error occurs, the adapter will be recycled by disabling the - * adapter enable bit and enabling it again after the device + * adapter enable bit and enabling it again after the device * becomes Quiescent. */ val64 = readq(&bar0->pcc_err_reg); @@ -2354,18 +2730,18 @@ static void alarm_intr_handler(struct s2io_nic *nic) /* Other type of interrupts are not being handled now, TODO */ } -/** +/** * wait_for_cmd_complete - waits for a command to complete. - * @sp : private member of the device structure, which is a pointer to the + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. - * Description: Function that waits for a command to Write into RMAC - * ADDR DATA registers to be completed and returns either success or - * error depending on whether the command was complete or not. + * Description: Function that waits for a command to Write into RMAC + * ADDR DATA registers to be completed and returns either success or + * error depending on whether the command was complete or not. * Return value: * SUCCESS on success and FAILURE on failure. */ -static int wait_for_cmd_complete(nic_t * sp) +int wait_for_cmd_complete(nic_t * sp) { XENA_dev_config_t __iomem *bar0 = sp->bar0; int ret = FAILURE, cnt = 0; @@ -2385,29 +2761,32 @@ static int wait_for_cmd_complete(nic_t * sp) return ret; } -/** - * s2io_reset - Resets the card. +/** + * s2io_reset - Resets the card. * @sp : private member of the device structure. * Description: Function to Reset the card. This function then also - * restores the previously saved PCI configuration space registers as + * restores the previously saved PCI configuration space registers as * the card reset also resets the configuration space. * Return value: * void. */ -static void s2io_reset(nic_t * sp) +void s2io_reset(nic_t * sp) { XENA_dev_config_t __iomem *bar0 = sp->bar0; u64 val64; - u16 subid; + u16 subid, pci_cmd; + + /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */ + pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd)); val64 = SW_RESET_ALL; writeq(val64, &bar0->sw_reset); - /* - * At this stage, if the PCI write is indeed completed, the - * card is reset and so is the PCI Config space of the device. - * So a read cannot be issued at this stage on any of the + /* + * At this stage, if the PCI write is indeed completed, the + * card is reset and so is the PCI Config space of the device. + * So a read cannot be issued at this stage on any of the * registers to ensure the write into "sw_reset" register * has gone through. * Question: Is there any system call that will explicitly force @@ -2418,42 +2797,72 @@ static void s2io_reset(nic_t * sp) */ msleep(250); - /* Restore the PCI state saved during initializarion. */ + /* Restore the PCI state saved during initialization. */ pci_restore_state(sp->pdev); + pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, + pci_cmd); s2io_init_pci(sp); msleep(250); + /* Set swapper to enable I/O register access */ + s2io_set_swapper(sp); + + /* Clear certain PCI/PCI-X fields after reset */ + if (sp->device_type == XFRAME_II_DEVICE) { + /* Clear parity err detect bit */ + pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000); + + /* Clearing PCIX Ecc status register */ + pci_write_config_dword(sp->pdev, 0x68, 0x7C); + + /* Clearing PCI_STATUS error reflected here */ + writeq(BIT(62), &bar0->txpic_int_reg); + } + + /* Reset device statistics maintained by OS */ + memset(&sp->stats, 0, sizeof (struct net_device_stats)); + /* SXE-002: Configure link and activity LED to turn it off */ subid = sp->pdev->subsystem_device; - if ((subid & 0xFF) >= 0x07) { + if (((subid & 0xFF) >= 0x07) && + (sp->device_type == XFRAME_I_DEVICE)) { val64 = readq(&bar0->gpio_control); val64 |= 0x0000800000000000ULL; writeq(val64, &bar0->gpio_control); val64 = 0x0411040400000000ULL; - writeq(val64, (void __iomem *) bar0 + 0x2700); + writeq(val64, (void __iomem *) ((u8 *) bar0 + 0x2700)); + } + + /* + * Clear spurious ECC interrupts that would have occured on + * XFRAME II cards after reset. + */ + if (sp->device_type == XFRAME_II_DEVICE) { + val64 = readq(&bar0->pcc_err_reg); + writeq(val64, &bar0->pcc_err_reg); } sp->device_enabled_once = FALSE; } /** - * s2io_set_swapper - to set the swapper controle on the card - * @sp : private member of the device structure, + * s2io_set_swapper - to set the swapper controle on the card + * @sp : private member of the device structure, * pointer to the s2io_nic structure. - * Description: Function to set the swapper control on the card + * Description: Function to set the swapper control on the card * correctly depending on the 'endianness' of the system. * Return value: * SUCCESS on success and FAILURE on failure. */ -static int s2io_set_swapper(nic_t * sp) +int s2io_set_swapper(nic_t * sp) { struct net_device *dev = sp->dev; XENA_dev_config_t __iomem *bar0 = sp->bar0; u64 val64, valt, valr; - /* + /* * Set proper endian settings and verify the same by reading * the PIF Feed-back register. */ @@ -2505,8 +2914,9 @@ static int s2io_set_swapper(nic_t * sp) i++; } if(i == 4) { + unsigned long long x = val64; DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr "); - DBG_PRINT(ERR_DBG, "reads:0x%llx\n",val64); + DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x); return FAILURE; } } @@ -2514,8 +2924,8 @@ static int s2io_set_swapper(nic_t * sp) val64 &= 0xFFFF000000000000ULL; #ifdef __BIG_ENDIAN - /* - * The device by default set to a big endian format, so a + /* + * The device by default set to a big endian format, so a * big endian driver need not set anything. */ val64 |= (SWAPPER_CTRL_TXP_FE | @@ -2531,9 +2941,9 @@ static int s2io_set_swapper(nic_t * sp) SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); writeq(val64, &bar0->swapper_ctrl); #else - /* + /* * Initially we enable all bits to make it accessible by the - * driver, then we selectively enable only those bits that + * driver, then we selectively enable only those bits that * we want to set. */ val64 |= (SWAPPER_CTRL_TXP_FE | @@ -2555,8 +2965,8 @@ static int s2io_set_swapper(nic_t * sp) #endif val64 = readq(&bar0->swapper_ctrl); - /* - * Verifying if endian settings are accurate by reading a + /* + * Verifying if endian settings are accurate by reading a * feedback register. */ val64 = readq(&bar0->pif_rd_swapper_fb); @@ -2576,55 +2986,63 @@ static int s2io_set_swapper(nic_t * sp) * Functions defined below concern the OS part of the driver * * ********************************************************* */ -/** +/** * s2io_open - open entry point of the driver * @dev : pointer to the device structure. * Description: * This function is the open entry point of the driver. It mainly calls a * function to allocate Rx buffers and inserts them into the buffer - * descriptors and then enables the Rx part of the NIC. + * descriptors and then enables the Rx part of the NIC. * Return value: * 0 on success and an appropriate (-)ve integer as defined in errno.h * file on failure. */ -static int s2io_open(struct net_device *dev) +int s2io_open(struct net_device *dev) { nic_t *sp = dev->priv; int err = 0; - /* - * Make sure you have link off by default every time + /* + * Make sure you have link off by default every time * Nic is initialized */ netif_carrier_off(dev); - sp->last_link_state = LINK_DOWN; + sp->last_link_state = 0; /* Initialize H/W and enable interrupts */ if (s2io_card_up(sp)) { DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n", dev->name); - return -ENODEV; + err = -ENODEV; + goto hw_init_failed; } /* After proper initialization of H/W, register ISR */ - err = request_irq((int) sp->irq, s2io_isr, SA_SHIRQ, + err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ, sp->name, dev); if (err) { - s2io_reset(sp); DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", dev->name); - return err; + goto isr_registration_failed; } if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) { DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n"); - s2io_reset(sp); - return -ENODEV; + err = -ENODEV; + goto setting_mac_address_failed; } netif_start_queue(dev); return 0; + +setting_mac_address_failed: + free_irq(sp->pdev->irq, dev); +isr_registration_failed: + del_timer_sync(&sp->alarm_timer); + s2io_reset(sp); +hw_init_failed: + return err; } /** @@ -2640,16 +3058,15 @@ static int s2io_open(struct net_device *dev) * file on failure. */ -static int s2io_close(struct net_device *dev) +int s2io_close(struct net_device *dev) { nic_t *sp = dev->priv; - flush_scheduled_work(); netif_stop_queue(dev); /* Reset card, kill tasklet and free Tx and Rx buffers. */ s2io_card_down(sp); - free_irq(dev->irq, dev); + free_irq(sp->pdev->irq, dev); sp->device_close_flag = TRUE; /* Device is shut down. */ return 0; } @@ -2667,7 +3084,7 @@ static int s2io_close(struct net_device *dev) * 0 on success & 1 on failure. */ -static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) +int s2io_xmit(struct sk_buff *skb, struct net_device *dev) { nic_t *sp = dev->priv; u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off; @@ -2678,29 +3095,39 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) #ifdef NETIF_F_TSO int mss; #endif + u16 vlan_tag = 0; + int vlan_priority = 0; mac_info_t *mac_control; struct config_param *config; - XENA_dev_config_t __iomem *bar0 = sp->bar0; mac_control = &sp->mac_control; config = &sp->config; - DBG_PRINT(TX_DBG, "%s: In S2IO Tx routine\n", dev->name); + DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name); spin_lock_irqsave(&sp->tx_lock, flags); - if (atomic_read(&sp->card_state) == CARD_DOWN) { - DBG_PRINT(ERR_DBG, "%s: Card going down for reset\n", + DBG_PRINT(TX_DBG, "%s: Card going down for reset\n", dev->name); spin_unlock_irqrestore(&sp->tx_lock, flags); - return 1; + dev_kfree_skb(skb); + return 0; } queue = 0; - put_off = (u16) mac_control->tx_curr_put_info[queue].offset; - get_off = (u16) mac_control->tx_curr_get_info[queue].offset; - txdp = (TxD_t *) sp->list_info[queue][put_off].list_virt_addr; - queue_len = mac_control->tx_curr_put_info[queue].fifo_len + 1; + /* Get Fifo number to Transmit based on vlan priority */ + if (sp->vlgrp && vlan_tx_tag_present(skb)) { + vlan_tag = vlan_tx_tag_get(skb); + vlan_priority = vlan_tag >> 13; + queue = config->fifo_mapping[vlan_priority]; + } + + put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset; + get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset; + txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off]. + list_virt_addr; + + queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1; /* Avoid "put" pointer going beyond "get" pointer */ if (txdp->Host_Control || (((put_off + 1) % queue_len) == get_off)) { DBG_PRINT(ERR_DBG, "Error in xmit, No free TXDs.\n"); @@ -2709,6 +3136,15 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&sp->tx_lock, flags); return 0; } + + /* A buffer with no data will be dropped */ + if (!skb->len) { + DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name); + dev_kfree_skb(skb); + spin_unlock_irqrestore(&sp->tx_lock, flags); + return 0; + } + #ifdef NETIF_F_TSO mss = skb_shinfo(skb)->tso_size; if (mss) { @@ -2720,9 +3156,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) frg_cnt = skb_shinfo(skb)->nr_frags; frg_len = skb->len - skb->data_len; - txdp->Host_Control = (unsigned long) skb; txdp->Buffer_Pointer = pci_map_single (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE); + txdp->Host_Control = (unsigned long) skb; if (skb->ip_summed == CHECKSUM_HW) { txdp->Control_2 |= (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN | @@ -2731,6 +3167,11 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) txdp->Control_2 |= config->tx_intr_type; + if (sp->vlgrp && vlan_tx_tag_present(skb)) { + txdp->Control_2 |= TXD_VLAN_ENABLE; + txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag); + } + txdp->Control_1 |= (TXD_BUFFER0_SIZE(frg_len) | TXD_GATHER_CODE_FIRST); txdp->Control_1 |= TXD_LIST_OWN_XENA; @@ -2738,6 +3179,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) /* For fragmented SKB. */ for (i = 0; i < frg_cnt; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + /* A '0' length fragment will be ignored */ + if (!frag->size) + continue; txdp++; txdp->Buffer_Pointer = (u64) pci_map_page (sp->pdev, frag->page, frag->page_offset, @@ -2747,23 +3191,23 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) txdp->Control_1 |= TXD_GATHER_CODE_LAST; tx_fifo = mac_control->tx_FIFO_start[queue]; - val64 = sp->list_info[queue][put_off].list_phy_addr; + val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr; writeq(val64, &tx_fifo->TxDL_Pointer); val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST | TX_FIFO_LAST_LIST); + #ifdef NETIF_F_TSO if (mss) val64 |= TX_FIFO_SPECIAL_FUNC; #endif writeq(val64, &tx_fifo->List_Control); - /* Perform a PCI read to flush previous writes */ - val64 = readq(&bar0->general_int_status); + mmiowb(); put_off++; - put_off %= mac_control->tx_curr_put_info[queue].fifo_len + 1; - mac_control->tx_curr_put_info[queue].offset = put_off; + put_off %= mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1; + mac_control->fifos[queue].tx_curr_put_info.offset = put_off; /* Avoid "put" pointer going beyond "get" pointer */ if (((put_off + 1) % queue_len) == get_off) { @@ -2779,18 +3223,74 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } +static void +s2io_alarm_handle(unsigned long data) +{ + nic_t *sp = (nic_t *)data; + + alarm_intr_handler(sp); + mod_timer(&sp->alarm_timer, jiffies + HZ / 2); +} + +static void s2io_txpic_intr_handle(nic_t *sp) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) sp->bar0; + u64 val64; + + val64 = readq(&bar0->pic_int_status); + if (val64 & PIC_INT_GPIO) { + val64 = readq(&bar0->gpio_int_reg); + if ((val64 & GPIO_INT_REG_LINK_DOWN) && + (val64 & GPIO_INT_REG_LINK_UP)) { + val64 |= GPIO_INT_REG_LINK_DOWN; + val64 |= GPIO_INT_REG_LINK_UP; + writeq(val64, &bar0->gpio_int_reg); + goto masking; + } + + if (((sp->last_link_state == LINK_UP) && + (val64 & GPIO_INT_REG_LINK_DOWN)) || + ((sp->last_link_state == LINK_DOWN) && + (val64 & GPIO_INT_REG_LINK_UP))) { + val64 = readq(&bar0->gpio_int_mask); + val64 |= GPIO_INT_MASK_LINK_DOWN; + val64 |= GPIO_INT_MASK_LINK_UP; + writeq(val64, &bar0->gpio_int_mask); + s2io_set_link((unsigned long)sp); + } +masking: + if (sp->last_link_state == LINK_UP) { + /*enable down interrupt */ + val64 = readq(&bar0->gpio_int_mask); + /* unmasks link down intr */ + val64 &= ~GPIO_INT_MASK_LINK_DOWN; + /* masks link up intr */ + val64 |= GPIO_INT_MASK_LINK_UP; + writeq(val64, &bar0->gpio_int_mask); + } else { + /*enable UP Interrupt */ + val64 = readq(&bar0->gpio_int_mask); + /* unmasks link up interrupt */ + val64 &= ~GPIO_INT_MASK_LINK_UP; + /* masks link down interrupt */ + val64 |= GPIO_INT_MASK_LINK_DOWN; + writeq(val64, &bar0->gpio_int_mask); + } + } +} + /** * s2io_isr - ISR handler of the device . * @irq: the irq of the device. * @dev_id: a void pointer to the dev structure of the NIC. * @pt_regs: pointer to the registers pushed on the stack. - * Description: This function is the ISR handler of the device. It - * identifies the reason for the interrupt and calls the relevant - * service routines. As a contongency measure, this ISR allocates the + * Description: This function is the ISR handler of the device. It + * identifies the reason for the interrupt and calls the relevant + * service routines. As a contongency measure, this ISR allocates the * recv buffers, if their numbers are below the panic value which is * presently set to 25% of the original number of rcv buffers allocated. * Return value: - * IRQ_HANDLED: will be returned if IRQ was handled by this routine + * IRQ_HANDLED: will be returned if IRQ was handled by this routine * IRQ_NONE: will be returned if interrupt is not from our device */ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs) @@ -2798,40 +3298,31 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs) struct net_device *dev = (struct net_device *) dev_id; nic_t *sp = dev->priv; XENA_dev_config_t __iomem *bar0 = sp->bar0; -#ifndef CONFIG_S2IO_NAPI - int i, ret; -#endif - u64 reason = 0; + int i; + u64 reason = 0, val64; mac_info_t *mac_control; struct config_param *config; + atomic_inc(&sp->isr_cnt); mac_control = &sp->mac_control; config = &sp->config; - /* + /* * Identify the cause for interrupt and call the appropriate * interrupt handler. Causes for the interrupt could be; * 1. Rx of packet. * 2. Tx complete. * 3. Link down. - * 4. Error in any functional blocks of the NIC. + * 4. Error in any functional blocks of the NIC. */ reason = readq(&bar0->general_int_status); if (!reason) { /* The interrupt was not raised by Xena. */ + atomic_dec(&sp->isr_cnt); return IRQ_NONE; } - /* If Intr is because of Tx Traffic */ - if (reason & GEN_INTR_TXTRAFFIC) { - tx_intr_handler(sp); - } - - /* If Intr is because of an error */ - if (reason & (GEN_ERROR_INTR)) - alarm_intr_handler(sp); - #ifdef CONFIG_S2IO_NAPI if (reason & GEN_INTR_RXTRAFFIC) { if (netif_rx_schedule_prep(dev)) { @@ -2843,17 +3334,43 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs) #else /* If Intr is because of Rx Traffic */ if (reason & GEN_INTR_RXTRAFFIC) { - rx_intr_handler(sp); + /* + * rx_traffic_int reg is an R1 register, writing all 1's + * will ensure that the actual interrupt causing bit get's + * cleared and hence a read can be avoided. + */ + val64 = 0xFFFFFFFFFFFFFFFFULL; + writeq(val64, &bar0->rx_traffic_int); + for (i = 0; i < config->rx_ring_num; i++) { + rx_intr_handler(&mac_control->rings[i]); + } } #endif - /* - * If the Rx buffer count is below the panic threshold then - * reallocate the buffers from the interrupt handler itself, + /* If Intr is because of Tx Traffic */ + if (reason & GEN_INTR_TXTRAFFIC) { + /* + * tx_traffic_int reg is an R1 register, writing all 1's + * will ensure that the actual interrupt causing bit get's + * cleared and hence a read can be avoided. + */ + val64 = 0xFFFFFFFFFFFFFFFFULL; + writeq(val64, &bar0->tx_traffic_int); + + for (i = 0; i < config->tx_fifo_num; i++) + tx_intr_handler(&mac_control->fifos[i]); + } + + if (reason & GEN_INTR_TXPIC) + s2io_txpic_intr_handle(sp); + /* + * If the Rx buffer count is below the panic threshold then + * reallocate the buffers from the interrupt handler itself, * else schedule a tasklet to reallocate the buffers. */ #ifndef CONFIG_S2IO_NAPI for (i = 0; i < config->rx_ring_num; i++) { + int ret; int rxb_size = atomic_read(&sp->rx_bufs_left[i]); int level = rx_buffer_level(sp, rxb_size, i); @@ -2865,6 +3382,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs) dev->name); DBG_PRINT(ERR_DBG, " in ISR!!\n"); clear_bit(0, (&sp->tasklet_status)); + atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } clear_bit(0, (&sp->tasklet_status)); @@ -2874,33 +3392,69 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs) } #endif + atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } /** - * s2io_get_stats - Updates the device statistics structure. + * s2io_updt_stats - + */ +static void s2io_updt_stats(nic_t *sp) +{ + XENA_dev_config_t __iomem *bar0 = sp->bar0; + u64 val64; + int cnt = 0; + + if (atomic_read(&sp->card_state) == CARD_UP) { + /* Apprx 30us on a 133 MHz bus */ + val64 = SET_UPDT_CLICKS(10) | + STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN; + writeq(val64, &bar0->stat_cfg); + do { + udelay(100); + val64 = readq(&bar0->stat_cfg); + if (!(val64 & BIT(0))) + break; + cnt++; + if (cnt == 5) + break; /* Updt failed */ + } while(1); + } +} + +/** + * s2io_get_stats - Updates the device statistics structure. * @dev : pointer to the device structure. * Description: - * This function updates the device statistics structure in the s2io_nic + * This function updates the device statistics structure in the s2io_nic * structure and returns a pointer to the same. * Return value: * pointer to the updated net_device_stats structure. */ -static struct net_device_stats *s2io_get_stats(struct net_device *dev) +struct net_device_stats *s2io_get_stats(struct net_device *dev) { nic_t *sp = dev->priv; mac_info_t *mac_control; struct config_param *config; + mac_control = &sp->mac_control; config = &sp->config; - sp->stats.tx_errors = mac_control->stats_info->tmac_any_err_frms; - sp->stats.rx_errors = mac_control->stats_info->rmac_drop_frms; - sp->stats.multicast = mac_control->stats_info->rmac_vld_mcst_frms; + /* Configure Stats for immediate updt */ + s2io_updt_stats(sp); + + sp->stats.tx_packets = + le32_to_cpu(mac_control->stats_info->tmac_frms); + sp->stats.tx_errors = + le32_to_cpu(mac_control->stats_info->tmac_any_err_frms); + sp->stats.rx_errors = + le32_to_cpu(mac_control->stats_info->rmac_drop_frms); + sp->stats.multicast = + le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms); sp->stats.rx_length_errors = - mac_control->stats_info->rmac_long_frms; + le32_to_cpu(mac_control->stats_info->rmac_long_frms); return (&sp->stats); } @@ -2909,8 +3463,8 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev) * s2io_set_multicast - entry point for multicast address enable/disable. * @dev : pointer to the device structure * Description: - * This function is a driver entry point which gets called by the kernel - * whenever multicast addresses must be enabled/disabled. This also gets + * This function is a driver entry point which gets called by the kernel + * whenever multicast addresses must be enabled/disabled. This also gets * called to set/reset promiscuous mode. Depending on the deivce flag, we * determine, if multicast address must be enabled or if promiscuous mode * is to be disabled etc. @@ -2948,6 +3502,8 @@ static void s2io_set_multicast(struct net_device *dev) /* Disable all Multicast addresses */ writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr), &bar0->rmac_addr_data0_mem); + writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0), + &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos); @@ -3010,7 +3566,7 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr), &bar0->rmac_addr_data0_mem); writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL), - &bar0->rmac_addr_data1_mem); + &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET @@ -3039,8 +3595,7 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr), &bar0->rmac_addr_data0_mem); writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL), - &bar0->rmac_addr_data1_mem); - + &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET @@ -3059,12 +3614,12 @@ static void s2io_set_multicast(struct net_device *dev) } /** - * s2io_set_mac_addr - Programs the Xframe mac address + * s2io_set_mac_addr - Programs the Xframe mac address * @dev : pointer to the device structure. * @addr: a uchar pointer to the new mac address which is to be set. - * Description : This procedure will program the Xframe to receive + * Description : This procedure will program the Xframe to receive * frames with new Mac Address - * Return value: SUCCESS on success and an appropriate (-)ve integer + * Return value: SUCCESS on success and an appropriate (-)ve integer * as defined in errno.h file on failure. */ @@ -3075,10 +3630,10 @@ int s2io_set_mac_addr(struct net_device *dev, u8 * addr) register u64 val64, mac_addr = 0; int i; - /* + /* * Set the new MAC address as the new unicast filter and reflect this * change on the device address registered with the OS. It will be - * at offset 0. + * at offset 0. */ for (i = 0; i < ETH_ALEN; i++) { mac_addr <<= 8; @@ -3102,12 +3657,12 @@ int s2io_set_mac_addr(struct net_device *dev, u8 * addr) } /** - * s2io_ethtool_sset - Sets different link parameters. + * s2io_ethtool_sset - Sets different link parameters. * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @info: pointer to the structure with parameters given by ethtool to set * link information. * Description: - * The function sets different link parameters provided by the user onto + * The function sets different link parameters provided by the user onto * the NIC. * Return value: * 0 on success. @@ -3129,7 +3684,7 @@ static int s2io_ethtool_sset(struct net_device *dev, } /** - * s2io_ethtol_gset - Return link specific information. + * s2io_ethtol_gset - Return link specific information. * @sp : private member of the device structure, pointer to the * s2io_nic structure. * @info : pointer to the structure with parameters given by ethtool @@ -3161,8 +3716,8 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) } /** - * s2io_ethtool_gdrvinfo - Returns driver specific information. - * @sp : private member of the device structure, which is a pointer to the + * s2io_ethtool_gdrvinfo - Returns driver specific information. + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @info : pointer to the structure with parameters given by ethtool to * return driver information. @@ -3190,9 +3745,9 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev, /** * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer. - * @sp: private member of the device structure, which is a pointer to the + * @sp: private member of the device structure, which is a pointer to the * s2io_nic structure. - * @regs : pointer to the structure with parameters given by ethtool for + * @regs : pointer to the structure with parameters given by ethtool for * dumping the registers. * @reg_space: The input argumnet into which all the registers are dumped. * Description: @@ -3221,11 +3776,11 @@ static void s2io_ethtool_gregs(struct net_device *dev, /** * s2io_phy_id - timer function that alternates adapter LED. - * @data : address of the private member of the device structure, which + * @data : address of the private member of the device structure, which * is a pointer to the s2io_nic structure, provided as an u32. - * Description: This is actually the timer function that alternates the - * adapter LED bit of the adapter control bit to set/reset every time on - * invocation. The timer is set for 1/2 a second, hence tha NIC blinks + * Description: This is actually the timer function that alternates the + * adapter LED bit of the adapter control bit to set/reset every time on + * invocation. The timer is set for 1/2 a second, hence tha NIC blinks * once every second. */ static void s2io_phy_id(unsigned long data) @@ -3236,7 +3791,8 @@ static void s2io_phy_id(unsigned long data) u16 subid; subid = sp->pdev->subsystem_device; - if ((subid & 0xFF) >= 0x07) { + if ((sp->device_type == XFRAME_II_DEVICE) || + ((subid & 0xFF) >= 0x07)) { val64 = readq(&bar0->gpio_control); val64 ^= GPIO_CTRL_GPIO_0; writeq(val64, &bar0->gpio_control); @@ -3253,12 +3809,12 @@ static void s2io_phy_id(unsigned long data) * s2io_ethtool_idnic - To physically identify the nic on the system. * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. - * @id : pointer to the structure with identification parameters given by + * @id : pointer to the structure with identification parameters given by * ethtool. * Description: Used to physically identify the NIC on the system. - * The Link LED will blink for a time specified by the user for + * The Link LED will blink for a time specified by the user for * identification. - * NOTE: The Link has to be Up to be able to blink the LED. Hence + * NOTE: The Link has to be Up to be able to blink the LED. Hence * identification is possible only if it's link is up. * Return value: * int , returns 0 on success @@ -3273,7 +3829,8 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) subid = sp->pdev->subsystem_device; last_gpio_ctrl_val = readq(&bar0->gpio_control); - if ((subid & 0xFF) < 0x07) { + if ((sp->device_type == XFRAME_I_DEVICE) && + ((subid & 0xFF) < 0x07)) { val64 = readq(&bar0->adapter_control); if (!(val64 & ADAPTER_CNTL_EN)) { printk(KERN_ERR @@ -3288,12 +3845,12 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) } mod_timer(&sp->id_timer, jiffies); if (data) - msleep(data * 1000); + msleep_interruptible(data * HZ); else - msleep(0xFFFFFFFF); + msleep_interruptible(MAX_FLICKER_TIME); del_timer_sync(&sp->id_timer); - if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) { + if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) { writeq(last_gpio_ctrl_val, &bar0->gpio_control); last_gpio_ctrl_val = readq(&bar0->gpio_control); } @@ -3303,7 +3860,8 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) /** * s2io_ethtool_getpause_data -Pause frame frame generation and reception. - * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. + * @sp : private member of the device structure, which is a pointer to the + * s2io_nic structure. * @ep : pointer to the structure with pause parameters given by ethtool. * Description: * Returns the Pause frame generation and reception capability of the NIC. @@ -3327,7 +3885,7 @@ static void s2io_ethtool_getpause_data(struct net_device *dev, /** * s2io_ethtool_setpause_data - set/reset pause frame generation. - * @sp : private member of the device structure, which is a pointer to the + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @ep : pointer to the structure with pause parameters given by ethtool. * Description: @@ -3338,7 +3896,7 @@ static void s2io_ethtool_getpause_data(struct net_device *dev, */ static int s2io_ethtool_setpause_data(struct net_device *dev, - struct ethtool_pauseparam *ep) + struct ethtool_pauseparam *ep) { u64 val64; nic_t *sp = dev->priv; @@ -3359,13 +3917,13 @@ static int s2io_ethtool_setpause_data(struct net_device *dev, /** * read_eeprom - reads 4 bytes of data from user given offset. - * @sp : private member of the device structure, which is a pointer to the + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @off : offset at which the data must be written * @data : Its an output parameter where the data read at the given - * offset is stored. + * offset is stored. * Description: - * Will read 4 bytes of data from the user given offset and return the + * Will read 4 bytes of data from the user given offset and return the * read data. * NOTE: Will allow to read only part of the EEPROM visible through the * I2C bus. @@ -3406,7 +3964,7 @@ static int read_eeprom(nic_t * sp, int off, u32 * data) * s2io_nic structure. * @off : offset at which the data must be written * @data : The data that is to be written - * @cnt : Number of bytes of the data that are actually to be written into + * @cnt : Number of bytes of the data that are actually to be written into * the Eeprom. (max of 3) * Description: * Actually writes the relevant part of the data value into the Eeprom @@ -3443,7 +4001,7 @@ static int write_eeprom(nic_t * sp, int off, u32 data, int cnt) /** * s2io_ethtool_geeprom - reads the value stored in the Eeprom. * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. - * @eeprom : pointer to the user level structure provided by ethtool, + * @eeprom : pointer to the user level structure provided by ethtool, * containing all relevant information. * @data_buf : user defined value to be written into Eeprom. * Description: Reads the values stored in the Eeprom at given offset @@ -3454,7 +4012,7 @@ static int write_eeprom(nic_t * sp, int off, u32 data, int cnt) */ static int s2io_ethtool_geeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 * data_buf) + struct ethtool_eeprom *eeprom, u8 * data_buf) { u32 data, i, valid; nic_t *sp = dev->priv; @@ -3479,7 +4037,7 @@ static int s2io_ethtool_geeprom(struct net_device *dev, * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. - * @eeprom : pointer to the user level structure provided by ethtool, + * @eeprom : pointer to the user level structure provided by ethtool, * containing all relevant information. * @data_buf ; user defined value to be written into Eeprom. * Description: @@ -3527,8 +4085,8 @@ static int s2io_ethtool_seeprom(struct net_device *dev, } /** - * s2io_register_test - reads and writes into all clock domains. - * @sp : private member of the device structure, which is a pointer to the + * s2io_register_test - reads and writes into all clock domains. + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @data : variable that returns the result of each of the test conducted b * by the driver. @@ -3545,8 +4103,8 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) u64 val64 = 0; int fail = 0; - val64 = readq(&bar0->pcc_enable); - if (val64 != 0xff00000000000000ULL) { + val64 = readq(&bar0->pif_rd_swapper_fb); + if (val64 != 0x123456789abcdefULL) { fail = 1; DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n"); } @@ -3590,13 +4148,13 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) } /** - * s2io_eeprom_test - to verify that EEprom in the xena can be programmed. + * s2io_eeprom_test - to verify that EEprom in the xena can be programmed. * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @data:variable that returns the result of each of the test conducted by * the driver. * Description: - * Verify that EEPROM in the xena can be programmed using I2C_CONTROL + * Verify that EEPROM in the xena can be programmed using I2C_CONTROL * register. * Return value: * 0 on success. @@ -3661,14 +4219,14 @@ static int s2io_eeprom_test(nic_t * sp, uint64_t * data) /** * s2io_bist_test - invokes the MemBist test of the card . - * @sp : private member of the device structure, which is a pointer to the + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. - * @data:variable that returns the result of each of the test conducted by + * @data:variable that returns the result of each of the test conducted by * the driver. * Description: * This invokes the MemBist test of the card. We give around * 2 secs time for the Test to complete. If it's still not complete - * within this peiod, we consider that the test failed. + * within this peiod, we consider that the test failed. * Return value: * 0 on success and -1 on failure. */ @@ -3697,13 +4255,13 @@ static int s2io_bist_test(nic_t * sp, uint64_t * data) } /** - * s2io-link_test - verifies the link state of the nic - * @sp ; private member of the device structure, which is a pointer to the + * s2io-link_test - verifies the link state of the nic + * @sp ; private member of the device structure, which is a pointer to the * s2io_nic structure. * @data: variable that returns the result of each of the test conducted by * the driver. * Description: - * The function verifies the link state of the NIC and updates the input + * The function verifies the link state of the NIC and updates the input * argument 'data' appropriately. * Return value: * 0 on success. @@ -3722,13 +4280,13 @@ static int s2io_link_test(nic_t * sp, uint64_t * data) } /** - * s2io_rldram_test - offline test for access to the RldRam chip on the NIC - * @sp - private member of the device structure, which is a pointer to the + * s2io_rldram_test - offline test for access to the RldRam chip on the NIC + * @sp - private member of the device structure, which is a pointer to the * s2io_nic structure. - * @data - variable that returns the result of each of the test + * @data - variable that returns the result of each of the test * conducted by the driver. * Description: - * This is one of the offline test that tests the read and write + * This is one of the offline test that tests the read and write * access to the RldRam chip on the NIC. * Return value: * 0 on success. @@ -3833,7 +4391,7 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) * s2io_nic structure. * @ethtest : pointer to a ethtool command specific structure that will be * returned to the user. - * @data : variable that returns the result of each of the test + * @data : variable that returns the result of each of the test * conducted by the driver. * Description: * This function conducts 6 tests ( 4 offline and 2 online) to determine @@ -3851,23 +4409,18 @@ static void s2io_ethtool_test(struct net_device *dev, if (ethtest->flags == ETH_TEST_FL_OFFLINE) { /* Offline Tests. */ - if (orig_state) { + if (orig_state) s2io_close(sp->dev); - s2io_set_swapper(sp); - } else - s2io_set_swapper(sp); if (s2io_register_test(sp, &data[0])) ethtest->flags |= ETH_TEST_FL_FAILED; s2io_reset(sp); - s2io_set_swapper(sp); if (s2io_rldram_test(sp, &data[3])) ethtest->flags |= ETH_TEST_FL_FAILED; s2io_reset(sp); - s2io_set_swapper(sp); if (s2io_eeprom_test(sp, &data[1])) ethtest->flags |= ETH_TEST_FL_FAILED; @@ -3910,61 +4463,111 @@ static void s2io_get_ethtool_stats(struct net_device *dev, nic_t *sp = dev->priv; StatInfo_t *stat_info = sp->mac_control.stats_info; - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_data_octets); + s2io_updt_stats(sp); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32 | + le32_to_cpu(stat_info->tmac_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 | + le32_to_cpu(stat_info->tmac_data_octets); tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_mcst_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_bcst_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 | + le32_to_cpu(stat_info->tmac_mcst_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 | + le32_to_cpu(stat_info->tmac_bcst_frms); tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_any_err_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 | + le32_to_cpu(stat_info->tmac_any_err_frms); tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_vld_ip); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_drop_ip); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_icmp); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_rst_tcp); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 | + le32_to_cpu(stat_info->tmac_vld_ip); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 | + le32_to_cpu(stat_info->tmac_drop_ip); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 | + le32_to_cpu(stat_info->tmac_icmp); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 | + le32_to_cpu(stat_info->tmac_rst_tcp); tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_udp); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_data_octets); + tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 | + le32_to_cpu(stat_info->tmac_udp); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_vld_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 | + le32_to_cpu(stat_info->rmac_data_octets); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_mcst_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_bcst_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_vld_mcst_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_vld_bcst_frms); tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_discarded_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_usized_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_osized_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_frag_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_jabber_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ip); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_discarded_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_usized_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_osized_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_frag_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_jabber_frms); + tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 | + le32_to_cpu(stat_info->rmac_ip); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets); tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_drop_ip); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_icmp); + tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 | + le32_to_cpu(stat_info->rmac_drop_ip); + tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 | + le32_to_cpu(stat_info->rmac_icmp); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_udp); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_drp_udp); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pause_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_accepted_ip); + tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 | + le32_to_cpu(stat_info->rmac_udp); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 | + le32_to_cpu(stat_info->rmac_err_drp_udp); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 | + le32_to_cpu(stat_info->rmac_pause_cnt); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 | + le32_to_cpu(stat_info->rmac_accepted_ip); tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp); + tmp_stats[i++] = 0; + tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs; + tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs; } -static int s2io_ethtool_get_regs_len(struct net_device *dev) +int s2io_ethtool_get_regs_len(struct net_device *dev) { return (XENA_REG_SPACE); } -static u32 s2io_ethtool_get_rx_csum(struct net_device * dev) +u32 s2io_ethtool_get_rx_csum(struct net_device * dev) { nic_t *sp = dev->priv; return (sp->rx_csum); } - -static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) +int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) { nic_t *sp = dev->priv; @@ -3975,19 +4578,17 @@ static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) return 0; } - -static int s2io_get_eeprom_len(struct net_device *dev) +int s2io_get_eeprom_len(struct net_device *dev) { return (XENA_EEPROM_SPACE); } -static int s2io_ethtool_self_test_count(struct net_device *dev) +int s2io_ethtool_self_test_count(struct net_device *dev) { return (S2IO_TEST_LEN); } - -static void s2io_ethtool_get_strings(struct net_device *dev, - u32 stringset, u8 * data) +void s2io_ethtool_get_strings(struct net_device *dev, + u32 stringset, u8 * data) { switch (stringset) { case ETH_SS_TEST: @@ -3998,13 +4599,12 @@ static void s2io_ethtool_get_strings(struct net_device *dev, sizeof(ethtool_stats_keys)); } } - static int s2io_ethtool_get_stats_count(struct net_device *dev) { return (S2IO_STAT_LEN); } -static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) +int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) { if (data) dev->features |= NETIF_F_IP_CSUM; @@ -4046,21 +4646,18 @@ static struct ethtool_ops netdev_ethtool_ops = { }; /** - * s2io_ioctl - Entry point for the Ioctl + * s2io_ioctl - Entry point for the Ioctl * @dev : Device pointer. * @ifr : An IOCTL specefic structure, that can contain a pointer to * a proprietary structure used to pass information to the driver. * @cmd : This is used to distinguish between the different commands that * can be passed to the IOCTL functions. * Description: - * This function has support for ethtool, adding multiple MAC addresses on - * the NIC and some DBG commands for the util tool. - * Return value: - * Currently the IOCTL supports no operations, hence by default this - * function returns OP NOT SUPPORTED value. + * Currently there are no special functionality supported in IOCTL, hence + * function always return EOPNOTSUPPORTED */ -static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { return -EOPNOTSUPP; } @@ -4076,17 +4673,9 @@ static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) * file on failure. */ -static int s2io_change_mtu(struct net_device *dev, int new_mtu) +int s2io_change_mtu(struct net_device *dev, int new_mtu) { nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; - register u64 val64; - - if (netif_running(dev)) { - DBG_PRINT(ERR_DBG, "%s: Must be stopped to ", dev->name); - DBG_PRINT(ERR_DBG, "change its MTU \n"); - return -EBUSY; - } if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) { DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n", @@ -4094,11 +4683,22 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu) return -EPERM; } - /* Set the new MTU into the PYLD register of the NIC */ - val64 = new_mtu; - writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len); - dev->mtu = new_mtu; + if (netif_running(dev)) { + s2io_card_down(sp); + netif_stop_queue(dev); + if (s2io_card_up(sp)) { + DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n", + __FUNCTION__); + } + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + } else { /* Device is down */ + XENA_dev_config_t __iomem *bar0 = sp->bar0; + u64 val64 = new_mtu; + + writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len); + } return 0; } @@ -4108,9 +4708,9 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu) * @dev_adr : address of the device structure in dma_addr_t format. * Description: * This is the tasklet or the bottom half of the ISR. This is - * an extension of the ISR which is scheduled by the scheduler to be run + * an extension of the ISR which is scheduled by the scheduler to be run * when the load on the CPU is low. All low priority tasks of the ISR can - * be pushed into the tasklet. For now the tasklet is used only to + * be pushed into the tasklet. For now the tasklet is used only to * replenish the Rx buffers in the Rx buffer descriptors. * Return value: * void. @@ -4166,19 +4766,22 @@ static void s2io_set_link(unsigned long data) } subid = nic->pdev->subsystem_device; - /* - * Allow a small delay for the NICs self initiated - * cleanup to complete. - */ - msleep(100); + if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) { + /* + * Allow a small delay for the NICs self initiated + * cleanup to complete. + */ + msleep(100); + } val64 = readq(&bar0->adapter_status); - if (verify_xena_quiescence(val64, nic->device_enabled_once)) { + if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) { if (LINK_IS_UP(val64)) { val64 = readq(&bar0->adapter_control); val64 |= ADAPTER_CNTL_EN; writeq(val64, &bar0->adapter_control); - if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) { + if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type, + subid)) { val64 = readq(&bar0->gpio_control); val64 |= GPIO_CTRL_GPIO_0; writeq(val64, &bar0->gpio_control); @@ -4187,20 +4790,24 @@ static void s2io_set_link(unsigned long data) val64 |= ADAPTER_LED_ON; writeq(val64, &bar0->adapter_control); } - val64 = readq(&bar0->adapter_status); - if (!LINK_IS_UP(val64)) { - DBG_PRINT(ERR_DBG, "%s:", dev->name); - DBG_PRINT(ERR_DBG, " Link down"); - DBG_PRINT(ERR_DBG, "after "); - DBG_PRINT(ERR_DBG, "enabling "); - DBG_PRINT(ERR_DBG, "device \n"); + if (s2io_link_fault_indication(nic) == + MAC_RMAC_ERR_TIMER) { + val64 = readq(&bar0->adapter_status); + if (!LINK_IS_UP(val64)) { + DBG_PRINT(ERR_DBG, "%s:", dev->name); + DBG_PRINT(ERR_DBG, " Link down"); + DBG_PRINT(ERR_DBG, "after "); + DBG_PRINT(ERR_DBG, "enabling "); + DBG_PRINT(ERR_DBG, "device \n"); + } } if (nic->device_enabled_once == FALSE) { nic->device_enabled_once = TRUE; } s2io_link(nic, LINK_UP); } else { - if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) { + if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type, + subid)) { val64 = readq(&bar0->gpio_control); val64 &= ~GPIO_CTRL_GPIO_0; writeq(val64, &bar0->gpio_control); @@ -4223,9 +4830,11 @@ static void s2io_card_down(nic_t * sp) unsigned long flags; register u64 val64 = 0; + del_timer_sync(&sp->alarm_timer); /* If s2io_set_link task is executing, wait till it completes. */ - while (test_and_set_bit(0, &(sp->link_state))) + while (test_and_set_bit(0, &(sp->link_state))) { msleep(50); + } atomic_set(&sp->card_state, CARD_DOWN); /* disable Tx and Rx traffic on the NIC */ @@ -4237,7 +4846,7 @@ static void s2io_card_down(nic_t * sp) /* Check if the device is Quiescent and then Reset the NIC */ do { val64 = readq(&bar0->adapter_status); - if (verify_xena_quiescence(val64, sp->device_enabled_once)) { + if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) { break; } @@ -4251,14 +4860,27 @@ static void s2io_card_down(nic_t * sp) break; } } while (1); - spin_lock_irqsave(&sp->tx_lock, flags); s2io_reset(sp); - /* Free all unused Tx and Rx buffers */ + /* Waiting till all Interrupt handlers are complete */ + cnt = 0; + do { + msleep(10); + if (!atomic_read(&sp->isr_cnt)) + break; + cnt++; + } while(cnt < 5); + + spin_lock_irqsave(&sp->tx_lock, flags); + /* Free all Tx buffers */ free_tx_buffers(sp); + spin_unlock_irqrestore(&sp->tx_lock, flags); + + /* Free all Rx buffers */ + spin_lock_irqsave(&sp->rx_lock, flags); free_rx_buffers(sp); + spin_unlock_irqrestore(&sp->rx_lock, flags); - spin_unlock_irqrestore(&sp->tx_lock, flags); clear_bit(0, &(sp->link_state)); } @@ -4276,8 +4898,8 @@ static int s2io_card_up(nic_t * sp) return -ENODEV; } - /* - * Initializing the Rx buffers. For now we are considering only 1 + /* + * Initializing the Rx buffers. For now we are considering only 1 * Rx ring and initializing buffers into 30 Rx blocks */ mac_control = &sp->mac_control; @@ -4311,16 +4933,18 @@ static int s2io_card_up(nic_t * sp) return -ENODEV; } + S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2)); + atomic_set(&sp->card_state, CARD_UP); return 0; } -/** +/** * s2io_restart_nic - Resets the NIC. * @data : long pointer to the device private structure * Description: * This function is scheduled to be run by the s2io_tx_watchdog - * function after 0.5 secs to reset the NIC. The idea is to reduce + * function after 0.5 secs to reset the NIC. The idea is to reduce * the run time of the watch dog routine which is run holding a * spin lock. */ @@ -4338,10 +4962,11 @@ static void s2io_restart_nic(unsigned long data) netif_wake_queue(dev); DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n", dev->name); + } -/** - * s2io_tx_watchdog - Watchdog for transmit side. +/** + * s2io_tx_watchdog - Watchdog for transmit side. * @dev : Pointer to net device structure * Description: * This function is triggered if the Tx Queue is stopped @@ -4369,7 +4994,7 @@ static void s2io_tx_watchdog(struct net_device *dev) * @len : length of the packet * @cksum : FCS checksum of the frame. * @ring_no : the ring from which this RxD was extracted. - * Description: + * Description: * This function is called by the Tx interrupt serivce routine to perform * some OS related operations on the SKB before passing it to the upper * layers. It mainly checks if the checksum is OK, if so adds it to the @@ -4379,35 +5004,68 @@ static void s2io_tx_watchdog(struct net_device *dev) * Return value: * SUCCESS on success and -1 on failure. */ -#ifndef CONFIG_2BUFF_MODE -static int rx_osm_handler(nic_t * sp, u16 len, RxD_t * rxdp, int ring_no) -#else -static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no, - buffAdd_t * ba) -#endif +static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) { + nic_t *sp = ring_data->nic; struct net_device *dev = (struct net_device *) sp->dev; - struct sk_buff *skb = - (struct sk_buff *) ((unsigned long) rxdp->Host_Control); + struct sk_buff *skb = (struct sk_buff *) + ((unsigned long) rxdp->Host_Control); + int ring_no = ring_data->ring_no; u16 l3_csum, l4_csum; #ifdef CONFIG_2BUFF_MODE - int buf0_len, buf2_len; + int buf0_len = RXD_GET_BUFFER0_SIZE(rxdp->Control_2); + int buf2_len = RXD_GET_BUFFER2_SIZE(rxdp->Control_2); + int get_block = ring_data->rx_curr_get_info.block_index; + int get_off = ring_data->rx_curr_get_info.offset; + buffAdd_t *ba = &ring_data->ba[get_block][get_off]; unsigned char *buff; +#else + u16 len = (u16) ((RXD_GET_BUFFER0_SIZE(rxdp->Control_2)) >> 48);; #endif + skb->dev = dev; + if (rxdp->Control_1 & RXD_T_CODE) { + unsigned long long err = rxdp->Control_1 & RXD_T_CODE; + DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n", + dev->name, err); + dev_kfree_skb(skb); + sp->stats.rx_crc_errors++; + atomic_dec(&sp->rx_bufs_left[ring_no]); + rxdp->Host_Control = 0; + return 0; + } - l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); - if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && (sp->rx_csum)) { + /* Updating statistics */ + rxdp->Host_Control = 0; + sp->rx_pkt_count++; + sp->stats.rx_packets++; +#ifndef CONFIG_2BUFF_MODE + sp->stats.rx_bytes += len; +#else + sp->stats.rx_bytes += buf0_len + buf2_len; +#endif + +#ifndef CONFIG_2BUFF_MODE + skb_put(skb, len); +#else + buff = skb_push(skb, buf0_len); + memcpy(buff, ba->ba_0, buf0_len); + skb_put(skb, buf2_len); +#endif + + if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && + (sp->rx_csum)) { + l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) { - /* + /* * NIC verifies if the Checksum of the received * frame is Ok or not and accordingly returns * a flag in the RxD. */ skb->ip_summed = CHECKSUM_UNNECESSARY; } else { - /* - * Packet with erroneous checksum, let the + /* + * Packet with erroneous checksum, let the * upper layers deal with it. */ skb->ip_summed = CHECKSUM_NONE; @@ -4416,44 +5074,26 @@ static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no, skb->ip_summed = CHECKSUM_NONE; } - if (rxdp->Control_1 & RXD_T_CODE) { - unsigned long long err = rxdp->Control_1 & RXD_T_CODE; - DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n", - dev->name, err); - } -#ifdef CONFIG_2BUFF_MODE - buf0_len = RXD_GET_BUFFER0_SIZE(rxdp->Control_2); - buf2_len = RXD_GET_BUFFER2_SIZE(rxdp->Control_2); -#endif - - skb->dev = dev; -#ifndef CONFIG_2BUFF_MODE - skb_put(skb, len); - skb->protocol = eth_type_trans(skb, dev); -#else - buff = skb_push(skb, buf0_len); - memcpy(buff, ba->ba_0, buf0_len); - skb_put(skb, buf2_len); skb->protocol = eth_type_trans(skb, dev); -#endif - #ifdef CONFIG_S2IO_NAPI - netif_receive_skb(skb); + if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { + /* Queueing the vlan frame to the upper layer */ + vlan_hwaccel_receive_skb(skb, sp->vlgrp, + RXD_GET_VLAN_TAG(rxdp->Control_2)); + } else { + netif_receive_skb(skb); + } #else - netif_rx(skb); + if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { + /* Queueing the vlan frame to the upper layer */ + vlan_hwaccel_rx(skb, sp->vlgrp, + RXD_GET_VLAN_TAG(rxdp->Control_2)); + } else { + netif_rx(skb); + } #endif - dev->last_rx = jiffies; - sp->rx_pkt_count++; - sp->stats.rx_packets++; -#ifndef CONFIG_2BUFF_MODE - sp->stats.rx_bytes += len; -#else - sp->stats.rx_bytes += buf0_len + buf2_len; -#endif - atomic_dec(&sp->rx_bufs_left[ring_no]); - rxdp->Host_Control = 0; return SUCCESS; } @@ -4464,13 +5104,13 @@ static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no, * @link : inidicates whether link is UP/DOWN. * Description: * This function stops/starts the Tx queue depending on whether the link - * status of the NIC is is down or up. This is called by the Alarm - * interrupt handler whenever a link change interrupt comes up. + * status of the NIC is is down or up. This is called by the Alarm + * interrupt handler whenever a link change interrupt comes up. * Return value: * void. */ -static void s2io_link(nic_t * sp, int link) +void s2io_link(nic_t * sp, int link) { struct net_device *dev = (struct net_device *) sp->dev; @@ -4487,8 +5127,25 @@ static void s2io_link(nic_t * sp, int link) } /** - * s2io_init_pci -Initialization of PCI and PCI-X configuration registers . - * @sp : private member of the device structure, which is a pointer to the + * get_xena_rev_id - to identify revision ID of xena. + * @pdev : PCI Dev structure + * Description: + * Function to identify the Revision ID of xena. + * Return value: + * returns the revision ID of the device. + */ + +int get_xena_rev_id(struct pci_dev *pdev) +{ + u8 id = 0; + int ret; + ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id); + return id; +} + +/** + * s2io_init_pci -Initialization of PCI and PCI-X configuration registers . + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * Description: * This function initializes a few of the PCI and PCI-X configuration registers @@ -4499,15 +5156,15 @@ static void s2io_link(nic_t * sp, int link) static void s2io_init_pci(nic_t * sp) { - u16 pci_cmd = 0; + u16 pci_cmd = 0, pcix_cmd = 0; /* Enable Data Parity Error Recovery in PCI-X command register. */ pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - &(sp->pcix_cmd)); + &(pcix_cmd)); pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - (sp->pcix_cmd | 1)); + (pcix_cmd | 1)); pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - &(sp->pcix_cmd)); + &(pcix_cmd)); /* Set the PErr Response bit in PCI command register. */ pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd); @@ -4515,53 +5172,43 @@ static void s2io_init_pci(nic_t * sp) (pci_cmd | PCI_COMMAND_PARITY)); pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd); - /* Set MMRB count to 1024 in PCI-X Command register. */ - sp->pcix_cmd &= 0xFFF3; - pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, (sp->pcix_cmd | (0x1 << 2))); /* MMRBC 1K */ - pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - &(sp->pcix_cmd)); - - /* Setting Maximum outstanding splits based on system type. */ - sp->pcix_cmd &= 0xFF8F; - - sp->pcix_cmd |= XENA_MAX_OUTSTANDING_SPLITS(0x1); /* 2 splits. */ - pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - sp->pcix_cmd); - pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - &(sp->pcix_cmd)); /* Forcibly disabling relaxed ordering capability of the card. */ - sp->pcix_cmd &= 0xfffd; + pcix_cmd &= 0xfffd; pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - sp->pcix_cmd); + pcix_cmd); pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - &(sp->pcix_cmd)); + &(pcix_cmd)); } MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>"); MODULE_LICENSE("GPL"); module_param(tx_fifo_num, int, 0); -module_param_array(tx_fifo_len, int, NULL, 0); module_param(rx_ring_num, int, 0); -module_param_array(rx_ring_sz, int, NULL, 0); -module_param(Stats_refresh_time, int, 0); +module_param_array(tx_fifo_len, uint, NULL, 0); +module_param_array(rx_ring_sz, uint, NULL, 0); +module_param_array(rts_frm_len, uint, NULL, 0); +module_param(use_continuous_tx_intrs, int, 1); module_param(rmac_pause_time, int, 0); module_param(mc_pause_threshold_q0q3, int, 0); module_param(mc_pause_threshold_q4q7, int, 0); module_param(shared_splits, int, 0); module_param(tmac_util_period, int, 0); module_param(rmac_util_period, int, 0); +module_param(bimodal, bool, 0); #ifndef CONFIG_S2IO_NAPI module_param(indicate_max_pkts, int, 0); #endif +module_param(rxsync_frequency, int, 0); + /** - * s2io_init_nic - Initialization of the adapter . + * s2io_init_nic - Initialization of the adapter . * @pdev : structure containing the PCI related information of the device. * @pre: List of PCI devices supported by the driver listed in s2io_tbl. * Description: * The function initializes an adapter identified by the pci_dec structure. - * All OS related initialization including memory and device structure and - * initlaization of the device private variable is done. Also the swapper - * control register is initialized to enable read and write into the I/O + * All OS related initialization including memory and device structure and + * initlaization of the device private variable is done. Also the swapper + * control register is initialized to enable read and write into the I/O * registers of the device. * Return value: * returns 0 on success and negative on failure. @@ -4572,7 +5219,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) { nic_t *sp; struct net_device *dev; - char *dev_name = "S2IO 10GE NIC"; int i, j, ret; int dma_flag = FALSE; u32 mac_up, mac_down; @@ -4581,10 +5227,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) u16 subid; mac_info_t *mac_control; struct config_param *config; + int mode; - - DBG_PRINT(ERR_DBG, "Loading S2IO driver with %s\n", - s2io_driver_version); +#ifdef CONFIG_S2IO_NAPI + DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n"); +#endif if ((ret = pci_enable_device(pdev))) { DBG_PRINT(ERR_DBG, @@ -4595,7 +5242,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n"); dma_flag = TRUE; - if (pci_set_consistent_dma_mask (pdev, DMA_64BIT_MASK)) { DBG_PRINT(ERR_DBG, @@ -4635,34 +5281,41 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) memset(sp, 0, sizeof(nic_t)); sp->dev = dev; sp->pdev = pdev; - sp->vendor_id = pdev->vendor; - sp->device_id = pdev->device; sp->high_dma_flag = dma_flag; - sp->irq = pdev->irq; sp->device_enabled_once = FALSE; - strcpy(sp->name, dev_name); + + if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) || + (pdev->device == PCI_DEVICE_ID_HERC_UNI)) + sp->device_type = XFRAME_II_DEVICE; + else + sp->device_type = XFRAME_I_DEVICE; /* Initialize some PCI/PCI-X fields of the NIC. */ s2io_init_pci(sp); - /* + /* * Setting the device configuration parameters. - * Most of these parameters can be specified by the user during - * module insertion as they are module loadable parameters. If - * these parameters are not not specified during load time, they + * Most of these parameters can be specified by the user during + * module insertion as they are module loadable parameters. If + * these parameters are not not specified during load time, they * are initialized with default values. */ mac_control = &sp->mac_control; config = &sp->config; /* Tx side parameters. */ - tx_fifo_len[0] = DEFAULT_FIFO_LEN; /* Default value. */ + if (tx_fifo_len[0] == 0) + tx_fifo_len[0] = DEFAULT_FIFO_LEN; /* Default value. */ config->tx_fifo_num = tx_fifo_num; for (i = 0; i < MAX_TX_FIFOS; i++) { config->tx_cfg[i].fifo_len = tx_fifo_len[i]; config->tx_cfg[i].fifo_priority = i; } + /* mapping the QoS priority to the configured fifos */ + for (i = 0; i < MAX_TX_FIFOS; i++) + config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i]; + config->tx_intr_type = TXD_INT_TYPE_UTILZ; for (i = 0; i < config->tx_fifo_num; i++) { config->tx_cfg[i].f_no_snoop = @@ -4675,7 +5328,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) config->max_txds = MAX_SKB_FRAGS; /* Rx side parameters. */ - rx_ring_sz[0] = SMALL_BLK_CNT; /* Default value. */ + if (rx_ring_sz[0] == 0) + rx_ring_sz[0] = SMALL_BLK_CNT; /* Default value. */ config->rx_ring_num = rx_ring_num; for (i = 0; i < MAX_RX_RINGS; i++) { config->rx_cfg[i].num_rxd = rx_ring_sz[i] * @@ -4699,10 +5353,13 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) for (i = 0; i < config->rx_ring_num; i++) atomic_set(&sp->rx_bufs_left[i], 0); + /* Initialize the number of ISRs currently running */ + atomic_set(&sp->isr_cnt, 0); + /* initialize the shared memory used by the NIC and the host */ if (init_shared_mem(sp)) { DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", - dev->name); + __FUNCTION__); ret = -ENOMEM; goto mem_alloc_failed; } @@ -4743,13 +5400,17 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->do_ioctl = &s2io_ioctl; dev->change_mtu = &s2io_change_mtu; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_rx_register = s2io_vlan_rx_register; + dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid; + /* * will use eth_mac_addr() for dev->set_mac_address * mac address will be set every time dev->open() is called */ -#ifdef CONFIG_S2IO_NAPI +#if defined(CONFIG_S2IO_NAPI) dev->poll = s2io_poll; - dev->weight = 90; + dev->weight = 32; #endif dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; @@ -4776,22 +5437,28 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) goto set_swap_failed; } - /* Fix for all "FFs" MAC address problems observed on Alpha platforms */ - fix_mac_address(sp); - s2io_reset(sp); + /* Verify if the Herc works on the slot its placed into */ + if (sp->device_type & XFRAME_II_DEVICE) { + mode = s2io_verify_pci_mode(sp); + if (mode < 0) { + DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__); + DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n"); + ret = -EBADSLT; + goto set_swap_failed; + } + } - /* - * Setting swapper control on the NIC, so the MAC address can be read. - */ - if (s2io_set_swapper(sp)) { - DBG_PRINT(ERR_DBG, - "%s: S2IO: swapper settings are wrong\n", - dev->name); - ret = -EAGAIN; - goto set_swap_failed; + /* Not needed for Herc */ + if (sp->device_type & XFRAME_I_DEVICE) { + /* + * Fix for all "FFs" MAC address problems observed on + * Alpha platforms + */ + fix_mac_address(sp); + s2io_reset(sp); } - /* + /* * MAC address initialization. * For now only one mac address will be read and used. */ @@ -4814,37 +5481,28 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16); sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24); - DBG_PRINT(INIT_DBG, - "DEFAULT MAC ADDR:0x%02x-%02x-%02x-%02x-%02x-%02x\n", - sp->def_mac_addr[0].mac_addr[0], - sp->def_mac_addr[0].mac_addr[1], - sp->def_mac_addr[0].mac_addr[2], - sp->def_mac_addr[0].mac_addr[3], - sp->def_mac_addr[0].mac_addr[4], - sp->def_mac_addr[0].mac_addr[5]); - /* Set the factory defined MAC address initially */ dev->addr_len = ETH_ALEN; memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN); /* - * Initialize the tasklet status and link state flags - * and the card statte parameter + * Initialize the tasklet status and link state flags + * and the card state parameter */ atomic_set(&(sp->card_state), 0); sp->tasklet_status = 0; sp->link_state = 0; - /* Initialize spinlocks */ spin_lock_init(&sp->tx_lock); #ifndef CONFIG_S2IO_NAPI spin_lock_init(&sp->put_lock); #endif + spin_lock_init(&sp->rx_lock); - /* - * SXE-002: Configure link and activity LED to init state - * on driver load. + /* + * SXE-002: Configure link and activity LED to init state + * on driver load. */ subid = sp->pdev->subsystem_device; if ((subid & 0xFF) >= 0x07) { @@ -4864,13 +5522,61 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) goto register_failed; } - /* - * Make Link state as off at this point, when the Link change - * interrupt comes the state will be automatically changed to + if (sp->device_type & XFRAME_II_DEVICE) { + DBG_PRINT(ERR_DBG, "%s: Neterion Xframe II 10GbE adapter ", + dev->name); + DBG_PRINT(ERR_DBG, "(rev %d), Driver %s\n", + get_xena_rev_id(sp->pdev), + s2io_driver_version); + DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", + sp->def_mac_addr[0].mac_addr[0], + sp->def_mac_addr[0].mac_addr[1], + sp->def_mac_addr[0].mac_addr[2], + sp->def_mac_addr[0].mac_addr[3], + sp->def_mac_addr[0].mac_addr[4], + sp->def_mac_addr[0].mac_addr[5]); + mode = s2io_print_pci_mode(sp); + if (mode < 0) { + DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode "); + ret = -EBADSLT; + goto set_swap_failed; + } + } else { + DBG_PRINT(ERR_DBG, "%s: Neterion Xframe I 10GbE adapter ", + dev->name); + DBG_PRINT(ERR_DBG, "(rev %d), Driver %s\n", + get_xena_rev_id(sp->pdev), + s2io_driver_version); + DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", + sp->def_mac_addr[0].mac_addr[0], + sp->def_mac_addr[0].mac_addr[1], + sp->def_mac_addr[0].mac_addr[2], + sp->def_mac_addr[0].mac_addr[3], + sp->def_mac_addr[0].mac_addr[4], + sp->def_mac_addr[0].mac_addr[5]); + } + + /* Initialize device name */ + strcpy(sp->name, dev->name); + if (sp->device_type & XFRAME_II_DEVICE) + strcat(sp->name, ": Neterion Xframe II 10GbE adapter"); + else + strcat(sp->name, ": Neterion Xframe I 10GbE adapter"); + + /* Initialize bimodal Interrupts */ + sp->config.bimodal = bimodal; + if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) { + sp->config.bimodal = 0; + DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n", + dev->name); + } + + /* + * Make Link state as off at this point, when the Link change + * interrupt comes the state will be automatically changed to * the right state. */ netif_carrier_off(dev); - sp->last_link_state = LINK_DOWN; return 0; @@ -4891,11 +5597,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } /** - * s2io_rem_nic - Free the PCI device + * s2io_rem_nic - Free the PCI device * @pdev: structure containing the PCI related information of the device. - * Description: This function is called by the Pci subsystem to release a + * Description: This function is called by the Pci subsystem to release a * PCI device and free up all resource held up by the device. This could - * be in response to a Hot plug event or when the driver is to be removed + * be in response to a Hot plug event or when the driver is to be removed * from memory. */ @@ -4919,7 +5625,6 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) pci_disable_device(pdev); pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); - free_netdev(dev); } @@ -4935,11 +5640,11 @@ int __init s2io_starter(void) } /** - * s2io_closer - Cleanup routine for the driver + * s2io_closer - Cleanup routine for the driver * Description: This function is the cleanup routine for the driver. It unregist * ers the driver. */ -static void s2io_closer(void) +void s2io_closer(void) { pci_unregister_driver(&s2io_driver); DBG_PRINT(INIT_DBG, "cleanup done\n"); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 1711c8c3dc9..5d9270730ca 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -31,6 +31,9 @@ #define SUCCESS 0 #define FAILURE -1 +/* Maximum time to flicker LED when asked to identify NIC using ethtool */ +#define MAX_FLICKER_TIME 60000 /* 60 Secs */ + /* Maximum outstanding splits to be configured into xena. */ typedef enum xena_max_outstanding_splits { XENA_ONE_SPLIT_TRANSACTION = 0, @@ -45,10 +48,10 @@ typedef enum xena_max_outstanding_splits { #define XENA_MAX_OUTSTANDING_SPLITS(n) (n << 4) /* OS concerned variables and constants */ -#define WATCH_DOG_TIMEOUT 5*HZ -#define EFILL 0x1234 -#define ALIGN_SIZE 127 -#define PCIX_COMMAND_REGISTER 0x62 +#define WATCH_DOG_TIMEOUT 15*HZ +#define EFILL 0x1234 +#define ALIGN_SIZE 127 +#define PCIX_COMMAND_REGISTER 0x62 /* * Debug related variables. @@ -61,7 +64,7 @@ typedef enum xena_max_outstanding_splits { #define INTR_DBG 4 /* Global variable that defines the present debug level of the driver. */ -static int debug_level = ERR_DBG; /* Default level. */ +int debug_level = ERR_DBG; /* Default level. */ /* DEBUG message print. */ #define DBG_PRINT(dbg_level, args...) if(!(debug_level<dbg_level)) printk(args) @@ -71,6 +74,12 @@ static int debug_level = ERR_DBG; /* Default level. */ #define L4_CKSUM_OK 0xFFFF #define S2IO_JUMBO_SIZE 9600 +/* Driver statistics maintained by driver */ +typedef struct { + unsigned long long single_ecc_errs; + unsigned long long double_ecc_errs; +} swStat_t; + /* The statistics block of Xena */ typedef struct stat_block { /* Tx MAC statistics counters. */ @@ -186,12 +195,90 @@ typedef struct stat_block { u32 rxd_rd_cnt; u32 rxf_wr_cnt; u32 txf_rd_cnt; + +/* Tx MAC statistics overflow counters. */ + u32 tmac_data_octets_oflow; + u32 tmac_frms_oflow; + u32 tmac_bcst_frms_oflow; + u32 tmac_mcst_frms_oflow; + u32 tmac_ucst_frms_oflow; + u32 tmac_ttl_octets_oflow; + u32 tmac_any_err_frms_oflow; + u32 tmac_nucst_frms_oflow; + u64 tmac_vlan_frms; + u32 tmac_drop_ip_oflow; + u32 tmac_vld_ip_oflow; + u32 tmac_rst_tcp_oflow; + u32 tmac_icmp_oflow; + u32 tpa_unknown_protocol; + u32 tmac_udp_oflow; + u32 reserved_10; + u32 tpa_parse_failure; + +/* Rx MAC Statistics overflow counters. */ + u32 rmac_data_octets_oflow; + u32 rmac_vld_frms_oflow; + u32 rmac_vld_bcst_frms_oflow; + u32 rmac_vld_mcst_frms_oflow; + u32 rmac_accepted_ucst_frms_oflow; + u32 rmac_ttl_octets_oflow; + u32 rmac_discarded_frms_oflow; + u32 rmac_accepted_nucst_frms_oflow; + u32 rmac_usized_frms_oflow; + u32 rmac_drop_events_oflow; + u32 rmac_frag_frms_oflow; + u32 rmac_osized_frms_oflow; + u32 rmac_ip_oflow; + u32 rmac_jabber_frms_oflow; + u32 rmac_icmp_oflow; + u32 rmac_drop_ip_oflow; + u32 rmac_err_drp_udp_oflow; + u32 rmac_udp_oflow; + u32 reserved_11; + u32 rmac_pause_cnt_oflow; + u64 rmac_ttl_1519_4095_frms; + u64 rmac_ttl_4096_8191_frms; + u64 rmac_ttl_8192_max_frms; + u64 rmac_ttl_gt_max_frms; + u64 rmac_osized_alt_frms; + u64 rmac_jabber_alt_frms; + u64 rmac_gt_max_alt_frms; + u64 rmac_vlan_frms; + u32 rmac_len_discard; + u32 rmac_fcs_discard; + u32 rmac_pf_discard; + u32 rmac_da_discard; + u32 rmac_red_discard; + u32 rmac_rts_discard; + u32 reserved_12; + u32 rmac_ingm_full_discard; + u32 reserved_13; + u32 rmac_accepted_ip_oflow; + u32 reserved_14; + u32 link_fault_cnt; + swStat_t sw_stat; } StatInfo_t; -/* Structures representing different init time configuration +/* + * Structures representing different init time configuration * parameters of the NIC. */ +#define MAX_TX_FIFOS 8 +#define MAX_RX_RINGS 8 + +/* FIFO mappings for all possible number of fifos configured */ +int fifo_map[][MAX_TX_FIFOS] = { + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 1, 1, 1, 1}, + {0, 0, 0, 1, 1, 1, 2, 2}, + {0, 0, 1, 1, 2, 2, 3, 3}, + {0, 0, 1, 1, 2, 2, 3, 4}, + {0, 0, 1, 1, 2, 3, 4, 5}, + {0, 0, 1, 2, 3, 4, 5, 6}, + {0, 1, 2, 3, 4, 5, 6, 7}, +}; + /* Maintains Per FIFO related information. */ typedef struct tx_fifo_config { #define MAX_AVAILABLE_TXDS 8192 @@ -237,14 +324,14 @@ typedef struct rx_ring_config { #define NO_SNOOP_RXD_BUFFER 0x02 } rx_ring_config_t; -/* This structure provides contains values of the tunable parameters - * of the H/W +/* This structure provides contains values of the tunable parameters + * of the H/W */ struct config_param { /* Tx Side */ u32 tx_fifo_num; /*Number of Tx FIFOs */ -#define MAX_TX_FIFOS 8 + u8 fifo_mapping[MAX_TX_FIFOS]; tx_fifo_config_t tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */ u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */ u64 tx_intr_type; @@ -252,10 +339,10 @@ struct config_param { /* Rx Side */ u32 rx_ring_num; /*Number of receive rings */ -#define MAX_RX_RINGS 8 #define MAX_RX_BLOCKS_PER_RING 150 rx_ring_config_t rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */ + u8 bimodal; /*Flag for setting bimodal interrupts*/ #define HEADER_ETHERNET_II_802_3_SIZE 14 #define HEADER_802_2_SIZE 3 @@ -269,6 +356,7 @@ struct config_param { #define MAX_PYLD_JUMBO 9600 #define MAX_MTU_JUMBO (MAX_PYLD_JUMBO+18) #define MAX_MTU_JUMBO_VLAN (MAX_PYLD_JUMBO+22) + u16 bus_speed; }; /* Structure representing MAC Addrs */ @@ -277,7 +365,7 @@ typedef struct mac_addr { } macaddr_t; /* Structure that represent every FIFO element in the BAR1 - * Address location. + * Address location. */ typedef struct _TxFIFO_element { u64 TxDL_Pointer; @@ -339,6 +427,7 @@ typedef struct _RxD_t { #define RXD_FRAME_PROTO vBIT(0xFFFF,24,8) #define RXD_FRAME_PROTO_IPV4 BIT(27) #define RXD_FRAME_PROTO_IPV6 BIT(28) +#define RXD_FRAME_IP_FRAG BIT(29) #define RXD_FRAME_PROTO_TCP BIT(30) #define RXD_FRAME_PROTO_UDP BIT(31) #define TCP_OR_UDP_FRAME (RXD_FRAME_PROTO_TCP | RXD_FRAME_PROTO_UDP) @@ -346,11 +435,15 @@ typedef struct _RxD_t { #define RXD_GET_L4_CKSUM(val) ((u16)(val) & 0xFFFF) u64 Control_2; +#define THE_RXD_MARK 0x3 +#define SET_RXD_MARKER vBIT(THE_RXD_MARK, 0, 2) +#define GET_RXD_MARKER(ctrl) ((ctrl & SET_RXD_MARKER) >> 62) + #ifndef CONFIG_2BUFF_MODE -#define MASK_BUFFER0_SIZE vBIT(0xFFFF,0,16) -#define SET_BUFFER0_SIZE(val) vBIT(val,0,16) +#define MASK_BUFFER0_SIZE vBIT(0x3FFF,2,14) +#define SET_BUFFER0_SIZE(val) vBIT(val,2,14) #else -#define MASK_BUFFER0_SIZE vBIT(0xFF,0,16) +#define MASK_BUFFER0_SIZE vBIT(0xFF,2,14) #define MASK_BUFFER1_SIZE vBIT(0xFFFF,16,16) #define MASK_BUFFER2_SIZE vBIT(0xFFFF,32,16) #define SET_BUFFER0_SIZE(val) vBIT(val,8,8) @@ -363,7 +456,7 @@ typedef struct _RxD_t { #define SET_NUM_TAG(val) vBIT(val,16,32) #ifndef CONFIG_2BUFF_MODE -#define RXD_GET_BUFFER0_SIZE(Control_2) (u64)((Control_2 & vBIT(0xFFFF,0,16))) +#define RXD_GET_BUFFER0_SIZE(Control_2) (u64)((Control_2 & vBIT(0x3FFF,2,14))) #else #define RXD_GET_BUFFER0_SIZE(Control_2) (u8)((Control_2 & MASK_BUFFER0_SIZE) \ >> 48) @@ -382,7 +475,7 @@ typedef struct _RxD_t { #endif } RxD_t; -/* Structure that represents the Rx descriptor block which contains +/* Structure that represents the Rx descriptor block which contains * 128 Rx descriptors. */ #ifndef CONFIG_2BUFF_MODE @@ -392,11 +485,11 @@ typedef struct _RxD_block { u64 reserved_0; #define END_OF_BLOCK 0xFEFFFFFFFFFFFFFFULL - u64 reserved_1; /* 0xFEFFFFFFFFFFFFFF to mark last + u64 reserved_1; /* 0xFEFFFFFFFFFFFFFF to mark last * Rxd in this blk */ u64 reserved_2_pNext_RxD_block; /* Logical ptr to next */ u64 pNext_RxD_Blk_physical; /* Buff0_ptr.In a 32 bit arch - * the upper 32 bits should + * the upper 32 bits should * be 0 */ } RxD_block_t; #else @@ -405,13 +498,13 @@ typedef struct _RxD_block { RxD_t rxd[MAX_RXDS_PER_BLOCK]; #define END_OF_BLOCK 0xFEFFFFFFFFFFFFFFULL - u64 reserved_1; /* 0xFEFFFFFFFFFFFFFF to mark last Rxd + u64 reserved_1; /* 0xFEFFFFFFFFFFFFFF to mark last Rxd * in this blk */ u64 pNext_RxD_Blk_physical; /* Phy ponter to next blk. */ } RxD_block_t; #define SIZE_OF_BLOCK 4096 -/* Structure to hold virtual addresses of Buf0 and Buf1 in +/* Structure to hold virtual addresses of Buf0 and Buf1 in * 2buf mode. */ typedef struct bufAdd { void *ba_0_org; @@ -423,8 +516,8 @@ typedef struct bufAdd { /* Structure which stores all the MAC control parameters */ -/* This structure stores the offset of the RxD in the ring - * from which the Rx Interrupt processor can start picking +/* This structure stores the offset of the RxD in the ring + * from which the Rx Interrupt processor can start picking * up the RxDs for processing. */ typedef struct _rx_curr_get_info_t { @@ -436,7 +529,7 @@ typedef struct _rx_curr_get_info_t { typedef rx_curr_get_info_t rx_curr_put_info_t; /* This structure stores the offset of the TxDl in the FIFO - * from which the Tx Interrupt processor can start picking + * from which the Tx Interrupt processor can start picking * up the TxDLs for send complete interrupt processing. */ typedef struct { @@ -446,32 +539,96 @@ typedef struct { typedef tx_curr_get_info_t tx_curr_put_info_t; -/* Infomation related to the Tx and Rx FIFOs and Rings of Xena - * is maintained in this structure. - */ -typedef struct mac_info { -/* rx side stuff */ - /* Put pointer info which indictes which RxD has to be replenished +/* Structure that holds the Phy and virt addresses of the Blocks */ +typedef struct rx_block_info { + RxD_t *block_virt_addr; + dma_addr_t block_dma_addr; +} rx_block_info_t; + +/* pre declaration of the nic structure */ +typedef struct s2io_nic nic_t; + +/* Ring specific structure */ +typedef struct ring_info { + /* The ring number */ + int ring_no; + + /* + * Place holders for the virtual and physical addresses of + * all the Rx Blocks + */ + rx_block_info_t rx_blocks[MAX_RX_BLOCKS_PER_RING]; + int block_count; + int pkt_cnt; + + /* + * Put pointer info which indictes which RxD has to be replenished * with a new buffer. */ - rx_curr_put_info_t rx_curr_put_info[MAX_RX_RINGS]; + rx_curr_put_info_t rx_curr_put_info; - /* Get pointer info which indictes which is the last RxD that was + /* + * Get pointer info which indictes which is the last RxD that was * processed by the driver. */ - rx_curr_get_info_t rx_curr_get_info[MAX_RX_RINGS]; + rx_curr_get_info_t rx_curr_get_info; - u16 rmac_pause_time; - u16 mc_pause_threshold_q0q3; - u16 mc_pause_threshold_q4q7; +#ifndef CONFIG_S2IO_NAPI + /* Index to the absolute position of the put pointer of Rx ring */ + int put_pos; +#endif + +#ifdef CONFIG_2BUFF_MODE + /* Buffer Address store. */ + buffAdd_t **ba; +#endif + nic_t *nic; +} ring_info_t; +/* Fifo specific structure */ +typedef struct fifo_info { + /* FIFO number */ + int fifo_no; + + /* Maximum TxDs per TxDL */ + int max_txds; + + /* Place holder of all the TX List's Phy and Virt addresses. */ + list_info_hold_t *list_info; + + /* + * Current offset within the tx FIFO where driver would write + * new Tx frame + */ + tx_curr_put_info_t tx_curr_put_info; + + /* + * Current offset within tx FIFO from where the driver would start freeing + * the buffers + */ + tx_curr_get_info_t tx_curr_get_info; + + nic_t *nic; +}fifo_info_t; + +/* Infomation related to the Tx and Rx FIFOs and Rings of Xena + * is maintained in this structure. + */ +typedef struct mac_info { /* tx side stuff */ /* logical pointer of start of each Tx FIFO */ TxFIFO_element_t __iomem *tx_FIFO_start[MAX_TX_FIFOS]; -/* Current offset within tx_FIFO_start, where driver would write new Tx frame*/ - tx_curr_put_info_t tx_curr_put_info[MAX_TX_FIFOS]; - tx_curr_get_info_t tx_curr_get_info[MAX_TX_FIFOS]; + /* Fifo specific structure */ + fifo_info_t fifos[MAX_TX_FIFOS]; + +/* rx side stuff */ + /* Ring specific structure */ + ring_info_t rings[MAX_RX_RINGS]; + + u16 rmac_pause_time; + u16 mc_pause_threshold_q0q3; + u16 mc_pause_threshold_q4q7; void *stats_mem; /* orignal pointer to allocated mem */ dma_addr_t stats_mem_phy; /* Physical address of the stat block */ @@ -485,12 +642,6 @@ typedef struct { int usage_cnt; } usr_addr_t; -/* Structure that holds the Phy and virt addresses of the Blocks */ -typedef struct rx_block_info { - RxD_t *block_virt_addr; - dma_addr_t block_dma_addr; -} rx_block_info_t; - /* Default Tunable parameters of the NIC. */ #define DEFAULT_FIFO_LEN 4096 #define SMALL_RXD_CNT 30 * (MAX_RXDS_PER_BLOCK+1) @@ -499,7 +650,20 @@ typedef struct rx_block_info { #define LARGE_BLK_CNT 100 /* Structure representing one instance of the NIC */ -typedef struct s2io_nic { +struct s2io_nic { +#ifdef CONFIG_S2IO_NAPI + /* + * Count of packets to be processed in a given iteration, it will be indicated + * by the quota field of the device structure when NAPI is enabled. + */ + int pkts_to_process; +#endif + struct net_device *dev; + mac_info_t mac_control; + struct config_param config; + struct pci_dev *pdev; + void __iomem *bar0; + void __iomem *bar1; #define MAX_MAC_SUPPORTED 16 #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED @@ -507,33 +671,20 @@ typedef struct s2io_nic { macaddr_t pre_mac_addr[MAX_MAC_SUPPORTED]; struct net_device_stats stats; - void __iomem *bar0; - void __iomem *bar1; - struct config_param config; - mac_info_t mac_control; int high_dma_flag; int device_close_flag; int device_enabled_once; - char name[32]; + char name[50]; struct tasklet_struct task; volatile unsigned long tasklet_status; - struct timer_list timer; - struct net_device *dev; - struct pci_dev *pdev; - u16 vendor_id; - u16 device_id; - u16 ccmd; - u32 cbar0_1; - u32 cbar0_2; - u32 cbar1_1; - u32 cbar1_2; - u32 cirq; - u8 cache_line; - u32 rom_expansion; - u16 pcix_cmd; - u32 irq; + /* Timer that handles I/O errors/exceptions */ + struct timer_list alarm_timer; + + /* Space to back up the PCI config space */ + u32 config_space[256 / sizeof(u32)]; + atomic_t rx_bufs_left[MAX_RX_RINGS]; spinlock_t tx_lock; @@ -558,27 +709,11 @@ typedef struct s2io_nic { u16 tx_err_count; u16 rx_err_count; -#ifndef CONFIG_S2IO_NAPI - /* Index to the absolute position of the put pointer of Rx ring. */ - int put_pos[MAX_RX_RINGS]; -#endif - - /* - * Place holders for the virtual and physical addresses of - * all the Rx Blocks - */ - rx_block_info_t rx_blocks[MAX_RX_RINGS][MAX_RX_BLOCKS_PER_RING]; - int block_count[MAX_RX_RINGS]; - int pkt_cnt[MAX_RX_RINGS]; - - /* Place holder of all the TX List's Phy and Virt addresses. */ - list_info_hold_t *list_info[MAX_TX_FIFOS]; - /* Id timer, used to blink NIC to physically identify NIC. */ struct timer_list id_timer; /* Restart timer, used to restart NIC if the device is stuck and - * a schedule task that will set the correct Link state once the + * a schedule task that will set the correct Link state once the * NIC's PHY has stabilized after a state change. */ #ifdef INIT_TQUEUE @@ -589,12 +724,12 @@ typedef struct s2io_nic { struct work_struct set_link_task; #endif - /* Flag that can be used to turn on or turn off the Rx checksum + /* Flag that can be used to turn on or turn off the Rx checksum * offload feature. */ int rx_csum; - /* after blink, the adapter must be restored with original + /* after blink, the adapter must be restored with original * values. */ u64 adapt_ctrl_org; @@ -604,16 +739,19 @@ typedef struct s2io_nic { #define LINK_DOWN 1 #define LINK_UP 2 -#ifdef CONFIG_2BUFF_MODE - /* Buffer Address store. */ - buffAdd_t **ba[MAX_RX_RINGS]; -#endif int task_flag; #define CARD_DOWN 1 #define CARD_UP 2 atomic_t card_state; volatile unsigned long link_state; -} nic_t; + struct vlan_group *vlgrp; +#define XFRAME_I_DEVICE 1 +#define XFRAME_II_DEVICE 2 + u8 device_type; + + spinlock_t rx_lock; + atomic_t isr_cnt; +}; #define RESET_ERROR 1; #define CMD_ERROR 2; @@ -622,9 +760,10 @@ typedef struct s2io_nic { #ifndef readq static inline u64 readq(void __iomem *addr) { - u64 ret = readl(addr + 4); - ret <<= 32; - ret |= readl(addr); + u64 ret = 0; + ret = readl(addr + 4); + (u64) ret <<= 32; + (u64) ret |= readl(addr); return ret; } @@ -637,10 +776,10 @@ static inline void writeq(u64 val, void __iomem *addr) writel((u32) (val >> 32), (addr + 4)); } -/* In 32 bit modes, some registers have to be written in a +/* In 32 bit modes, some registers have to be written in a * particular order to expect correct hardware operation. The - * macro SPECIAL_REG_WRITE is used to perform such ordered - * writes. Defines UF (Upper First) and LF (Lower First) will + * macro SPECIAL_REG_WRITE is used to perform such ordered + * writes. Defines UF (Upper First) and LF (Lower First) will * be used to specify the required write order. */ #define UF 1 @@ -716,6 +855,7 @@ static inline void SPECIAL_REG_WRITE(u64 val, void __iomem *addr, int order) #define PCC_FB_ECC_ERR vBIT(0xff, 16, 8) /* Interrupt to indicate PCC_FB_ECC Error. */ +#define RXD_GET_VLAN_TAG(Control_2) (u16)(Control_2 & MASK_VLAN_TAG) /* * Prototype declaration. */ @@ -725,36 +865,30 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev); static int init_shared_mem(struct s2io_nic *sp); static void free_shared_mem(struct s2io_nic *sp); static int init_nic(struct s2io_nic *nic); -#ifndef CONFIG_S2IO_NAPI -static void rx_intr_handler(struct s2io_nic *sp); -#endif -static void tx_intr_handler(struct s2io_nic *sp); +static void rx_intr_handler(ring_info_t *ring_data); +static void tx_intr_handler(fifo_info_t *fifo_data); static void alarm_intr_handler(struct s2io_nic *sp); static int s2io_starter(void); -static void s2io_closer(void); +void s2io_closer(void); static void s2io_tx_watchdog(struct net_device *dev); static void s2io_tasklet(unsigned long dev_addr); static void s2io_set_multicast(struct net_device *dev); -#ifndef CONFIG_2BUFF_MODE -static int rx_osm_handler(nic_t * sp, u16 len, RxD_t * rxdp, int ring_no); -#else -static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no, - buffAdd_t * ba); -#endif -static void s2io_link(nic_t * sp, int link); -static void s2io_reset(nic_t * sp); -#ifdef CONFIG_S2IO_NAPI +static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp); +void s2io_link(nic_t * sp, int link); +void s2io_reset(nic_t * sp); +#if defined(CONFIG_S2IO_NAPI) static int s2io_poll(struct net_device *dev, int *budget); #endif static void s2io_init_pci(nic_t * sp); -static int s2io_set_mac_addr(struct net_device *dev, u8 * addr); +int s2io_set_mac_addr(struct net_device *dev, u8 * addr); +static void s2io_alarm_handle(unsigned long data); static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs); -static int verify_xena_quiescence(u64 val64, int flag); +static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag); static struct ethtool_ops netdev_ethtool_ops; static void s2io_set_link(unsigned long data); -static int s2io_set_swapper(nic_t * sp); -static void s2io_card_down(nic_t * nic); -static int s2io_card_up(nic_t * nic); - +int s2io_set_swapper(nic_t * sp); +static void s2io_card_down(nic_t *nic); +static int s2io_card_up(nic_t *nic); +int get_xena_rev_id(struct pci_dev *pdev); #endif /* _S2IO_H */ diff --git a/drivers/net/skge.c b/drivers/net/skge.c index f15739481d6..d7c98515fdf 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -42,7 +42,7 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "0.8" +#define DRV_VERSION "0.9" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 @@ -79,8 +79,8 @@ static const struct pci_device_id skge_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */ { PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) }, - { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032) }, { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064) }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, }, { 0 } }; MODULE_DEVICE_TABLE(pci, skge_id_table); @@ -189,7 +189,7 @@ static u32 skge_supported_modes(const struct skge_hw *hw) { u32 supported; - if (iscopper(hw)) { + if (hw->copper) { supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half @@ -222,7 +222,7 @@ static int skge_get_settings(struct net_device *dev, ecmd->transceiver = XCVR_INTERNAL; ecmd->supported = skge_supported_modes(hw); - if (iscopper(hw)) { + if (hw->copper) { ecmd->port = PORT_TP; ecmd->phy_address = hw->phy_addr; } else @@ -876,6 +876,9 @@ static int skge_rx_fill(struct skge_port *skge) static void skge_link_up(struct skge_port *skge) { + skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), + LED_BLK_OFF|LED_SYNC_OFF|LED_ON); + netif_carrier_on(skge->netdev); if (skge->tx_avail > MAX_SKB_FRAGS + 1) netif_wake_queue(skge->netdev); @@ -894,6 +897,7 @@ static void skge_link_up(struct skge_port *skge) static void skge_link_down(struct skge_port *skge) { + skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF); netif_carrier_off(skge->netdev); netif_stop_queue(skge->netdev); @@ -1599,7 +1603,7 @@ static void yukon_init(struct skge_hw *hw, int port) adv = PHY_AN_CSMA; if (skge->autoneg == AUTONEG_ENABLE) { - if (iscopper(hw)) { + if (hw->copper) { if (skge->advertising & ADVERTISED_1000baseT_Full) ct1000 |= PHY_M_1000C_AFD; if (skge->advertising & ADVERTISED_1000baseT_Half) @@ -1691,7 +1695,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port) /* Set hardware config mode */ reg = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP | GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE; - reg |= iscopper(hw) ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB; + reg |= hw->copper ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB; /* Clear GMC reset */ skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_SET); @@ -1780,7 +1784,12 @@ static void yukon_mac_init(struct skge_hw *hw, int port) reg &= ~GMF_RX_F_FL_ON; skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR); skge_write16(hw, SK_REG(port, RX_GMF_CTRL_T), reg); - skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF); + /* + * because Pause Packet Truncation in GMAC is not working + * we have to increase the Flush Threshold to 64 bytes + * in order to flush pause packets in Rx FIFO on Yukon-1 + */ + skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF+1); /* Configure Tx MAC FIFO */ skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); @@ -2670,18 +2679,6 @@ static void skge_error_irq(struct skge_hw *hw) /* Timestamp (unused) overflow */ if (hwstatus & IS_IRQ_TIST_OV) skge_write8(hw, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ); - - if (hwstatus & IS_IRQ_SENSOR) { - /* no sensors on 32-bit Yukon */ - if (!(skge_read16(hw, B0_CTST) & CS_BUS_SLOT_SZ)) { - printk(KERN_ERR PFX "ignoring bogus sensor interrups\n"); - skge_write32(hw, B0_HWE_IMSK, - IS_ERR_MSK & ~IS_IRQ_SENSOR); - } else - printk(KERN_WARNING PFX "sensor interrupt\n"); - } - - } if (hwstatus & IS_RAM_RD_PAR) { @@ -2712,9 +2709,10 @@ static void skge_error_irq(struct skge_hw *hw) skge_pci_clear(hw); + /* if error still set then just ignore it */ hwstatus = skge_read32(hw, B0_HWE_ISRC); if (hwstatus & IS_IRQ_STAT) { - printk(KERN_WARNING PFX "IRQ status %x: still set ignoring hardware errors\n", + pr_debug("IRQ status %x: still set ignoring hardware errors\n", hwstatus); hw->intr_mask &= ~IS_HW_ERR; } @@ -2876,7 +2874,7 @@ static const char *skge_board_name(const struct skge_hw *hw) static int skge_reset(struct skge_hw *hw) { u16 ctst; - u8 t8, mac_cfg; + u8 t8, mac_cfg, pmd_type, phy_type; int i; ctst = skge_read16(hw, B0_CTST); @@ -2895,18 +2893,19 @@ static int skge_reset(struct skge_hw *hw) ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA)); hw->chip_id = skge_read8(hw, B2_CHIP_ID); - hw->phy_type = skge_read8(hw, B2_E_1) & 0xf; - hw->pmd_type = skge_read8(hw, B2_PMD_TYP); + phy_type = skge_read8(hw, B2_E_1) & 0xf; + pmd_type = skge_read8(hw, B2_PMD_TYP); + hw->copper = (pmd_type == 'T' || pmd_type == '1'); switch (hw->chip_id) { case CHIP_ID_GENESIS: - switch (hw->phy_type) { + switch (phy_type) { case SK_PHY_BCOM: hw->phy_addr = PHY_ADDR_BCOM; break; default: printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n", - pci_name(hw->pdev), hw->phy_type); + pci_name(hw->pdev), phy_type); return -EOPNOTSUPP; } break; @@ -2914,13 +2913,10 @@ static int skge_reset(struct skge_hw *hw) case CHIP_ID_YUKON: case CHIP_ID_YUKON_LITE: case CHIP_ID_YUKON_LP: - if (hw->phy_type < SK_PHY_MARV_COPPER && hw->pmd_type != 'S') - hw->phy_type = SK_PHY_MARV_COPPER; + if (phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S') + hw->copper = 1; hw->phy_addr = PHY_ADDR_MARV; - if (!iscopper(hw)) - hw->phy_type = SK_PHY_MARV_FIBER; - break; default: @@ -2948,12 +2944,20 @@ static int skge_reset(struct skge_hw *hw) else hw->ram_size = t8 * 4096; + hw->intr_mask = IS_HW_ERR | IS_EXT_REG; if (hw->chip_id == CHIP_ID_GENESIS) genesis_init(hw); else { /* switch power to VCC (WA for VAUX problem) */ skge_write8(hw, B0_POWER_CTRL, PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON); + /* avoid boards with stuck Hardware error bits */ + if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) && + (skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) { + printk(KERN_WARNING PFX "stuck hardware sensor bit\n"); + hw->intr_mask &= ~IS_HW_ERR; + } + for (i = 0; i < hw->ports; i++) { skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET); skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR); @@ -2994,7 +2998,6 @@ static int skge_reset(struct skge_hw *hw) skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100)); skge_write32(hw, B2_IRQM_CTRL, TIM_START); - hw->intr_mask = IS_HW_ERR | IS_EXT_REG; skge_write32(hw, B0_IMSK, hw->intr_mask); if (hw->chip_id != CHIP_ID_GENESIS) diff --git a/drivers/net/skge.h b/drivers/net/skge.h index b432f1bb816..f1680beb8e6 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -214,8 +214,6 @@ enum { /* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */ enum { - IS_ERR_MSK = 0x00003fff,/* All Error bits */ - IS_IRQ_TIST_OV = 1<<13, /* Time Stamp Timer Overflow (YUKON only) */ IS_IRQ_SENSOR = 1<<12, /* IRQ from Sensor (YUKON only) */ IS_IRQ_MST_ERR = 1<<11, /* IRQ master error detected */ @@ -230,6 +228,12 @@ enum { IS_M2_PAR_ERR = 1<<2, /* MAC 2 Parity Error */ IS_R1_PAR_ERR = 1<<1, /* Queue R1 Parity Error */ IS_R2_PAR_ERR = 1<<0, /* Queue R2 Parity Error */ + + IS_ERR_MSK = IS_IRQ_MST_ERR | IS_IRQ_STAT + | IS_NO_STAT_M1 | IS_NO_STAT_M2 + | IS_RAM_RD_PAR | IS_RAM_WR_PAR + | IS_M1_PAR_ERR | IS_M2_PAR_ERR + | IS_R1_PAR_ERR | IS_R2_PAR_ERR, }; /* B2_TST_CTRL1 8 bit Test Control Register 1 */ @@ -2456,24 +2460,17 @@ struct skge_hw { u8 chip_id; u8 chip_rev; - u8 phy_type; - u8 pmd_type; - u16 phy_addr; + u8 copper; u8 ports; u32 ram_size; u32 ram_offset; + u16 phy_addr; struct tasklet_struct ext_tasklet; spinlock_t phy_lock; }; - -static inline int iscopper(const struct skge_hw *hw) -{ - return (hw->pmd_type == 'T'); -} - enum { FLOW_MODE_NONE = 0, /* No Flow-Control */ FLOW_MODE_LOC_SEND = 1, /* Local station sends PAUSE */ diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index cdc9cc873e0..90b818a8de6 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -1,6 +1,11 @@ /* * sonic.c * + * (C) 2005 Finn Thain + * + * Converted to DMA API, added zero-copy buffer handling, and + * (from the mac68k project) introduced dhd's support for 16-bit cards. + * * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de) * * This driver is based on work from Andreas Busse, but most of @@ -9,12 +14,23 @@ * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de) * * Core code included by system sonic drivers + * + * And... partially rewritten again by David Huggins-Daines in order + * to cope with screwed up Macintosh NICs that may or may not use + * 16-bit DMA. + * + * (C) 1999 David Huggins-Daines <dhd@debian.org> + * */ /* * Sources: Olivetti M700-10 Risc Personal Computer hardware handbook, * National Semiconductors data sheet for the DP83932B Sonic Ethernet * controller, and the files "8390.c" and "skeleton.c" in this directory. + * + * Additional sources: Nat Semi data sheet for the DP83932C and Nat Semi + * Application Note AN-746, the files "lance.c" and "ibmlana.c". See also + * the NetBSD file "sys/arch/mac68k/dev/if_sn.c". */ @@ -28,6 +44,9 @@ */ static int sonic_open(struct net_device *dev) { + struct sonic_local *lp = netdev_priv(dev); + int i; + if (sonic_debug > 2) printk("sonic_open: initializing sonic driver.\n"); @@ -40,14 +59,59 @@ static int sonic_open(struct net_device *dev) * This means that during execution of the handler interrupt are disabled * covering another bug otherwise corrupting data. This doesn't mean * this glue works ok under all situations. + * + * Note (dhd): this also appears to prevent lockups on the Macintrash + * when more than one Ethernet card is installed (knock on wood) + * + * Note (fthain): whether the above is still true is anyones guess. Certainly + * the buffer handling algorithms will not tolerate re-entrance without some + * mutual exclusion added. Anyway, the memcpy has now been eliminated from the + * rx code to make this a faster "fast interrupt". */ -// if (sonic_request_irq(dev->irq, &sonic_interrupt, 0, "sonic", dev)) { - if (sonic_request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT, - "sonic", dev)) { - printk("\n%s: unable to get IRQ %d .\n", dev->name, dev->irq); + if (request_irq(dev->irq, &sonic_interrupt, SONIC_IRQ_FLAG, "sonic", dev)) { + printk(KERN_ERR "\n%s: unable to get IRQ %d .\n", dev->name, dev->irq); return -EAGAIN; } + for (i = 0; i < SONIC_NUM_RRS; i++) { + struct sk_buff *skb = dev_alloc_skb(SONIC_RBSIZE + 2); + if (skb == NULL) { + while(i > 0) { /* free any that were allocated successfully */ + i--; + dev_kfree_skb(lp->rx_skb[i]); + lp->rx_skb[i] = NULL; + } + printk(KERN_ERR "%s: couldn't allocate receive buffers\n", + dev->name); + return -ENOMEM; + } + skb->dev = dev; + /* align IP header unless DMA requires otherwise */ + if (SONIC_BUS_SCALE(lp->dma_bitmode) == 2) + skb_reserve(skb, 2); + lp->rx_skb[i] = skb; + } + + for (i = 0; i < SONIC_NUM_RRS; i++) { + dma_addr_t laddr = dma_map_single(lp->device, skb_put(lp->rx_skb[i], SONIC_RBSIZE), + SONIC_RBSIZE, DMA_FROM_DEVICE); + if (!laddr) { + while(i > 0) { /* free any that were mapped successfully */ + i--; + dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE); + lp->rx_laddr[i] = (dma_addr_t)0; + } + for (i = 0; i < SONIC_NUM_RRS; i++) { + dev_kfree_skb(lp->rx_skb[i]); + lp->rx_skb[i] = NULL; + } + printk(KERN_ERR "%s: couldn't map rx DMA buffers\n", + dev->name); + return -ENOMEM; + } + lp->rx_laddr[i] = laddr; + } + /* * Initialize the SONIC */ @@ -67,7 +131,8 @@ static int sonic_open(struct net_device *dev) */ static int sonic_close(struct net_device *dev) { - unsigned int base_addr = dev->base_addr; + struct sonic_local *lp = netdev_priv(dev); + int i; if (sonic_debug > 2) printk("sonic_close\n"); @@ -77,20 +142,56 @@ static int sonic_close(struct net_device *dev) /* * stop the SONIC, disable interrupts */ - SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_IMR, 0); + SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); - sonic_free_irq(dev->irq, dev); /* release the IRQ */ + /* unmap and free skbs that haven't been transmitted */ + for (i = 0; i < SONIC_NUM_TDS; i++) { + if(lp->tx_laddr[i]) { + dma_unmap_single(lp->device, lp->tx_laddr[i], lp->tx_len[i], DMA_TO_DEVICE); + lp->tx_laddr[i] = (dma_addr_t)0; + } + if(lp->tx_skb[i]) { + dev_kfree_skb(lp->tx_skb[i]); + lp->tx_skb[i] = NULL; + } + } + + /* unmap and free the receive buffers */ + for (i = 0; i < SONIC_NUM_RRS; i++) { + if(lp->rx_laddr[i]) { + dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE); + lp->rx_laddr[i] = (dma_addr_t)0; + } + if(lp->rx_skb[i]) { + dev_kfree_skb(lp->rx_skb[i]); + lp->rx_skb[i] = NULL; + } + } + + free_irq(dev->irq, dev); /* release the IRQ */ return 0; } static void sonic_tx_timeout(struct net_device *dev) { - struct sonic_local *lp = (struct sonic_local *) dev->priv; - printk("%s: transmit timed out.\n", dev->name); - + struct sonic_local *lp = netdev_priv(dev); + int i; + /* Stop the interrupts for this */ + SONIC_WRITE(SONIC_IMR, 0); + /* We could resend the original skbs. Easier to re-initialise. */ + for (i = 0; i < SONIC_NUM_TDS; i++) { + if(lp->tx_laddr[i]) { + dma_unmap_single(lp->device, lp->tx_laddr[i], lp->tx_len[i], DMA_TO_DEVICE); + lp->tx_laddr[i] = (dma_addr_t)0; + } + if(lp->tx_skb[i]) { + dev_kfree_skb(lp->tx_skb[i]); + lp->tx_skb[i] = NULL; + } + } /* Try to restart the adaptor. */ sonic_init(dev); lp->stats.tx_errors++; @@ -100,60 +201,92 @@ static void sonic_tx_timeout(struct net_device *dev) /* * transmit packet + * + * Appends new TD during transmission thus avoiding any TX interrupts + * until we run out of TDs. + * This routine interacts closely with the ISR in that it may, + * set tx_skb[i] + * reset the status flags of the new TD + * set and reset EOL flags + * stop the tx queue + * The ISR interacts with this routine in various ways. It may, + * reset tx_skb[i] + * test the EOL and status flags of the TDs + * wake the tx queue + * Concurrently with all of this, the SONIC is potentially writing to + * the status flags of the TDs. + * Until some mutual exclusion is added, this code will not work with SMP. However, + * MIPS Jazz machines and m68k Macs were all uni-processor machines. */ + static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct sonic_local *lp = (struct sonic_local *) dev->priv; - unsigned int base_addr = dev->base_addr; - unsigned int laddr; - int entry, length; - - netif_stop_queue(dev); + struct sonic_local *lp = netdev_priv(dev); + dma_addr_t laddr; + int length; + int entry = lp->next_tx; if (sonic_debug > 2) printk("sonic_send_packet: skb=%p, dev=%p\n", skb, dev); + length = skb->len; + if (length < ETH_ZLEN) { + skb = skb_padto(skb, ETH_ZLEN); + if (skb == NULL) + return 0; + length = ETH_ZLEN; + } + /* * Map the packet data into the logical DMA address space */ - if ((laddr = vdma_alloc(CPHYSADDR(skb->data), skb->len)) == ~0UL) { - printk("%s: no VDMA entry for transmit available.\n", - dev->name); + + laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE); + if (!laddr) { + printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name); dev_kfree_skb(skb); - netif_start_queue(dev); return 1; } - entry = lp->cur_tx & SONIC_TDS_MASK; + + sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */ + sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1); /* single fragment */ + sonic_tda_put(dev, entry, SONIC_TD_PKTSIZE, length); /* length of packet */ + sonic_tda_put(dev, entry, SONIC_TD_FRAG_PTR_L, laddr & 0xffff); + sonic_tda_put(dev, entry, SONIC_TD_FRAG_PTR_H, laddr >> 16); + sonic_tda_put(dev, entry, SONIC_TD_FRAG_SIZE, length); + sonic_tda_put(dev, entry, SONIC_TD_LINK, + sonic_tda_get(dev, entry, SONIC_TD_LINK) | SONIC_EOL); + + /* + * Must set tx_skb[entry] only after clearing status, and + * before clearing EOL and before stopping queue + */ + wmb(); + lp->tx_len[entry] = length; lp->tx_laddr[entry] = laddr; lp->tx_skb[entry] = skb; - length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; - flush_cache_all(); + wmb(); + sonic_tda_put(dev, lp->eol_tx, SONIC_TD_LINK, + sonic_tda_get(dev, lp->eol_tx, SONIC_TD_LINK) & ~SONIC_EOL); + lp->eol_tx = entry; - /* - * Setup the transmit descriptor and issue the transmit command. - */ - lp->tda[entry].tx_status = 0; /* clear status */ - lp->tda[entry].tx_frag_count = 1; /* single fragment */ - lp->tda[entry].tx_pktsize = length; /* length of packet */ - lp->tda[entry].tx_frag_ptr_l = laddr & 0xffff; - lp->tda[entry].tx_frag_ptr_h = laddr >> 16; - lp->tda[entry].tx_frag_size = length; - lp->cur_tx++; - lp->stats.tx_bytes += length; + lp->next_tx = (entry + 1) & SONIC_TDS_MASK; + if (lp->tx_skb[lp->next_tx] != NULL) { + /* The ring is full, the ISR has yet to process the next TD. */ + if (sonic_debug > 3) + printk("%s: stopping queue\n", dev->name); + netif_stop_queue(dev); + /* after this packet, wait for ISR to free up some TDAs */ + } else netif_start_queue(dev); if (sonic_debug > 2) - printk("sonic_send_packet: issueing Tx command\n"); + printk("sonic_send_packet: issuing Tx command\n"); SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP); dev->trans_start = jiffies; - if (lp->cur_tx < lp->dirty_tx + SONIC_NUM_TDS) - netif_start_queue(dev); - else - lp->tx_full = 1; - return 0; } @@ -164,175 +297,199 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) static irqreturn_t sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - unsigned int base_addr = dev->base_addr; - struct sonic_local *lp; + struct sonic_local *lp = netdev_priv(dev); int status; if (dev == NULL) { - printk("sonic_interrupt: irq %d for unknown device.\n", irq); + printk(KERN_ERR "sonic_interrupt: irq %d for unknown device.\n", irq); return IRQ_NONE; } - lp = (struct sonic_local *) dev->priv; - - status = SONIC_READ(SONIC_ISR); - SONIC_WRITE(SONIC_ISR, 0x7fff); /* clear all bits */ - - if (sonic_debug > 2) - printk("sonic_interrupt: ISR=%x\n", status); - - if (status & SONIC_INT_PKTRX) { - sonic_rx(dev); /* got packet(s) */ - } - - if (status & SONIC_INT_TXDN) { - int dirty_tx = lp->dirty_tx; - - while (dirty_tx < lp->cur_tx) { - int entry = dirty_tx & SONIC_TDS_MASK; - int status = lp->tda[entry].tx_status; + if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT)) + return IRQ_NONE; - if (sonic_debug > 3) - printk - ("sonic_interrupt: status %d, cur_tx %d, dirty_tx %d\n", - status, lp->cur_tx, lp->dirty_tx); + do { + if (status & SONIC_INT_PKTRX) { + if (sonic_debug > 2) + printk("%s: packet rx\n", dev->name); + sonic_rx(dev); /* got packet(s) */ + SONIC_WRITE(SONIC_ISR, SONIC_INT_PKTRX); /* clear the interrupt */ + } - if (status == 0) { - /* It still hasn't been Txed, kick the sonic again */ - SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP); - break; - } + if (status & SONIC_INT_TXDN) { + int entry = lp->cur_tx; + int td_status; + int freed_some = 0; - /* put back EOL and free descriptor */ - lp->tda[entry].tx_frag_count = 0; - lp->tda[entry].tx_status = 0; - - if (status & 0x0001) - lp->stats.tx_packets++; - else { - lp->stats.tx_errors++; - if (status & 0x0642) - lp->stats.tx_aborted_errors++; - if (status & 0x0180) - lp->stats.tx_carrier_errors++; - if (status & 0x0020) - lp->stats.tx_window_errors++; - if (status & 0x0004) - lp->stats.tx_fifo_errors++; - } + /* At this point, cur_tx is the index of a TD that is one of: + * unallocated/freed (status set & tx_skb[entry] clear) + * allocated and sent (status set & tx_skb[entry] set ) + * allocated and not yet sent (status clear & tx_skb[entry] set ) + * still being allocated by sonic_send_packet (status clear & tx_skb[entry] clear) + */ - /* We must free the original skb */ - if (lp->tx_skb[entry]) { + if (sonic_debug > 2) + printk("%s: tx done\n", dev->name); + + while (lp->tx_skb[entry] != NULL) { + if ((td_status = sonic_tda_get(dev, entry, SONIC_TD_STATUS)) == 0) + break; + + if (td_status & 0x0001) { + lp->stats.tx_packets++; + lp->stats.tx_bytes += sonic_tda_get(dev, entry, SONIC_TD_PKTSIZE); + } else { + lp->stats.tx_errors++; + if (td_status & 0x0642) + lp->stats.tx_aborted_errors++; + if (td_status & 0x0180) + lp->stats.tx_carrier_errors++; + if (td_status & 0x0020) + lp->stats.tx_window_errors++; + if (td_status & 0x0004) + lp->stats.tx_fifo_errors++; + } + + /* We must free the original skb */ dev_kfree_skb_irq(lp->tx_skb[entry]); - lp->tx_skb[entry] = 0; + lp->tx_skb[entry] = NULL; + /* and unmap DMA buffer */ + dma_unmap_single(lp->device, lp->tx_laddr[entry], lp->tx_len[entry], DMA_TO_DEVICE); + lp->tx_laddr[entry] = (dma_addr_t)0; + freed_some = 1; + + if (sonic_tda_get(dev, entry, SONIC_TD_LINK) & SONIC_EOL) { + entry = (entry + 1) & SONIC_TDS_MASK; + break; + } + entry = (entry + 1) & SONIC_TDS_MASK; } - /* and the VDMA address */ - vdma_free(lp->tx_laddr[entry]); - dirty_tx++; - } - if (lp->tx_full - && dirty_tx + SONIC_NUM_TDS > lp->cur_tx + 2) { - /* The ring is no longer full, clear tbusy. */ - lp->tx_full = 0; - netif_wake_queue(dev); + if (freed_some || lp->tx_skb[entry] == NULL) + netif_wake_queue(dev); /* The ring is no longer full */ + lp->cur_tx = entry; + SONIC_WRITE(SONIC_ISR, SONIC_INT_TXDN); /* clear the interrupt */ } - lp->dirty_tx = dirty_tx; - } + /* + * check error conditions + */ + if (status & SONIC_INT_RFO) { + if (sonic_debug > 1) + printk("%s: rx fifo overrun\n", dev->name); + lp->stats.rx_fifo_errors++; + SONIC_WRITE(SONIC_ISR, SONIC_INT_RFO); /* clear the interrupt */ + } + if (status & SONIC_INT_RDE) { + if (sonic_debug > 1) + printk("%s: rx descriptors exhausted\n", dev->name); + lp->stats.rx_dropped++; + SONIC_WRITE(SONIC_ISR, SONIC_INT_RDE); /* clear the interrupt */ + } + if (status & SONIC_INT_RBAE) { + if (sonic_debug > 1) + printk("%s: rx buffer area exceeded\n", dev->name); + lp->stats.rx_dropped++; + SONIC_WRITE(SONIC_ISR, SONIC_INT_RBAE); /* clear the interrupt */ + } - /* - * check error conditions - */ - if (status & SONIC_INT_RFO) { - printk("%s: receive fifo underrun\n", dev->name); - lp->stats.rx_fifo_errors++; - } - if (status & SONIC_INT_RDE) { - printk("%s: receive descriptors exhausted\n", dev->name); - lp->stats.rx_dropped++; - } - if (status & SONIC_INT_RBE) { - printk("%s: receive buffer exhausted\n", dev->name); - lp->stats.rx_dropped++; - } - if (status & SONIC_INT_RBAE) { - printk("%s: receive buffer area exhausted\n", dev->name); - lp->stats.rx_dropped++; - } + /* counter overruns; all counters are 16bit wide */ + if (status & SONIC_INT_FAE) { + lp->stats.rx_frame_errors += 65536; + SONIC_WRITE(SONIC_ISR, SONIC_INT_FAE); /* clear the interrupt */ + } + if (status & SONIC_INT_CRC) { + lp->stats.rx_crc_errors += 65536; + SONIC_WRITE(SONIC_ISR, SONIC_INT_CRC); /* clear the interrupt */ + } + if (status & SONIC_INT_MP) { + lp->stats.rx_missed_errors += 65536; + SONIC_WRITE(SONIC_ISR, SONIC_INT_MP); /* clear the interrupt */ + } - /* counter overruns; all counters are 16bit wide */ - if (status & SONIC_INT_FAE) - lp->stats.rx_frame_errors += 65536; - if (status & SONIC_INT_CRC) - lp->stats.rx_crc_errors += 65536; - if (status & SONIC_INT_MP) - lp->stats.rx_missed_errors += 65536; + /* transmit error */ + if (status & SONIC_INT_TXER) { + if ((SONIC_READ(SONIC_TCR) & SONIC_TCR_FU) && (sonic_debug > 2)) + printk(KERN_ERR "%s: tx fifo underrun\n", dev->name); + SONIC_WRITE(SONIC_ISR, SONIC_INT_TXER); /* clear the interrupt */ + } - /* transmit error */ - if (status & SONIC_INT_TXER) - lp->stats.tx_errors++; + /* bus retry */ + if (status & SONIC_INT_BR) { + printk(KERN_ERR "%s: Bus retry occurred! Device interrupt disabled.\n", + dev->name); + /* ... to help debug DMA problems causing endless interrupts. */ + /* Bounce the eth interface to turn on the interrupt again. */ + SONIC_WRITE(SONIC_IMR, 0); + SONIC_WRITE(SONIC_ISR, SONIC_INT_BR); /* clear the interrupt */ + } - /* - * clear interrupt bits and return - */ - SONIC_WRITE(SONIC_ISR, status); + /* load CAM done */ + if (status & SONIC_INT_LCD) + SONIC_WRITE(SONIC_ISR, SONIC_INT_LCD); /* clear the interrupt */ + } while((status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT)); return IRQ_HANDLED; } /* - * We have a good packet(s), get it/them out of the buffers. + * We have a good packet(s), pass it/them up the network stack. */ static void sonic_rx(struct net_device *dev) { - unsigned int base_addr = dev->base_addr; - struct sonic_local *lp = (struct sonic_local *) dev->priv; - sonic_rd_t *rd = &lp->rda[lp->cur_rx & SONIC_RDS_MASK]; + struct sonic_local *lp = netdev_priv(dev); int status; - - while (rd->in_use == 0) { - struct sk_buff *skb; + int entry = lp->cur_rx; + + while (sonic_rda_get(dev, entry, SONIC_RD_IN_USE) == 0) { + struct sk_buff *used_skb; + struct sk_buff *new_skb; + dma_addr_t new_laddr; + u16 bufadr_l; + u16 bufadr_h; int pkt_len; - unsigned char *pkt_ptr; - status = rd->rx_status; - if (sonic_debug > 3) - printk("status %x, cur_rx %d, cur_rra %x\n", - status, lp->cur_rx, lp->cur_rra); + status = sonic_rda_get(dev, entry, SONIC_RD_STATUS); if (status & SONIC_RCR_PRX) { - pkt_len = rd->rx_pktlen; - pkt_ptr = - (char *) - sonic_chiptomem((rd->rx_pktptr_h << 16) + - rd->rx_pktptr_l); - - if (sonic_debug > 3) - printk - ("pktptr %p (rba %p) h:%x l:%x, bsize h:%x l:%x\n", - pkt_ptr, lp->rba, rd->rx_pktptr_h, - rd->rx_pktptr_l, - SONIC_READ(SONIC_RBWC1), - SONIC_READ(SONIC_RBWC0)); - /* Malloc up new buffer. */ - skb = dev_alloc_skb(pkt_len + 2); - if (skb == NULL) { - printk - ("%s: Memory squeeze, dropping packet.\n", - dev->name); + new_skb = dev_alloc_skb(SONIC_RBSIZE + 2); + if (new_skb == NULL) { + printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + break; + } + new_skb->dev = dev; + /* provide 16 byte IP header alignment unless DMA requires otherwise */ + if(SONIC_BUS_SCALE(lp->dma_bitmode) == 2) + skb_reserve(new_skb, 2); + + new_laddr = dma_map_single(lp->device, skb_put(new_skb, SONIC_RBSIZE), + SONIC_RBSIZE, DMA_FROM_DEVICE); + if (!new_laddr) { + dev_kfree_skb(new_skb); + printk(KERN_ERR "%s: Failed to map rx buffer, dropping packet.\n", dev->name); lp->stats.rx_dropped++; break; } - skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte align */ - skb_put(skb, pkt_len); /* Make room */ - eth_copy_and_sum(skb, pkt_ptr, pkt_len, 0); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); /* pass the packet to upper layers */ + + /* now we have a new skb to replace it, pass the used one up the stack */ + dma_unmap_single(lp->device, lp->rx_laddr[entry], SONIC_RBSIZE, DMA_FROM_DEVICE); + used_skb = lp->rx_skb[entry]; + pkt_len = sonic_rda_get(dev, entry, SONIC_RD_PKTLEN); + skb_trim(used_skb, pkt_len); + used_skb->protocol = eth_type_trans(used_skb, dev); + netif_rx(used_skb); dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; + /* and insert the new skb */ + lp->rx_laddr[entry] = new_laddr; + lp->rx_skb[entry] = new_skb; + + bufadr_l = (unsigned long)new_laddr & 0xffff; + bufadr_h = (unsigned long)new_laddr >> 16; + sonic_rra_put(dev, entry, SONIC_RR_BUFADR_L, bufadr_l); + sonic_rra_put(dev, entry, SONIC_RR_BUFADR_H, bufadr_h); } else { /* This should only happen, if we enable accepting broken packets. */ lp->stats.rx_errors++; @@ -341,29 +498,35 @@ static void sonic_rx(struct net_device *dev) if (status & SONIC_RCR_CRCR) lp->stats.rx_crc_errors++; } - - rd->in_use = 1; - rd = &lp->rda[(++lp->cur_rx) & SONIC_RDS_MASK]; - /* now give back the buffer to the receive buffer area */ if (status & SONIC_RCR_LPKT) { /* - * this was the last packet out of the current receice buffer + * this was the last packet out of the current receive buffer * give the buffer back to the SONIC */ - lp->cur_rra += sizeof(sonic_rr_t); - if (lp->cur_rra > - (lp->rra_laddr + - (SONIC_NUM_RRS - - 1) * sizeof(sonic_rr_t))) lp->cur_rra = - lp->rra_laddr; - SONIC_WRITE(SONIC_RWP, lp->cur_rra & 0xffff); + lp->cur_rwp += SIZEOF_SONIC_RR * SONIC_BUS_SCALE(lp->dma_bitmode); + if (lp->cur_rwp >= lp->rra_end) lp->cur_rwp = lp->rra_laddr & 0xffff; + SONIC_WRITE(SONIC_RWP, lp->cur_rwp); + if (SONIC_READ(SONIC_ISR) & SONIC_INT_RBE) { + if (sonic_debug > 2) + printk("%s: rx buffer exhausted\n", dev->name); + SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE); /* clear the flag */ + } } else - printk - ("%s: rx desc without RCR_LPKT. Shouldn't happen !?\n", + printk(KERN_ERR "%s: rx desc without RCR_LPKT. Shouldn't happen !?\n", dev->name); + /* + * give back the descriptor + */ + sonic_rda_put(dev, entry, SONIC_RD_LINK, + sonic_rda_get(dev, entry, SONIC_RD_LINK) | SONIC_EOL); + sonic_rda_put(dev, entry, SONIC_RD_IN_USE, 1); + sonic_rda_put(dev, lp->eol_rx, SONIC_RD_LINK, + sonic_rda_get(dev, lp->eol_rx, SONIC_RD_LINK) & ~SONIC_EOL); + lp->eol_rx = entry; + lp->cur_rx = entry = (entry + 1) & SONIC_RDS_MASK; } /* - * If any worth-while packets have been received, dev_rint() + * If any worth-while packets have been received, netif_rx() * has done a mark_bh(NET_BH) for us and will work on them * when we get to the bottom-half routine. */ @@ -376,8 +539,7 @@ static void sonic_rx(struct net_device *dev) */ static struct net_device_stats *sonic_get_stats(struct net_device *dev) { - struct sonic_local *lp = (struct sonic_local *) dev->priv; - unsigned int base_addr = dev->base_addr; + struct sonic_local *lp = netdev_priv(dev); /* read the tally counter from the SONIC and reset them */ lp->stats.rx_crc_errors += SONIC_READ(SONIC_CRCT); @@ -396,8 +558,7 @@ static struct net_device_stats *sonic_get_stats(struct net_device *dev) */ static void sonic_multicast_list(struct net_device *dev) { - struct sonic_local *lp = (struct sonic_local *) dev->priv; - unsigned int base_addr = dev->base_addr; + struct sonic_local *lp = netdev_priv(dev); unsigned int rcr; struct dev_mc_list *dmi = dev->mc_list; unsigned char *addr; @@ -413,20 +574,15 @@ static void sonic_multicast_list(struct net_device *dev) rcr |= SONIC_RCR_AMC; } else { if (sonic_debug > 2) - printk - ("sonic_multicast_list: mc_count %d\n", - dev->mc_count); - lp->cda.cam_enable = 1; /* always enable our own address */ + printk("sonic_multicast_list: mc_count %d\n", dev->mc_count); + sonic_set_cam_enable(dev, 1); /* always enable our own address */ for (i = 1; i <= dev->mc_count; i++) { addr = dmi->dmi_addr; dmi = dmi->next; - lp->cda.cam_desc[i].cam_cap0 = - addr[1] << 8 | addr[0]; - lp->cda.cam_desc[i].cam_cap1 = - addr[3] << 8 | addr[2]; - lp->cda.cam_desc[i].cam_cap2 = - addr[5] << 8 | addr[4]; - lp->cda.cam_enable |= (1 << i); + sonic_cda_put(dev, i, SONIC_CD_CAP0, addr[1] << 8 | addr[0]); + sonic_cda_put(dev, i, SONIC_CD_CAP1, addr[3] << 8 | addr[2]); + sonic_cda_put(dev, i, SONIC_CD_CAP2, addr[5] << 8 | addr[4]); + sonic_set_cam_enable(dev, sonic_get_cam_enable(dev) | (1 << i)); } SONIC_WRITE(SONIC_CDC, 16); /* issue Load CAM command */ @@ -447,19 +603,16 @@ static void sonic_multicast_list(struct net_device *dev) */ static int sonic_init(struct net_device *dev) { - unsigned int base_addr = dev->base_addr; unsigned int cmd; - struct sonic_local *lp = (struct sonic_local *) dev->priv; - unsigned int rra_start; - unsigned int rra_end; + struct sonic_local *lp = netdev_priv(dev); int i; /* * put the Sonic into software-reset mode and * disable all interrupts */ - SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_IMR, 0); + SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); /* @@ -475,34 +628,32 @@ static int sonic_init(struct net_device *dev) if (sonic_debug > 2) printk("sonic_init: initialize receive resource area\n"); - rra_start = lp->rra_laddr & 0xffff; - rra_end = - (rra_start + (SONIC_NUM_RRS * sizeof(sonic_rr_t))) & 0xffff; - for (i = 0; i < SONIC_NUM_RRS; i++) { - lp->rra[i].rx_bufadr_l = - (lp->rba_laddr + i * SONIC_RBSIZE) & 0xffff; - lp->rra[i].rx_bufadr_h = - (lp->rba_laddr + i * SONIC_RBSIZE) >> 16; - lp->rra[i].rx_bufsize_l = SONIC_RBSIZE >> 1; - lp->rra[i].rx_bufsize_h = 0; + u16 bufadr_l = (unsigned long)lp->rx_laddr[i] & 0xffff; + u16 bufadr_h = (unsigned long)lp->rx_laddr[i] >> 16; + sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l); + sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h); + sonic_rra_put(dev, i, SONIC_RR_BUFSIZE_L, SONIC_RBSIZE >> 1); + sonic_rra_put(dev, i, SONIC_RR_BUFSIZE_H, 0); } /* initialize all RRA registers */ - SONIC_WRITE(SONIC_RSA, rra_start); - SONIC_WRITE(SONIC_REA, rra_end); - SONIC_WRITE(SONIC_RRP, rra_start); - SONIC_WRITE(SONIC_RWP, rra_end); + lp->rra_end = (lp->rra_laddr + SONIC_NUM_RRS * SIZEOF_SONIC_RR * + SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff; + lp->cur_rwp = (lp->rra_laddr + (SONIC_NUM_RRS - 1) * SIZEOF_SONIC_RR * + SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff; + + SONIC_WRITE(SONIC_RSA, lp->rra_laddr & 0xffff); + SONIC_WRITE(SONIC_REA, lp->rra_end); + SONIC_WRITE(SONIC_RRP, lp->rra_laddr & 0xffff); + SONIC_WRITE(SONIC_RWP, lp->cur_rwp); SONIC_WRITE(SONIC_URRA, lp->rra_laddr >> 16); - SONIC_WRITE(SONIC_EOBC, (SONIC_RBSIZE - 2) >> 1); - - lp->cur_rra = - lp->rra_laddr + (SONIC_NUM_RRS - 1) * sizeof(sonic_rr_t); + SONIC_WRITE(SONIC_EOBC, (SONIC_RBSIZE >> 1) - (lp->dma_bitmode ? 2 : 1)); /* load the resource pointers */ if (sonic_debug > 3) - printk("sonic_init: issueing RRRA command\n"); - + printk("sonic_init: issuing RRRA command\n"); + SONIC_WRITE(SONIC_CMD, SONIC_CR_RRRA); i = 0; while (i++ < 100) { @@ -511,27 +662,30 @@ static int sonic_init(struct net_device *dev) } if (sonic_debug > 2) - printk("sonic_init: status=%x\n", SONIC_READ(SONIC_CMD)); - + printk("sonic_init: status=%x i=%d\n", SONIC_READ(SONIC_CMD), i); + /* * Initialize the receive descriptors so that they * become a circular linked list, ie. let the last * descriptor point to the first again. */ if (sonic_debug > 2) - printk("sonic_init: initialize receive descriptors\n"); - for (i = 0; i < SONIC_NUM_RDS; i++) { - lp->rda[i].rx_status = 0; - lp->rda[i].rx_pktlen = 0; - lp->rda[i].rx_pktptr_l = 0; - lp->rda[i].rx_pktptr_h = 0; - lp->rda[i].rx_seqno = 0; - lp->rda[i].in_use = 1; - lp->rda[i].link = - lp->rda_laddr + (i + 1) * sizeof(sonic_rd_t); + printk("sonic_init: initialize receive descriptors\n"); + for (i=0; i<SONIC_NUM_RDS; i++) { + sonic_rda_put(dev, i, SONIC_RD_STATUS, 0); + sonic_rda_put(dev, i, SONIC_RD_PKTLEN, 0); + sonic_rda_put(dev, i, SONIC_RD_PKTPTR_L, 0); + sonic_rda_put(dev, i, SONIC_RD_PKTPTR_H, 0); + sonic_rda_put(dev, i, SONIC_RD_SEQNO, 0); + sonic_rda_put(dev, i, SONIC_RD_IN_USE, 1); + sonic_rda_put(dev, i, SONIC_RD_LINK, + lp->rda_laddr + + ((i+1) * SIZEOF_SONIC_RD * SONIC_BUS_SCALE(lp->dma_bitmode))); } /* fix last descriptor */ - lp->rda[SONIC_NUM_RDS - 1].link = lp->rda_laddr; + sonic_rda_put(dev, SONIC_NUM_RDS - 1, SONIC_RD_LINK, + (lp->rda_laddr & 0xffff) | SONIC_EOL); + lp->eol_rx = SONIC_NUM_RDS - 1; lp->cur_rx = 0; SONIC_WRITE(SONIC_URDA, lp->rda_laddr >> 16); SONIC_WRITE(SONIC_CRDA, lp->rda_laddr & 0xffff); @@ -542,34 +696,34 @@ static int sonic_init(struct net_device *dev) if (sonic_debug > 2) printk("sonic_init: initialize transmit descriptors\n"); for (i = 0; i < SONIC_NUM_TDS; i++) { - lp->tda[i].tx_status = 0; - lp->tda[i].tx_config = 0; - lp->tda[i].tx_pktsize = 0; - lp->tda[i].tx_frag_count = 0; - lp->tda[i].link = - (lp->tda_laddr + - (i + 1) * sizeof(sonic_td_t)) | SONIC_END_OF_LINKS; + sonic_tda_put(dev, i, SONIC_TD_STATUS, 0); + sonic_tda_put(dev, i, SONIC_TD_CONFIG, 0); + sonic_tda_put(dev, i, SONIC_TD_PKTSIZE, 0); + sonic_tda_put(dev, i, SONIC_TD_FRAG_COUNT, 0); + sonic_tda_put(dev, i, SONIC_TD_LINK, + (lp->tda_laddr & 0xffff) + + (i + 1) * SIZEOF_SONIC_TD * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->tx_skb[i] = NULL; } - lp->tda[SONIC_NUM_TDS - 1].link = - (lp->tda_laddr & 0xffff) | SONIC_END_OF_LINKS; + /* fix last descriptor */ + sonic_tda_put(dev, SONIC_NUM_TDS - 1, SONIC_TD_LINK, + (lp->tda_laddr & 0xffff)); SONIC_WRITE(SONIC_UTDA, lp->tda_laddr >> 16); SONIC_WRITE(SONIC_CTDA, lp->tda_laddr & 0xffff); - lp->cur_tx = lp->dirty_tx = 0; - + lp->cur_tx = lp->next_tx = 0; + lp->eol_tx = SONIC_NUM_TDS - 1; + /* * put our own address to CAM desc[0] */ - lp->cda.cam_desc[0].cam_cap0 = - dev->dev_addr[1] << 8 | dev->dev_addr[0]; - lp->cda.cam_desc[0].cam_cap1 = - dev->dev_addr[3] << 8 | dev->dev_addr[2]; - lp->cda.cam_desc[0].cam_cap2 = - dev->dev_addr[5] << 8 | dev->dev_addr[4]; - lp->cda.cam_enable = 1; + sonic_cda_put(dev, 0, SONIC_CD_CAP0, dev->dev_addr[1] << 8 | dev->dev_addr[0]); + sonic_cda_put(dev, 0, SONIC_CD_CAP1, dev->dev_addr[3] << 8 | dev->dev_addr[2]); + sonic_cda_put(dev, 0, SONIC_CD_CAP2, dev->dev_addr[5] << 8 | dev->dev_addr[4]); + sonic_set_cam_enable(dev, 1); for (i = 0; i < 16; i++) - lp->cda.cam_desc[i].cam_entry_pointer = i; + sonic_cda_put(dev, i, SONIC_CD_ENTRY_POINTER, i); /* * initialize CAM registers @@ -588,8 +742,8 @@ static int sonic_init(struct net_device *dev) break; } if (sonic_debug > 2) { - printk("sonic_init: CMD=%x, ISR=%x\n", - SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR)); + printk("sonic_init: CMD=%x, ISR=%x\n, i=%d", + SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR), i); } /* @@ -604,7 +758,7 @@ static int sonic_init(struct net_device *dev) cmd = SONIC_READ(SONIC_CMD); if ((cmd & SONIC_CR_RXEN) == 0 || (cmd & SONIC_CR_STP) == 0) - printk("sonic_init: failed, status=%x\n", cmd); + printk(KERN_ERR "sonic_init: failed, status=%x\n", cmd); if (sonic_debug > 2) printk("sonic_init: new status=%x\n", diff --git a/drivers/net/sonic.h b/drivers/net/sonic.h index c4a6d58e4af..cede969a8ba 100644 --- a/drivers/net/sonic.h +++ b/drivers/net/sonic.h @@ -1,5 +1,5 @@ /* - * Helpfile for sonic.c + * Header file for sonic.c * * (C) Waldorf Electronics, Germany * Written by Andreas Busse @@ -9,10 +9,16 @@ * and pad structure members must be exchanged. Also, the structures * need to be changed accordingly to the bus size. * - * 981229 MSch: did just that for the 68k Mac port (32 bit, big endian), - * see CONFIG_MACSONIC branch below. + * 981229 MSch: did just that for the 68k Mac port (32 bit, big endian) * + * 990611 David Huggins-Daines <dhd@debian.org>: This machine abstraction + * does not cope with 16-bit bus sizes very well. Therefore I have + * rewritten it with ugly macros and evil inlines. + * + * 050625 Finn Thain: introduced more 32-bit cards and dhd's support + * for 16-bit cards (from the mac68k project). */ + #ifndef SONIC_H #define SONIC_H @@ -83,6 +89,7 @@ /* * Error counters */ + #define SONIC_CRCT 0x2c #define SONIC_FAET 0x2d #define SONIC_MPT 0x2e @@ -182,14 +189,14 @@ #define SONIC_INT_BR 0x4000 #define SONIC_INT_HBL 0x2000 -#define SONIC_INT_LCD 0x1000 -#define SONIC_INT_PINT 0x0800 -#define SONIC_INT_PKTRX 0x0400 -#define SONIC_INT_TXDN 0x0200 -#define SONIC_INT_TXER 0x0100 -#define SONIC_INT_TC 0x0080 -#define SONIC_INT_RDE 0x0040 -#define SONIC_INT_RBE 0x0020 +#define SONIC_INT_LCD 0x1000 +#define SONIC_INT_PINT 0x0800 +#define SONIC_INT_PKTRX 0x0400 +#define SONIC_INT_TXDN 0x0200 +#define SONIC_INT_TXER 0x0100 +#define SONIC_INT_TC 0x0080 +#define SONIC_INT_RDE 0x0040 +#define SONIC_INT_RBE 0x0020 #define SONIC_INT_RBAE 0x0010 #define SONIC_INT_CRC 0x0008 #define SONIC_INT_FAE 0x0004 @@ -201,224 +208,61 @@ * The interrupts we allow. */ -#define SONIC_IMR_DEFAULT (SONIC_INT_BR | \ - SONIC_INT_LCD | \ - SONIC_INT_PINT | \ +#define SONIC_IMR_DEFAULT ( SONIC_INT_BR | \ + SONIC_INT_LCD | \ + SONIC_INT_RFO | \ SONIC_INT_PKTRX | \ SONIC_INT_TXDN | \ SONIC_INT_TXER | \ SONIC_INT_RDE | \ - SONIC_INT_RBE | \ SONIC_INT_RBAE | \ SONIC_INT_CRC | \ SONIC_INT_FAE | \ SONIC_INT_MP) -#define SONIC_END_OF_LINKS 0x0001 - - -#ifdef CONFIG_MACSONIC -/* - * Big endian like structures on 680x0 Macs - */ - -typedef struct { - u32 rx_bufadr_l; /* receive buffer ptr */ - u32 rx_bufadr_h; - - u32 rx_bufsize_l; /* no. of words in the receive buffer */ - u32 rx_bufsize_h; -} sonic_rr_t; - -/* - * Sonic receive descriptor. Receive descriptors are - * kept in a linked list of these structures. - */ - -typedef struct { - SREGS_PAD(pad0); - u16 rx_status; /* status after reception of a packet */ - SREGS_PAD(pad1); - u16 rx_pktlen; /* length of the packet incl. CRC */ - - /* - * Pointers to the location in the receive buffer area (RBA) - * where the packet resides. A packet is always received into - * a contiguous piece of memory. - */ - SREGS_PAD(pad2); - u16 rx_pktptr_l; - SREGS_PAD(pad3); - u16 rx_pktptr_h; - - SREGS_PAD(pad4); - u16 rx_seqno; /* sequence no. */ - - SREGS_PAD(pad5); - u16 link; /* link to next RDD (end if EOL bit set) */ - - /* - * Owner of this descriptor, 0= driver, 1=sonic - */ - - SREGS_PAD(pad6); - u16 in_use; - - caddr_t rda_next; /* pointer to next RD */ -} sonic_rd_t; - - -/* - * Describes a Transmit Descriptor - */ -typedef struct { - SREGS_PAD(pad0); - u16 tx_status; /* status after transmission of a packet */ - SREGS_PAD(pad1); - u16 tx_config; /* transmit configuration for this packet */ - SREGS_PAD(pad2); - u16 tx_pktsize; /* size of the packet to be transmitted */ - SREGS_PAD(pad3); - u16 tx_frag_count; /* no. of fragments */ - - SREGS_PAD(pad4); - u16 tx_frag_ptr_l; - SREGS_PAD(pad5); - u16 tx_frag_ptr_h; - SREGS_PAD(pad6); - u16 tx_frag_size; - - SREGS_PAD(pad7); - u16 link; /* ptr to next descriptor */ -} sonic_td_t; - - -/* - * Describes an entry in the CAM Descriptor Area. - */ - -typedef struct { - SREGS_PAD(pad0); - u16 cam_entry_pointer; - SREGS_PAD(pad1); - u16 cam_cap0; - SREGS_PAD(pad2); - u16 cam_cap1; - SREGS_PAD(pad3); - u16 cam_cap2; -} sonic_cd_t; - +#define SONIC_EOL 0x0001 #define CAM_DESCRIPTORS 16 - -typedef struct { - sonic_cd_t cam_desc[CAM_DESCRIPTORS]; - SREGS_PAD(pad); - u16 cam_enable; -} sonic_cda_t; - -#else /* original declarations, little endian 32 bit */ - -/* - * structure definitions - */ - -typedef struct { - u32 rx_bufadr_l; /* receive buffer ptr */ - u32 rx_bufadr_h; - - u32 rx_bufsize_l; /* no. of words in the receive buffer */ - u32 rx_bufsize_h; -} sonic_rr_t; - -/* - * Sonic receive descriptor. Receive descriptors are - * kept in a linked list of these structures. - */ - -typedef struct { - u16 rx_status; /* status after reception of a packet */ - SREGS_PAD(pad0); - u16 rx_pktlen; /* length of the packet incl. CRC */ - SREGS_PAD(pad1); - - /* - * Pointers to the location in the receive buffer area (RBA) - * where the packet resides. A packet is always received into - * a contiguous piece of memory. - */ - u16 rx_pktptr_l; - SREGS_PAD(pad2); - u16 rx_pktptr_h; - SREGS_PAD(pad3); - - u16 rx_seqno; /* sequence no. */ - SREGS_PAD(pad4); - - u16 link; /* link to next RDD (end if EOL bit set) */ - SREGS_PAD(pad5); - - /* - * Owner of this descriptor, 0= driver, 1=sonic - */ - - u16 in_use; - SREGS_PAD(pad6); - - caddr_t rda_next; /* pointer to next RD */ -} sonic_rd_t; - - -/* - * Describes a Transmit Descriptor - */ -typedef struct { - u16 tx_status; /* status after transmission of a packet */ - SREGS_PAD(pad0); - u16 tx_config; /* transmit configuration for this packet */ - SREGS_PAD(pad1); - u16 tx_pktsize; /* size of the packet to be transmitted */ - SREGS_PAD(pad2); - u16 tx_frag_count; /* no. of fragments */ - SREGS_PAD(pad3); - - u16 tx_frag_ptr_l; - SREGS_PAD(pad4); - u16 tx_frag_ptr_h; - SREGS_PAD(pad5); - u16 tx_frag_size; - SREGS_PAD(pad6); - - u16 link; /* ptr to next descriptor */ - SREGS_PAD(pad7); -} sonic_td_t; - - -/* - * Describes an entry in the CAM Descriptor Area. - */ - -typedef struct { - u16 cam_entry_pointer; - SREGS_PAD(pad0); - u16 cam_cap0; - SREGS_PAD(pad1); - u16 cam_cap1; - SREGS_PAD(pad2); - u16 cam_cap2; - SREGS_PAD(pad3); -} sonic_cd_t; - -#define CAM_DESCRIPTORS 16 - - -typedef struct { - sonic_cd_t cam_desc[CAM_DESCRIPTORS]; - u16 cam_enable; - SREGS_PAD(pad); -} sonic_cda_t; -#endif /* endianness */ +/* Offsets in the various DMA buffers accessed by the SONIC */ + +#define SONIC_BITMODE16 0 +#define SONIC_BITMODE32 1 +#define SONIC_BUS_SCALE(bitmode) ((bitmode) ? 4 : 2) +/* Note! These are all measured in bus-size units, so use SONIC_BUS_SCALE */ +#define SIZEOF_SONIC_RR 4 +#define SONIC_RR_BUFADR_L 0 +#define SONIC_RR_BUFADR_H 1 +#define SONIC_RR_BUFSIZE_L 2 +#define SONIC_RR_BUFSIZE_H 3 + +#define SIZEOF_SONIC_RD 7 +#define SONIC_RD_STATUS 0 +#define SONIC_RD_PKTLEN 1 +#define SONIC_RD_PKTPTR_L 2 +#define SONIC_RD_PKTPTR_H 3 +#define SONIC_RD_SEQNO 4 +#define SONIC_RD_LINK 5 +#define SONIC_RD_IN_USE 6 + +#define SIZEOF_SONIC_TD 8 +#define SONIC_TD_STATUS 0 +#define SONIC_TD_CONFIG 1 +#define SONIC_TD_PKTSIZE 2 +#define SONIC_TD_FRAG_COUNT 3 +#define SONIC_TD_FRAG_PTR_L 4 +#define SONIC_TD_FRAG_PTR_H 5 +#define SONIC_TD_FRAG_SIZE 6 +#define SONIC_TD_LINK 7 + +#define SIZEOF_SONIC_CD 4 +#define SONIC_CD_ENTRY_POINTER 0 +#define SONIC_CD_CAP0 1 +#define SONIC_CD_CAP1 2 +#define SONIC_CD_CAP2 3 + +#define SIZEOF_SONIC_CDA ((CAM_DESCRIPTORS * SIZEOF_SONIC_CD) + 1) +#define SONIC_CDA_CAM_ENABLE (CAM_DESCRIPTORS * SIZEOF_SONIC_CD) /* * Some tunables for the buffer areas. Power of 2 is required @@ -426,44 +270,60 @@ typedef struct { * * MSch: use more buffer space for the slow m68k Macs! */ -#ifdef CONFIG_MACSONIC -#define SONIC_NUM_RRS 32 /* number of receive resources */ -#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */ -#define SONIC_NUM_TDS 32 /* number of transmit descriptors */ -#else -#define SONIC_NUM_RRS 16 /* number of receive resources */ -#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */ -#define SONIC_NUM_TDS 16 /* number of transmit descriptors */ -#endif -#define SONIC_RBSIZE 1520 /* size of one resource buffer */ +#define SONIC_NUM_RRS 16 /* number of receive resources */ +#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */ +#define SONIC_NUM_TDS 16 /* number of transmit descriptors */ -#define SONIC_RDS_MASK (SONIC_NUM_RDS-1) -#define SONIC_TDS_MASK (SONIC_NUM_TDS-1) +#define SONIC_RDS_MASK (SONIC_NUM_RDS-1) +#define SONIC_TDS_MASK (SONIC_NUM_TDS-1) +#define SONIC_RBSIZE 1520 /* size of one resource buffer */ + +/* Again, measured in bus size units! */ +#define SIZEOF_SONIC_DESC (SIZEOF_SONIC_CDA \ + + (SIZEOF_SONIC_TD * SONIC_NUM_TDS) \ + + (SIZEOF_SONIC_RD * SONIC_NUM_RDS) \ + + (SIZEOF_SONIC_RR * SONIC_NUM_RRS)) /* Information that need to be kept for each board. */ struct sonic_local { - sonic_cda_t cda; /* virtual CPU address of CDA */ - sonic_td_t tda[SONIC_NUM_TDS]; /* transmit descriptor area */ - sonic_rr_t rra[SONIC_NUM_RRS]; /* receive resource area */ - sonic_rd_t rda[SONIC_NUM_RDS]; /* receive descriptor area */ - struct sk_buff *tx_skb[SONIC_NUM_TDS]; /* skbuffs for packets to transmit */ - unsigned int tx_laddr[SONIC_NUM_TDS]; /* logical DMA address fro skbuffs */ - unsigned char *rba; /* start of receive buffer areas */ - unsigned int cda_laddr; /* logical DMA address of CDA */ - unsigned int tda_laddr; /* logical DMA address of TDA */ - unsigned int rra_laddr; /* logical DMA address of RRA */ - unsigned int rda_laddr; /* logical DMA address of RDA */ - unsigned int rba_laddr; /* logical DMA address of RBA */ - unsigned int cur_rra; /* current indexes to resource areas */ + /* Bus size. 0 == 16 bits, 1 == 32 bits. */ + int dma_bitmode; + /* Register offset within the longword (independent of endianness, + and varies from one type of Macintosh SONIC to another + (Aarrgh)) */ + int reg_offset; + void *descriptors; + /* Crud. These areas have to be within the same 64K. Therefore + we allocate a desriptors page, and point these to places within it. */ + void *cda; /* CAM descriptor area */ + void *tda; /* Transmit descriptor area */ + void *rra; /* Receive resource area */ + void *rda; /* Receive descriptor area */ + struct sk_buff* volatile rx_skb[SONIC_NUM_RRS]; /* packets to be received */ + struct sk_buff* volatile tx_skb[SONIC_NUM_TDS]; /* packets to be transmitted */ + unsigned int tx_len[SONIC_NUM_TDS]; /* lengths of tx DMA mappings */ + /* Logical DMA addresses on MIPS, bus addresses on m68k + * (so "laddr" is a bit misleading) */ + dma_addr_t descriptors_laddr; + u32 cda_laddr; /* logical DMA address of CDA */ + u32 tda_laddr; /* logical DMA address of TDA */ + u32 rra_laddr; /* logical DMA address of RRA */ + u32 rda_laddr; /* logical DMA address of RDA */ + dma_addr_t rx_laddr[SONIC_NUM_RRS]; /* logical DMA addresses of rx skbuffs */ + dma_addr_t tx_laddr[SONIC_NUM_TDS]; /* logical DMA addresses of tx skbuffs */ + unsigned int rra_end; + unsigned int cur_rwp; unsigned int cur_rx; - unsigned int cur_tx; - unsigned int dirty_tx; /* last unacked transmit packet */ - char tx_full; + unsigned int cur_tx; /* first unacked transmit packet */ + unsigned int eol_rx; + unsigned int eol_tx; /* last unacked transmit packet */ + unsigned int next_tx; /* next free TD */ + struct device *device; /* generic device */ struct net_device_stats stats; }; -#define TX_TIMEOUT 6 +#define TX_TIMEOUT (3 * HZ) /* Index to functions, as function prototypes. */ @@ -477,6 +337,114 @@ static void sonic_multicast_list(struct net_device *dev); static int sonic_init(struct net_device *dev); static void sonic_tx_timeout(struct net_device *dev); +/* Internal inlines for reading/writing DMA buffers. Note that bus + size and endianness matter here, whereas they don't for registers, + as far as we can tell. */ +/* OpenBSD calls this "SWO". I'd like to think that sonic_buf_put() + is a much better name. */ +static inline void sonic_buf_put(void* base, int bitmode, + int offset, __u16 val) +{ + if (bitmode) +#ifdef __BIG_ENDIAN + ((__u16 *) base + (offset*2))[1] = val; +#else + ((__u16 *) base + (offset*2))[0] = val; +#endif + else + ((__u16 *) base)[offset] = val; +} + +static inline __u16 sonic_buf_get(void* base, int bitmode, + int offset) +{ + if (bitmode) +#ifdef __BIG_ENDIAN + return ((volatile __u16 *) base + (offset*2))[1]; +#else + return ((volatile __u16 *) base + (offset*2))[0]; +#endif + else + return ((volatile __u16 *) base)[offset]; +} + +/* Inlines that you should actually use for reading/writing DMA buffers */ +static inline void sonic_cda_put(struct net_device* dev, int entry, + int offset, __u16 val) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + sonic_buf_put(lp->cda, lp->dma_bitmode, + (entry * SIZEOF_SONIC_CD) + offset, val); +} + +static inline __u16 sonic_cda_get(struct net_device* dev, int entry, + int offset) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + return sonic_buf_get(lp->cda, lp->dma_bitmode, + (entry * SIZEOF_SONIC_CD) + offset); +} + +static inline void sonic_set_cam_enable(struct net_device* dev, __u16 val) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + sonic_buf_put(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE, val); +} + +static inline __u16 sonic_get_cam_enable(struct net_device* dev) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + return sonic_buf_get(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE); +} + +static inline void sonic_tda_put(struct net_device* dev, int entry, + int offset, __u16 val) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + sonic_buf_put(lp->tda, lp->dma_bitmode, + (entry * SIZEOF_SONIC_TD) + offset, val); +} + +static inline __u16 sonic_tda_get(struct net_device* dev, int entry, + int offset) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + return sonic_buf_get(lp->tda, lp->dma_bitmode, + (entry * SIZEOF_SONIC_TD) + offset); +} + +static inline void sonic_rda_put(struct net_device* dev, int entry, + int offset, __u16 val) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + sonic_buf_put(lp->rda, lp->dma_bitmode, + (entry * SIZEOF_SONIC_RD) + offset, val); +} + +static inline __u16 sonic_rda_get(struct net_device* dev, int entry, + int offset) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + return sonic_buf_get(lp->rda, lp->dma_bitmode, + (entry * SIZEOF_SONIC_RD) + offset); +} + +static inline void sonic_rra_put(struct net_device* dev, int entry, + int offset, __u16 val) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + sonic_buf_put(lp->rra, lp->dma_bitmode, + (entry * SIZEOF_SONIC_RR) + offset, val); +} + +static inline __u16 sonic_rra_get(struct net_device* dev, int entry, + int offset) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + return sonic_buf_get(lp->rra, lp->dma_bitmode, + (entry * SIZEOF_SONIC_RR) + offset); +} + static const char *version = "sonic.c:v0.92 20.9.98 tsbogend@alpha.franken.de\n"; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 368b8fb1402..6d4ab1e333b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -66,8 +66,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.35" -#define DRV_MODULE_RELDATE "August 6, 2005" +#define DRV_MODULE_VERSION "3.37" +#define DRV_MODULE_RELDATE "August 25, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -7865,8 +7865,6 @@ static int tg3_test_loopback(struct tg3 *tp) err = -EIO; - tg3_abort_hw(tp, 1); - tg3_reset_hw(tp); mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) | @@ -8970,6 +8968,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) tp->phy_id = hw_phy_id; if (hw_phy_id_masked == PHY_ID_BCM8002) tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES; + else + tp->tg3_flags2 &= ~TG3_FLG2_PHY_SERDES; } else { if (tp->phy_id != PHY_ID_INVALID) { /* Do nothing, phy ID already set up in diff --git a/drivers/net/tokenring/Kconfig b/drivers/net/tokenring/Kconfig index 23d0fa4bbce..e4cfc80b283 100644 --- a/drivers/net/tokenring/Kconfig +++ b/drivers/net/tokenring/Kconfig @@ -84,7 +84,7 @@ config 3C359 config TMS380TR tristate "Generic TMS380 Token Ring ISA/PCI adapter support" - depends on TR && (PCI || ISA) + depends on TR && (PCI || ISA && ISA_DMA_API || MCA) select FW_LOADER ---help--- This driver provides generic support for token ring adapters @@ -158,7 +158,7 @@ config ABYSS config MADGEMC tristate "Madge Smart 16/4 Ringnode MicroChannel" - depends on TR && TMS380TR && MCA_LEGACY + depends on TR && TMS380TR && MCA help This tms380 module supports the Madge Smart 16/4 MC16 and MC32 MicroChannel adapters. diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c index 87103c40099..9345e68c451 100644 --- a/drivers/net/tokenring/abyss.c +++ b/drivers/net/tokenring/abyss.c @@ -139,7 +139,7 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_ */ dev->base_addr += 0x10; - ret = tmsdev_init(dev, PCI_MAX_ADDRESS, pdev); + ret = tmsdev_init(dev, &pdev->dev); if (ret) { printk("%s: unable to get memory for dev->priv.\n", dev->name); diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index 659cbdbef7f..3a25d191ea4 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -20,7 +20,7 @@ static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n"; #include <linux/module.h> -#include <linux/mca-legacy.h> +#include <linux/mca.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/pci.h> @@ -38,9 +38,7 @@ static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n"; #define MADGEMC_IO_EXTENT 32 #define MADGEMC_SIF_OFFSET 0x08 -struct madgemc_card { - struct net_device *dev; - +struct card_info { /* * These are read from the BIA ROM. */ @@ -57,16 +55,12 @@ struct madgemc_card { unsigned int arblevel:4; unsigned int ringspeed:2; /* 0 = 4mb, 1 = 16, 2 = Auto/none */ unsigned int cabletype:1; /* 0 = RJ45, 1 = DB9 */ - - struct madgemc_card *next; }; -static struct madgemc_card *madgemc_card_list; - static int madgemc_open(struct net_device *dev); static int madgemc_close(struct net_device *dev); static int madgemc_chipset_init(struct net_device *dev); -static void madgemc_read_rom(struct madgemc_card *card); +static void madgemc_read_rom(struct net_device *dev, struct card_info *card); static unsigned short madgemc_setnselout_pins(struct net_device *dev); static void madgemc_setcabletype(struct net_device *dev, int type); @@ -151,261 +145,237 @@ static void madgemc_sifwritew(struct net_device *dev, unsigned short val, unsign -static int __init madgemc_probe(void) +static int __devinit madgemc_probe(struct device *device) { static int versionprinted; struct net_device *dev; struct net_local *tp; - struct madgemc_card *card; - int i,slot = 0; - __u8 posreg[4]; - - if (!MCA_bus) - return -1; - - while (slot != MCA_NOTFOUND) { - /* - * Currently we only support the MC16/32 (MCA ID 002d) - */ - slot = mca_find_unused_adapter(0x002d, slot); - if (slot == MCA_NOTFOUND) - break; - - /* - * If we get here, we have an adapter. - */ - if (versionprinted++ == 0) - printk("%s", version); - - dev = alloc_trdev(sizeof(struct net_local)); - if (dev == NULL) { - printk("madgemc: unable to allocate dev space\n"); - if (madgemc_card_list) - return 0; - return -1; - } + struct card_info *card; + struct mca_device *mdev = to_mca_device(device); + int ret = 0, i = 0; + + if (versionprinted++ == 0) + printk("%s", version); + + if(mca_device_claimed(mdev)) + return -EBUSY; + mca_device_set_claim(mdev, 1); + + dev = alloc_trdev(sizeof(struct net_local)); + if (!dev) { + printk("madgemc: unable to allocate dev space\n"); + mca_device_set_claim(mdev, 0); + ret = -ENOMEM; + goto getout; + } - SET_MODULE_OWNER(dev); - dev->dma = 0; + SET_MODULE_OWNER(dev); + dev->dma = 0; - /* - * Fetch MCA config registers - */ - for(i=0;i<4;i++) - posreg[i] = mca_read_stored_pos(slot, i+2); - - card = kmalloc(sizeof(struct madgemc_card), GFP_KERNEL); - if (card==NULL) { - printk("madgemc: unable to allocate card struct\n"); - free_netdev(dev); - if (madgemc_card_list) - return 0; - return -1; - } - card->dev = dev; - - /* - * Parse configuration information. This all comes - * directly from the publicly available @002d.ADF. - * Get it from Madge or your local ADF library. - */ - - /* - * Base address - */ - dev->base_addr = 0x0a20 + - ((posreg[2] & MC16_POS2_ADDR2)?0x0400:0) + - ((posreg[0] & MC16_POS0_ADDR1)?0x1000:0) + - ((posreg[3] & MC16_POS3_ADDR3)?0x2000:0); - - /* - * Interrupt line - */ - switch(posreg[0] >> 6) { /* upper two bits */ + card = kmalloc(sizeof(struct card_info), GFP_KERNEL); + if (card==NULL) { + printk("madgemc: unable to allocate card struct\n"); + ret = -ENOMEM; + goto getout1; + } + + /* + * Parse configuration information. This all comes + * directly from the publicly available @002d.ADF. + * Get it from Madge or your local ADF library. + */ + + /* + * Base address + */ + dev->base_addr = 0x0a20 + + ((mdev->pos[2] & MC16_POS2_ADDR2)?0x0400:0) + + ((mdev->pos[0] & MC16_POS0_ADDR1)?0x1000:0) + + ((mdev->pos[3] & MC16_POS3_ADDR3)?0x2000:0); + + /* + * Interrupt line + */ + switch(mdev->pos[0] >> 6) { /* upper two bits */ case 0x1: dev->irq = 3; break; case 0x2: dev->irq = 9; break; /* IRQ 2 = IRQ 9 */ case 0x3: dev->irq = 10; break; default: dev->irq = 0; break; - } + } - if (dev->irq == 0) { - printk("%s: invalid IRQ\n", dev->name); - goto getout1; - } + if (dev->irq == 0) { + printk("%s: invalid IRQ\n", dev->name); + ret = -EBUSY; + goto getout2; + } - if (!request_region(dev->base_addr, MADGEMC_IO_EXTENT, - "madgemc")) { - printk(KERN_INFO "madgemc: unable to setup Smart MC in slot %d because of I/O base conflict at 0x%04lx\n", slot, dev->base_addr); - dev->base_addr += MADGEMC_SIF_OFFSET; - goto getout1; - } + if (!request_region(dev->base_addr, MADGEMC_IO_EXTENT, + "madgemc")) { + printk(KERN_INFO "madgemc: unable to setup Smart MC in slot %d because of I/O base conflict at 0x%04lx\n", mdev->slot, dev->base_addr); dev->base_addr += MADGEMC_SIF_OFFSET; + ret = -EBUSY; + goto getout2; + } + dev->base_addr += MADGEMC_SIF_OFFSET; + + /* + * Arbitration Level + */ + card->arblevel = ((mdev->pos[0] >> 1) & 0x7) + 8; + + /* + * Burst mode and Fairness + */ + card->burstmode = ((mdev->pos[2] >> 6) & 0x3); + card->fairness = ((mdev->pos[2] >> 4) & 0x1); + + /* + * Ring Speed + */ + if ((mdev->pos[1] >> 2)&0x1) + card->ringspeed = 2; /* not selected */ + else if ((mdev->pos[2] >> 5) & 0x1) + card->ringspeed = 1; /* 16Mb */ + else + card->ringspeed = 0; /* 4Mb */ + + /* + * Cable type + */ + if ((mdev->pos[1] >> 6)&0x1) + card->cabletype = 1; /* STP/DB9 */ + else + card->cabletype = 0; /* UTP/RJ-45 */ + + + /* + * ROM Info. This requires us to actually twiddle + * bits on the card, so we must ensure above that + * the base address is free of conflict (request_region above). + */ + madgemc_read_rom(dev, card); - /* - * Arbitration Level - */ - card->arblevel = ((posreg[0] >> 1) & 0x7) + 8; - - /* - * Burst mode and Fairness - */ - card->burstmode = ((posreg[2] >> 6) & 0x3); - card->fairness = ((posreg[2] >> 4) & 0x1); - - /* - * Ring Speed - */ - if ((posreg[1] >> 2)&0x1) - card->ringspeed = 2; /* not selected */ - else if ((posreg[2] >> 5) & 0x1) - card->ringspeed = 1; /* 16Mb */ - else - card->ringspeed = 0; /* 4Mb */ - - /* - * Cable type - */ - if ((posreg[1] >> 6)&0x1) - card->cabletype = 1; /* STP/DB9 */ - else - card->cabletype = 0; /* UTP/RJ-45 */ - - - /* - * ROM Info. This requires us to actually twiddle - * bits on the card, so we must ensure above that - * the base address is free of conflict (request_region above). - */ - madgemc_read_rom(card); - - if (card->manid != 0x4d) { /* something went wrong */ - printk(KERN_INFO "%s: Madge MC ROM read failed (unknown manufacturer ID %02x)\n", dev->name, card->manid); - goto getout; - } + if (card->manid != 0x4d) { /* something went wrong */ + printk(KERN_INFO "%s: Madge MC ROM read failed (unknown manufacturer ID %02x)\n", dev->name, card->manid); + goto getout3; + } - if ((card->cardtype != 0x08) && (card->cardtype != 0x0d)) { - printk(KERN_INFO "%s: Madge MC ROM read failed (unknown card ID %02x)\n", dev->name, card->cardtype); - goto getout; - } + if ((card->cardtype != 0x08) && (card->cardtype != 0x0d)) { + printk(KERN_INFO "%s: Madge MC ROM read failed (unknown card ID %02x)\n", dev->name, card->cardtype); + ret = -EIO; + goto getout3; + } - /* All cards except Rev 0 and 1 MC16's have 256kb of RAM */ - if ((card->cardtype == 0x08) && (card->cardrev <= 0x01)) - card->ramsize = 128; - else - card->ramsize = 256; - - printk("%s: %s Rev %d at 0x%04lx IRQ %d\n", - dev->name, - (card->cardtype == 0x08)?MADGEMC16_CARDNAME: - MADGEMC32_CARDNAME, card->cardrev, - dev->base_addr, dev->irq); - - if (card->cardtype == 0x0d) - printk("%s: Warning: MC32 support is experimental and highly untested\n", dev->name); - - if (card->ringspeed==2) { /* Unknown */ - printk("%s: Warning: Ring speed not set in POS -- Please run the reference disk and set it!\n", dev->name); - card->ringspeed = 1; /* default to 16mb */ - } + /* All cards except Rev 0 and 1 MC16's have 256kb of RAM */ + if ((card->cardtype == 0x08) && (card->cardrev <= 0x01)) + card->ramsize = 128; + else + card->ramsize = 256; + + printk("%s: %s Rev %d at 0x%04lx IRQ %d\n", + dev->name, + (card->cardtype == 0x08)?MADGEMC16_CARDNAME: + MADGEMC32_CARDNAME, card->cardrev, + dev->base_addr, dev->irq); + + if (card->cardtype == 0x0d) + printk("%s: Warning: MC32 support is experimental and highly untested\n", dev->name); + + if (card->ringspeed==2) { /* Unknown */ + printk("%s: Warning: Ring speed not set in POS -- Please run the reference disk and set it!\n", dev->name); + card->ringspeed = 1; /* default to 16mb */ + } - printk("%s: RAM Size: %dKB\n", dev->name, card->ramsize); + printk("%s: RAM Size: %dKB\n", dev->name, card->ramsize); - printk("%s: Ring Speed: %dMb/sec on %s\n", dev->name, - (card->ringspeed)?16:4, - card->cabletype?"STP/DB9":"UTP/RJ-45"); - printk("%s: Arbitration Level: %d\n", dev->name, - card->arblevel); + printk("%s: Ring Speed: %dMb/sec on %s\n", dev->name, + (card->ringspeed)?16:4, + card->cabletype?"STP/DB9":"UTP/RJ-45"); + printk("%s: Arbitration Level: %d\n", dev->name, + card->arblevel); - printk("%s: Burst Mode: ", dev->name); - switch(card->burstmode) { + printk("%s: Burst Mode: ", dev->name); + switch(card->burstmode) { case 0: printk("Cycle steal"); break; case 1: printk("Limited burst"); break; case 2: printk("Delayed release"); break; case 3: printk("Immediate release"); break; - } - printk(" (%s)\n", (card->fairness)?"Unfair":"Fair"); - - - /* - * Enable SIF before we assign the interrupt handler, - * just in case we get spurious interrupts that need - * handling. - */ - outb(0, dev->base_addr + MC_CONTROL_REG0); /* sanity */ - madgemc_setsifsel(dev, 1); - if (request_irq(dev->irq, madgemc_interrupt, SA_SHIRQ, - "madgemc", dev)) - goto getout; - - madgemc_chipset_init(dev); /* enables interrupts! */ - madgemc_setcabletype(dev, card->cabletype); + } + printk(" (%s)\n", (card->fairness)?"Unfair":"Fair"); - /* Setup MCA structures */ - mca_set_adapter_name(slot, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME); - mca_set_adapter_procfn(slot, madgemc_mcaproc, dev); - mca_mark_as_used(slot); - printk("%s: Ring Station Address: ", dev->name); - printk("%2.2x", dev->dev_addr[0]); - for (i = 1; i < 6; i++) - printk(":%2.2x", dev->dev_addr[i]); - printk("\n"); - - /* XXX is ISA_MAX_ADDRESS correct here? */ - if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) { - printk("%s: unable to get memory for dev->priv.\n", - dev->name); - release_region(dev->base_addr-MADGEMC_SIF_OFFSET, - MADGEMC_IO_EXTENT); - - kfree(card); - tmsdev_term(dev); - free_netdev(dev); - if (madgemc_card_list) - return 0; - return -1; - } - tp = netdev_priv(dev); - - /* - * The MC16 is physically a 32bit card. However, Madge - * insists on calling it 16bit, so I'll assume here that - * they know what they're talking about. Cut off DMA - * at 16mb. - */ - tp->setnselout = madgemc_setnselout_pins; - tp->sifwriteb = madgemc_sifwriteb; - tp->sifreadb = madgemc_sifreadb; - tp->sifwritew = madgemc_sifwritew; - tp->sifreadw = madgemc_sifreadw; - tp->DataRate = (card->ringspeed)?SPEED_16:SPEED_4; - - memcpy(tp->ProductID, "Madge MCA 16/4 ", PROD_ID_SIZE + 1); - - dev->open = madgemc_open; - dev->stop = madgemc_close; - - if (register_netdev(dev) == 0) { - /* Enlist in the card list */ - card->next = madgemc_card_list; - madgemc_card_list = card; - slot++; - continue; /* successful, try to find another */ - } - - free_irq(dev->irq, dev); - getout: - release_region(dev->base_addr-MADGEMC_SIF_OFFSET, - MADGEMC_IO_EXTENT); - getout1: - kfree(card); - free_netdev(dev); - slot++; + /* + * Enable SIF before we assign the interrupt handler, + * just in case we get spurious interrupts that need + * handling. + */ + outb(0, dev->base_addr + MC_CONTROL_REG0); /* sanity */ + madgemc_setsifsel(dev, 1); + if (request_irq(dev->irq, madgemc_interrupt, SA_SHIRQ, + "madgemc", dev)) { + ret = -EBUSY; + goto getout3; } - if (madgemc_card_list) + madgemc_chipset_init(dev); /* enables interrupts! */ + madgemc_setcabletype(dev, card->cabletype); + + /* Setup MCA structures */ + mca_device_set_name(mdev, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME); + mca_set_adapter_procfn(mdev->slot, madgemc_mcaproc, dev); + + printk("%s: Ring Station Address: ", dev->name); + printk("%2.2x", dev->dev_addr[0]); + for (i = 1; i < 6; i++) + printk(":%2.2x", dev->dev_addr[i]); + printk("\n"); + + if (tmsdev_init(dev, device)) { + printk("%s: unable to get memory for dev->priv.\n", + dev->name); + ret = -ENOMEM; + goto getout4; + } + tp = netdev_priv(dev); + + /* + * The MC16 is physically a 32bit card. However, Madge + * insists on calling it 16bit, so I'll assume here that + * they know what they're talking about. Cut off DMA + * at 16mb. + */ + tp->setnselout = madgemc_setnselout_pins; + tp->sifwriteb = madgemc_sifwriteb; + tp->sifreadb = madgemc_sifreadb; + tp->sifwritew = madgemc_sifwritew; + tp->sifreadw = madgemc_sifreadw; + tp->DataRate = (card->ringspeed)?SPEED_16:SPEED_4; + + memcpy(tp->ProductID, "Madge MCA 16/4 ", PROD_ID_SIZE + 1); + + dev->open = madgemc_open; + dev->stop = madgemc_close; + + tp->tmspriv = card; + dev_set_drvdata(device, dev); + + if (register_netdev(dev) == 0) return 0; - return -1; + + dev_set_drvdata(device, NULL); + ret = -ENOMEM; +getout4: + free_irq(dev->irq, dev); +getout3: + release_region(dev->base_addr-MADGEMC_SIF_OFFSET, + MADGEMC_IO_EXTENT); +getout2: + kfree(card); +getout1: + free_netdev(dev); +getout: + mca_device_set_claim(mdev, 0); + return ret; } /* @@ -664,12 +634,12 @@ static void madgemc_chipset_close(struct net_device *dev) * is complete. * */ -static void madgemc_read_rom(struct madgemc_card *card) +static void madgemc_read_rom(struct net_device *dev, struct card_info *card) { unsigned long ioaddr; unsigned char reg0, reg1, tmpreg0, i; - ioaddr = card->dev->base_addr; + ioaddr = dev->base_addr; reg0 = inb(ioaddr + MC_CONTROL_REG0); reg1 = inb(ioaddr + MC_CONTROL_REG1); @@ -686,9 +656,9 @@ static void madgemc_read_rom(struct madgemc_card *card) outb(tmpreg0 | MC_CONTROL_REG0_PAGE, ioaddr + MC_CONTROL_REG0); /* Read BIA */ - card->dev->addr_len = 6; + dev->addr_len = 6; for (i = 0; i < 6; i++) - card->dev->dev_addr[i] = inb(ioaddr + MC_ROM_BIA_START + i); + dev->dev_addr[i] = inb(ioaddr + MC_ROM_BIA_START + i); /* Restore original register values */ outb(reg0, ioaddr + MC_CONTROL_REG0); @@ -721,14 +691,10 @@ static int madgemc_close(struct net_device *dev) static int madgemc_mcaproc(char *buf, int slot, void *d) { struct net_device *dev = (struct net_device *)d; - struct madgemc_card *curcard = madgemc_card_list; + struct net_local *tp = dev->priv; + struct card_info *curcard = tp->tmspriv; int len = 0; - while (curcard) { /* search for card struct */ - if (curcard->dev == dev) - break; - curcard = curcard->next; - } len += sprintf(buf+len, "-------\n"); if (curcard) { struct net_local *tp = netdev_priv(dev); @@ -763,25 +729,56 @@ static int madgemc_mcaproc(char *buf, int slot, void *d) return len; } -static void __exit madgemc_exit(void) +static int __devexit madgemc_remove(struct device *device) { - struct net_device *dev; - struct madgemc_card *this_card; - - while (madgemc_card_list) { - dev = madgemc_card_list->dev; - unregister_netdev(dev); - release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT); - free_irq(dev->irq, dev); - tmsdev_term(dev); - free_netdev(dev); - this_card = madgemc_card_list; - madgemc_card_list = this_card->next; - kfree(this_card); - } + struct net_device *dev = dev_get_drvdata(device); + struct net_local *tp; + struct card_info *card; + + if (!dev) + BUG(); + + tp = dev->priv; + card = tp->tmspriv; + kfree(card); + tp->tmspriv = NULL; + + unregister_netdev(dev); + release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT); + free_irq(dev->irq, dev); + tmsdev_term(dev); + free_netdev(dev); + dev_set_drvdata(device, NULL); + + return 0; +} + +static short madgemc_adapter_ids[] __initdata = { + 0x002d, + 0x0000 +}; + +static struct mca_driver madgemc_driver = { + .id_table = madgemc_adapter_ids, + .driver = { + .name = "madgemc", + .bus = &mca_bus_type, + .probe = madgemc_probe, + .remove = __devexit_p(madgemc_remove), + }, +}; + +static int __init madgemc_init (void) +{ + return mca_register_driver (&madgemc_driver); +} + +static void __exit madgemc_exit (void) +{ + mca_unregister_driver (&madgemc_driver); } -module_init(madgemc_probe); +module_init(madgemc_init); module_exit(madgemc_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c index 40ad0fde28a..eb1423ede75 100644 --- a/drivers/net/tokenring/proteon.c +++ b/drivers/net/tokenring/proteon.c @@ -62,8 +62,7 @@ static int dmalist[] __initdata = { }; static char cardname[] = "Proteon 1392\0"; - -struct net_device *proteon_probe(int unit); +static u64 dma_mask = ISA_MAX_ADDRESS; static int proteon_open(struct net_device *dev); static void proteon_read_eeprom(struct net_device *dev); static unsigned short proteon_setnselout_pins(struct net_device *dev); @@ -116,7 +115,7 @@ nodev: return -ENODEV; } -static int __init setup_card(struct net_device *dev) +static int __init setup_card(struct net_device *dev, struct device *pdev) { struct net_local *tp; static int versionprinted; @@ -137,7 +136,7 @@ static int __init setup_card(struct net_device *dev) } } if (err) - goto out4; + goto out5; /* At this point we have found a valid card. */ @@ -145,14 +144,15 @@ static int __init setup_card(struct net_device *dev) printk(KERN_DEBUG "%s", version); err = -EIO; - if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) + pdev->dma_mask = &dma_mask; + if (tmsdev_init(dev, pdev)) goto out4; dev->base_addr &= ~3; proteon_read_eeprom(dev); - printk(KERN_DEBUG "%s: Ring Station Address: ", dev->name); + printk(KERN_DEBUG "proteon.c: Ring Station Address: "); printk("%2.2x", dev->dev_addr[0]); for (j = 1; j < 6; j++) printk(":%2.2x", dev->dev_addr[j]); @@ -185,7 +185,7 @@ static int __init setup_card(struct net_device *dev) if(irqlist[j] == 0) { - printk(KERN_INFO "%s: AutoSelect no IRQ available\n", dev->name); + printk(KERN_INFO "proteon.c: AutoSelect no IRQ available\n"); goto out3; } } @@ -196,15 +196,15 @@ static int __init setup_card(struct net_device *dev) break; if (irqlist[j] == 0) { - printk(KERN_INFO "%s: Illegal IRQ %d specified\n", - dev->name, dev->irq); + printk(KERN_INFO "proteon.c: Illegal IRQ %d specified\n", + dev->irq); goto out3; } if (request_irq(dev->irq, tms380tr_interrupt, 0, cardname, dev)) { - printk(KERN_INFO "%s: Selected IRQ %d not available\n", - dev->name, dev->irq); + printk(KERN_INFO "proteon.c: Selected IRQ %d not available\n", + dev->irq); goto out3; } } @@ -220,7 +220,7 @@ static int __init setup_card(struct net_device *dev) if(dmalist[j] == 0) { - printk(KERN_INFO "%s: AutoSelect no DMA available\n", dev->name); + printk(KERN_INFO "proteon.c: AutoSelect no DMA available\n"); goto out2; } } @@ -231,25 +231,25 @@ static int __init setup_card(struct net_device *dev) break; if (dmalist[j] == 0) { - printk(KERN_INFO "%s: Illegal DMA %d specified\n", - dev->name, dev->dma); + printk(KERN_INFO "proteon.c: Illegal DMA %d specified\n", + dev->dma); goto out2; } if (request_dma(dev->dma, cardname)) { - printk(KERN_INFO "%s: Selected DMA %d not available\n", - dev->name, dev->dma); + printk(KERN_INFO "proteon.c: Selected DMA %d not available\n", + dev->dma); goto out2; } } - printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", - dev->name, dev->base_addr, dev->irq, dev->dma); - err = register_netdev(dev); if (err) goto out; + printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", + dev->name, dev->base_addr, dev->irq, dev->dma); + return 0; out: free_dma(dev->dma); @@ -258,34 +258,11 @@ out2: out3: tmsdev_term(dev); out4: - release_region(dev->base_addr, PROTEON_IO_EXTENT); + release_region(dev->base_addr, PROTEON_IO_EXTENT); +out5: return err; } -struct net_device * __init proteon_probe(int unit) -{ - struct net_device *dev = alloc_trdev(sizeof(struct net_local)); - int err = 0; - - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) { - sprintf(dev->name, "tr%d", unit); - netdev_boot_setup_check(dev); - } - - err = setup_card(dev); - if (err) - goto out; - - return dev; - -out: - free_netdev(dev); - return ERR_PTR(err); -} - /* * Reads MAC address from adapter RAM, which should've read it from * the onboard ROM. @@ -352,8 +329,6 @@ static int proteon_open(struct net_device *dev) return tms380tr_open(dev); } -#ifdef MODULE - #define ISATR_MAX_ADAPTERS 3 static int io[ISATR_MAX_ADAPTERS]; @@ -366,13 +341,23 @@ module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); module_param_array(dma, int, NULL, 0); -static struct net_device *proteon_dev[ISATR_MAX_ADAPTERS]; +static struct platform_device *proteon_dev[ISATR_MAX_ADAPTERS]; + +static struct device_driver proteon_driver = { + .name = "proteon", + .bus = &platform_bus_type, +}; -int init_module(void) +static int __init proteon_init(void) { struct net_device *dev; + struct platform_device *pdev; int i, num = 0, err = 0; + err = driver_register(&proteon_driver); + if (err) + return err; + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { dev = alloc_trdev(sizeof(struct net_local)); if (!dev) @@ -381,11 +366,15 @@ int init_module(void) dev->base_addr = io[i]; dev->irq = irq[i]; dev->dma = dma[i]; - err = setup_card(dev); + pdev = platform_device_register_simple("proteon", + i, NULL, 0); + err = setup_card(dev, &pdev->dev); if (!err) { - proteon_dev[i] = dev; + proteon_dev[i] = pdev; + dev_set_drvdata(&pdev->dev, dev); ++num; } else { + platform_device_unregister(pdev); free_netdev(dev); } } @@ -399,23 +388,28 @@ int init_module(void) return (0); } -void cleanup_module(void) +static void __exit proteon_cleanup(void) { + struct net_device *dev; int i; for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - struct net_device *dev = proteon_dev[i]; + struct platform_device *pdev = proteon_dev[i]; - if (!dev) + if (!pdev) continue; - + dev = dev_get_drvdata(&pdev->dev); unregister_netdev(dev); release_region(dev->base_addr, PROTEON_IO_EXTENT); free_irq(dev->irq, dev); free_dma(dev->dma); tmsdev_term(dev); free_netdev(dev); + dev_set_drvdata(&pdev->dev, NULL); + platform_device_unregister(pdev); } + driver_unregister(&proteon_driver); } -#endif /* MODULE */ +module_init(proteon_init); +module_exit(proteon_cleanup); diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c index f26796e2d0e..3c7c66204f7 100644 --- a/drivers/net/tokenring/skisa.c +++ b/drivers/net/tokenring/skisa.c @@ -68,8 +68,7 @@ static int dmalist[] __initdata = { }; static char isa_cardname[] = "SK NET TR 4/16 ISA\0"; - -struct net_device *sk_isa_probe(int unit); +static u64 dma_mask = ISA_MAX_ADDRESS; static int sk_isa_open(struct net_device *dev); static void sk_isa_read_eeprom(struct net_device *dev); static unsigned short sk_isa_setnselout_pins(struct net_device *dev); @@ -133,7 +132,7 @@ static int __init sk_isa_probe1(struct net_device *dev, int ioaddr) return 0; } -static int __init setup_card(struct net_device *dev) +static int __init setup_card(struct net_device *dev, struct device *pdev) { struct net_local *tp; static int versionprinted; @@ -154,7 +153,7 @@ static int __init setup_card(struct net_device *dev) } } if (err) - goto out4; + goto out5; /* At this point we have found a valid card. */ @@ -162,14 +161,15 @@ static int __init setup_card(struct net_device *dev) printk(KERN_DEBUG "%s", version); err = -EIO; - if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) + pdev->dma_mask = &dma_mask; + if (tmsdev_init(dev, pdev)) goto out4; dev->base_addr &= ~3; sk_isa_read_eeprom(dev); - printk(KERN_DEBUG "%s: Ring Station Address: ", dev->name); + printk(KERN_DEBUG "skisa.c: Ring Station Address: "); printk("%2.2x", dev->dev_addr[0]); for (j = 1; j < 6; j++) printk(":%2.2x", dev->dev_addr[j]); @@ -202,7 +202,7 @@ static int __init setup_card(struct net_device *dev) if(irqlist[j] == 0) { - printk(KERN_INFO "%s: AutoSelect no IRQ available\n", dev->name); + printk(KERN_INFO "skisa.c: AutoSelect no IRQ available\n"); goto out3; } } @@ -213,15 +213,15 @@ static int __init setup_card(struct net_device *dev) break; if (irqlist[j] == 0) { - printk(KERN_INFO "%s: Illegal IRQ %d specified\n", - dev->name, dev->irq); + printk(KERN_INFO "skisa.c: Illegal IRQ %d specified\n", + dev->irq); goto out3; } if (request_irq(dev->irq, tms380tr_interrupt, 0, isa_cardname, dev)) { - printk(KERN_INFO "%s: Selected IRQ %d not available\n", - dev->name, dev->irq); + printk(KERN_INFO "skisa.c: Selected IRQ %d not available\n", + dev->irq); goto out3; } } @@ -237,7 +237,7 @@ static int __init setup_card(struct net_device *dev) if(dmalist[j] == 0) { - printk(KERN_INFO "%s: AutoSelect no DMA available\n", dev->name); + printk(KERN_INFO "skisa.c: AutoSelect no DMA available\n"); goto out2; } } @@ -248,25 +248,25 @@ static int __init setup_card(struct net_device *dev) break; if (dmalist[j] == 0) { - printk(KERN_INFO "%s: Illegal DMA %d specified\n", - dev->name, dev->dma); + printk(KERN_INFO "skisa.c: Illegal DMA %d specified\n", + dev->dma); goto out2; } if (request_dma(dev->dma, isa_cardname)) { - printk(KERN_INFO "%s: Selected DMA %d not available\n", - dev->name, dev->dma); + printk(KERN_INFO "skisa.c: Selected DMA %d not available\n", + dev->dma); goto out2; } } - printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", - dev->name, dev->base_addr, dev->irq, dev->dma); - err = register_netdev(dev); if (err) goto out; + printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", + dev->name, dev->base_addr, dev->irq, dev->dma); + return 0; out: free_dma(dev->dma); @@ -275,33 +275,11 @@ out2: out3: tmsdev_term(dev); out4: - release_region(dev->base_addr, SK_ISA_IO_EXTENT); + release_region(dev->base_addr, SK_ISA_IO_EXTENT); +out5: return err; } -struct net_device * __init sk_isa_probe(int unit) -{ - struct net_device *dev = alloc_trdev(sizeof(struct net_local)); - int err = 0; - - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) { - sprintf(dev->name, "tr%d", unit); - netdev_boot_setup_check(dev); - } - - err = setup_card(dev); - if (err) - goto out; - - return dev; -out: - free_netdev(dev); - return ERR_PTR(err); -} - /* * Reads MAC address from adapter RAM, which should've read it from * the onboard ROM. @@ -361,8 +339,6 @@ static int sk_isa_open(struct net_device *dev) return tms380tr_open(dev); } -#ifdef MODULE - #define ISATR_MAX_ADAPTERS 3 static int io[ISATR_MAX_ADAPTERS]; @@ -375,13 +351,23 @@ module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); module_param_array(dma, int, NULL, 0); -static struct net_device *sk_isa_dev[ISATR_MAX_ADAPTERS]; +static struct platform_device *sk_isa_dev[ISATR_MAX_ADAPTERS]; -int init_module(void) +static struct device_driver sk_isa_driver = { + .name = "skisa", + .bus = &platform_bus_type, +}; + +static int __init sk_isa_init(void) { struct net_device *dev; + struct platform_device *pdev; int i, num = 0, err = 0; + err = driver_register(&sk_isa_driver); + if (err) + return err; + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { dev = alloc_trdev(sizeof(struct net_local)); if (!dev) @@ -390,12 +376,15 @@ int init_module(void) dev->base_addr = io[i]; dev->irq = irq[i]; dev->dma = dma[i]; - err = setup_card(dev); - + pdev = platform_device_register_simple("skisa", + i, NULL, 0); + err = setup_card(dev, &pdev->dev); if (!err) { - sk_isa_dev[i] = dev; + sk_isa_dev[i] = pdev; + dev_set_drvdata(&sk_isa_dev[i]->dev, dev); ++num; } else { + platform_device_unregister(pdev); free_netdev(dev); } } @@ -409,23 +398,28 @@ int init_module(void) return (0); } -void cleanup_module(void) +static void __exit sk_isa_cleanup(void) { + struct net_device *dev; int i; for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - struct net_device *dev = sk_isa_dev[i]; + struct platform_device *pdev = sk_isa_dev[i]; - if (!dev) + if (!pdev) continue; - + dev = dev_get_drvdata(&pdev->dev); unregister_netdev(dev); release_region(dev->base_addr, SK_ISA_IO_EXTENT); free_irq(dev->irq, dev); free_dma(dev->dma); tmsdev_term(dev); free_netdev(dev); + dev_set_drvdata(&pdev->dev, NULL); + platform_device_unregister(pdev); } + driver_unregister(&sk_isa_driver); } -#endif /* MODULE */ +module_init(sk_isa_init); +module_exit(sk_isa_cleanup); diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 5e0b0ce98ed..2e39bf1f746 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -62,6 +62,7 @@ * normal operation. * 30-Dec-02 JF Removed incorrect __init from * tms380tr_init_card. + * 22-Jul-05 JF Converted to dma-mapping. * * To do: * 1. Multi/Broadcast packet handling (this may have fixed itself) @@ -89,7 +90,7 @@ static const char version[] = "tms380tr.c: v1.10 30/12/2002 by Christoph Goos, A #include <linux/time.h> #include <linux/errno.h> #include <linux/init.h> -#include <linux/pci.h> +#include <linux/dma-mapping.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -114,8 +115,6 @@ static const char version[] = "tms380tr.c: v1.10 30/12/2002 by Christoph Goos, A #endif static unsigned int tms380tr_debug = TMS380TR_DEBUG; -static struct device tms_device; - /* Index to functions, as function prototypes. * Alphabetical by function name. */ @@ -434,7 +433,7 @@ static void tms380tr_init_net_local(struct net_device *dev) skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize); /* data unreachable for DMA ? then use local buffer */ - dmabuf = pci_map_single(tp->pdev, tp->Rpl[i].Skb->data, tp->MaxPacketSize, PCI_DMA_FROMDEVICE); + dmabuf = dma_map_single(tp->pdev, tp->Rpl[i].Skb->data, tp->MaxPacketSize, DMA_FROM_DEVICE); if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit)) { tp->Rpl[i].SkbStat = SKB_DATA_COPY; @@ -638,10 +637,10 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device /* Is buffer reachable for Busmaster-DMA? */ length = skb->len; - dmabuf = pci_map_single(tp->pdev, skb->data, length, PCI_DMA_TODEVICE); + dmabuf = dma_map_single(tp->pdev, skb->data, length, DMA_TO_DEVICE); if(tp->dmalimit && (dmabuf + length > tp->dmalimit)) { /* Copy frame to local buffer */ - pci_unmap_single(tp->pdev, dmabuf, length, PCI_DMA_TODEVICE); + dma_unmap_single(tp->pdev, dmabuf, length, DMA_TO_DEVICE); dmabuf = 0; i = tp->TplFree->TPLIndex; buf = tp->LocalTxBuffers[i]; @@ -1284,9 +1283,7 @@ static int tms380tr_reset_adapter(struct net_device *dev) unsigned short count, c, count2; const struct firmware *fw_entry = NULL; - strncpy(tms_device.bus_id,dev->name, BUS_ID_SIZE); - - if (request_firmware(&fw_entry, "tms380tr.bin", &tms_device) != 0) { + if (request_firmware(&fw_entry, "tms380tr.bin", tp->pdev) != 0) { printk(KERN_ALERT "%s: firmware %s is missing, cannot start.\n", dev->name, "tms380tr.bin"); return (-1); @@ -2021,7 +2018,7 @@ static void tms380tr_cancel_tx_queue(struct net_local* tp) printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl); if (tpl->DMABuff) - pci_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, PCI_DMA_TODEVICE); + dma_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(tpl->Skb); } @@ -2090,7 +2087,7 @@ static void tms380tr_tx_status_irq(struct net_device *dev) tp->MacStat.tx_packets++; if (tpl->DMABuff) - pci_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, PCI_DMA_TODEVICE); + dma_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, DMA_TO_DEVICE); dev_kfree_skb_irq(tpl->Skb); tpl->BusyFlag = 0; /* "free" TPL */ } @@ -2209,7 +2206,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) tp->MacStat.rx_errors++; } if (rpl->DMABuff) - pci_unmap_single(tp->pdev, rpl->DMABuff, tp->MaxPacketSize, PCI_DMA_TODEVICE); + dma_unmap_single(tp->pdev, rpl->DMABuff, tp->MaxPacketSize, DMA_TO_DEVICE); rpl->DMABuff = 0; /* Allocate new skb for rpl */ @@ -2227,7 +2224,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) skb_put(rpl->Skb, tp->MaxPacketSize); /* Data unreachable for DMA ? then use local buffer */ - dmabuf = pci_map_single(tp->pdev, rpl->Skb->data, tp->MaxPacketSize, PCI_DMA_FROMDEVICE); + dmabuf = dma_map_single(tp->pdev, rpl->Skb->data, tp->MaxPacketSize, DMA_FROM_DEVICE); if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit)) { rpl->SkbStat = SKB_DATA_COPY; @@ -2332,23 +2329,26 @@ void tmsdev_term(struct net_device *dev) struct net_local *tp; tp = netdev_priv(dev); - pci_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local), - PCI_DMA_BIDIRECTIONAL); + dma_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local), + DMA_BIDIRECTIONAL); } -int tmsdev_init(struct net_device *dev, unsigned long dmalimit, - struct pci_dev *pdev) +int tmsdev_init(struct net_device *dev, struct device *pdev) { struct net_local *tms_local; memset(dev->priv, 0, sizeof(struct net_local)); tms_local = netdev_priv(dev); init_waitqueue_head(&tms_local->wait_for_tok_int); - tms_local->dmalimit = dmalimit; + if (pdev->dma_mask) + tms_local->dmalimit = *pdev->dma_mask; + else + return -ENOMEM; tms_local->pdev = pdev; - tms_local->dmabuffer = pci_map_single(pdev, (void *)tms_local, - sizeof(struct net_local), PCI_DMA_BIDIRECTIONAL); - if (tms_local->dmabuffer + sizeof(struct net_local) > dmalimit) + tms_local->dmabuffer = dma_map_single(pdev, (void *)tms_local, + sizeof(struct net_local), DMA_BIDIRECTIONAL); + if (tms_local->dmabuffer + sizeof(struct net_local) > + tms_local->dmalimit) { printk(KERN_INFO "%s: Memory not accessible for DMA\n", dev->name); @@ -2370,8 +2370,6 @@ int tmsdev_init(struct net_device *dev, unsigned long dmalimit, return 0; } -#ifdef MODULE - EXPORT_SYMBOL(tms380tr_open); EXPORT_SYMBOL(tms380tr_close); EXPORT_SYMBOL(tms380tr_interrupt); @@ -2379,6 +2377,8 @@ EXPORT_SYMBOL(tmsdev_init); EXPORT_SYMBOL(tmsdev_term); EXPORT_SYMBOL(tms380tr_wait); +#ifdef MODULE + static struct module *TMS380_module = NULL; int init_module(void) diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h index f2c5ba0f37a..30452c67bb6 100644 --- a/drivers/net/tokenring/tms380tr.h +++ b/drivers/net/tokenring/tms380tr.h @@ -17,8 +17,7 @@ int tms380tr_open(struct net_device *dev); int tms380tr_close(struct net_device *dev); irqreturn_t tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs); -int tmsdev_init(struct net_device *dev, unsigned long dmalimit, - struct pci_dev *pdev); +int tmsdev_init(struct net_device *dev, struct device *pdev); void tmsdev_term(struct net_device *dev); void tms380tr_wait(unsigned long time); @@ -719,7 +718,7 @@ struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */ struct sk_buff *Skb; unsigned char TPLIndex; volatile unsigned char BusyFlag;/* Flag: TPL busy? */ - dma_addr_t DMABuff; /* DMA IO bus address from pci_map */ + dma_addr_t DMABuff; /* DMA IO bus address from dma_map */ }; /* ---------------------Receive Functions-------------------------------* @@ -1060,7 +1059,7 @@ struct s_RPL { /* Receive Parameter List */ struct sk_buff *Skb; SKB_STAT SkbStat; int RPLIndex; - dma_addr_t DMABuff; /* DMA IO bus address from pci_map */ + dma_addr_t DMABuff; /* DMA IO bus address from dma_map */ }; /* Information that need to be kept for each board. */ @@ -1091,7 +1090,7 @@ typedef struct net_local { RPL *RplTail; unsigned char LocalRxBuffers[RPL_NUM][DEFAULT_PACKET_SIZE]; - struct pci_dev *pdev; + struct device *pdev; int DataRate; unsigned char ScbInUse; unsigned short CMDqueue; diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c index 2e18c0a4648..ab47c0547a3 100644 --- a/drivers/net/tokenring/tmspci.c +++ b/drivers/net/tokenring/tmspci.c @@ -100,7 +100,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic unsigned int pci_irq_line; unsigned long pci_ioaddr; struct card_info *cardinfo = &card_info_table[ent->driver_data]; - + if (versionprinted++ == 0) printk("%s", version); @@ -143,7 +143,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic printk(":%2.2x", dev->dev_addr[i]); printk("\n"); - ret = tmsdev_init(dev, PCI_MAX_ADDRESS, pdev); + ret = tmsdev_init(dev, &pdev->dev); if (ret) { printk("%s: unable to get memory for dev->priv.\n", dev->name); goto err_out_irq; diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c index 6e74af62ca0..9e56fc346ba 100644 --- a/drivers/net/wan/cycx_drv.c +++ b/drivers/net/wan/cycx_drv.c @@ -56,7 +56,7 @@ #include <linux/sched.h> /* for jiffies, HZ, etc. */ #include <linux/cycx_drv.h> /* API definitions */ #include <linux/cycx_cfm.h> /* CYCX firmware module definitions */ -#include <linux/delay.h> /* udelay */ +#include <linux/delay.h> /* udelay, msleep_interruptible */ #include <asm/io.h> /* read[wl], write[wl], ioremap, iounmap */ #define MOD_VERSION 0 @@ -74,7 +74,6 @@ static int reset_cyc2x(void __iomem *addr); static int detect_cyc2x(void __iomem *addr); /* Miscellaneous functions */ -static void delay_cycx(int sec); static int get_option_index(long *optlist, long optval); static u16 checksum(u8 *buf, u32 len); @@ -259,7 +258,7 @@ static int memory_exists(void __iomem *addr) if (readw(addr + 0x10) == TEST_PATTERN) return 1; - delay_cycx(1); + msleep_interruptible(1 * 1000); } return 0; @@ -316,7 +315,7 @@ static void cycx_reset_boot(void __iomem *addr, u8 *code, u32 len) /* 80186 was in hold, go */ writeb(0, addr + START_CPU); - delay_cycx(1); + msleep_interruptible(1 * 1000); } /* Load data.bin file through boot (reset) interface. */ @@ -462,13 +461,13 @@ static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len) cycx_reset_boot(hw->dpmbase, reset_image, img_hdr->reset_size); /* reset is waiting for boot */ writew(GEN_POWER_ON, pt_cycld); - delay_cycx(1); + msleep_interruptible(1 * 1000); for (j = 0 ; j < 3 ; j++) if (!readw(pt_cycld)) goto reset_loaded; else - delay_cycx(1); + msleep_interruptible(1 * 1000); } printk(KERN_ERR "%s: reset not started.\n", modname); @@ -495,7 +494,7 @@ reset_loaded: /* Arthur Ganzert's tip: wait a while after the firmware loading... seg abr 26 17:17:12 EST 1999 - acme */ - delay_cycx(7); + msleep_interruptible(7 * 1000); printk(KERN_INFO "%s: firmware loaded!\n", modname); /* enable interrupts */ @@ -547,20 +546,13 @@ static int get_option_index(long *optlist, long optval) static int reset_cyc2x(void __iomem *addr) { writeb(0, addr + RST_ENABLE); - delay_cycx(2); + msleep_interruptible(2 * 1000); writeb(0, addr + RST_DISABLE); - delay_cycx(2); + msleep_interruptible(2 * 1000); return memory_exists(addr); } -/* Delay */ -static void delay_cycx(int sec) -{ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(sec * HZ); -} - /* Calculate 16-bit CRC using CCITT polynomial. */ static u16 checksum(u8 *buf, u32 len) { diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 1d3231cc471..ec3f75a030d 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -270,7 +270,7 @@ config PCMCIA_HERMES config AIRO_CS tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" - depends on NET_RADIO && PCMCIA + depends on NET_RADIO && PCMCIA && (BROKEN || !M32R) ---help--- This is the standard Linux driver to support Cisco/Aironet PCMCIA 802.11 wireless cards. This driver is the same as the Aironet diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index aabcdc2be05..9c2d07cde01 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -4322,36 +4322,36 @@ static const struct iw_priv_args orinoco_privtab[] = { */ static const iw_handler orinoco_handler[] = { - [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) orinoco_ioctl_commit, - [SIOCGIWNAME -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getname, - [SIOCSIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfreq, - [SIOCGIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfreq, - [SIOCSIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setmode, - [SIOCGIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getmode, - [SIOCSIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setsens, - [SIOCGIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getsens, - [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwrange, - [SIOCSIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setspy, - [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy, - [SIOCSIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap, - [SIOCGIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap, - [SIOCSIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setscan, - [SIOCGIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getscan, - [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid, - [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid, - [SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick, - [SIOCGIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getnick, - [SIOCSIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrate, - [SIOCGIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrate, - [SIOCSIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrts, - [SIOCGIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrts, - [SIOCSIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfrag, - [SIOCGIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfrag, - [SIOCGIWRETRY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getretry, - [SIOCSIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_setiwencode, - [SIOCGIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwencode, - [SIOCSIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setpower, - [SIOCGIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getpower, + [SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_commit, + [SIOCGIWNAME -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getname, + [SIOCSIWFREQ -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setfreq, + [SIOCGIWFREQ -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getfreq, + [SIOCSIWMODE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setmode, + [SIOCGIWMODE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getmode, + [SIOCSIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setsens, + [SIOCGIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getsens, + [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwrange, + [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setspy, + [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getspy, + [SIOCSIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setwap, + [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getwap, + [SIOCSIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setscan, + [SIOCGIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getscan, + [SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setessid, + [SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getessid, + [SIOCSIWNICKN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setnick, + [SIOCGIWNICKN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getnick, + [SIOCSIWRATE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setrate, + [SIOCGIWRATE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getrate, + [SIOCSIWRTS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setrts, + [SIOCGIWRTS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getrts, + [SIOCSIWFRAG -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setfrag, + [SIOCGIWFRAG -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getfrag, + [SIOCGIWRETRY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getretry, + [SIOCSIWENCODE-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setiwencode, + [SIOCGIWENCODE-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwencode, + [SIOCSIWPOWER -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setpower, + [SIOCGIWPOWER -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getpower, }; @@ -4359,15 +4359,15 @@ static const iw_handler orinoco_handler[] = { Added typecasting since we no longer use iwreq_data -- Moustafa */ static const iw_handler orinoco_private_handler[] = { - [0] (iw_handler) orinoco_ioctl_reset, - [1] (iw_handler) orinoco_ioctl_reset, - [2] (iw_handler) orinoco_ioctl_setport3, - [3] (iw_handler) orinoco_ioctl_getport3, - [4] (iw_handler) orinoco_ioctl_setpreamble, - [5] (iw_handler) orinoco_ioctl_getpreamble, - [6] (iw_handler) orinoco_ioctl_setibssport, - [7] (iw_handler) orinoco_ioctl_getibssport, - [9] (iw_handler) orinoco_ioctl_getrid, + [0] = (iw_handler) orinoco_ioctl_reset, + [1] = (iw_handler) orinoco_ioctl_reset, + [2] = (iw_handler) orinoco_ioctl_setport3, + [3] = (iw_handler) orinoco_ioctl_getport3, + [4] = (iw_handler) orinoco_ioctl_setpreamble, + [5] = (iw_handler) orinoco_ioctl_getpreamble, + [6] = (iw_handler) orinoco_ioctl_setibssport, + [7] = (iw_handler) orinoco_ioctl_getibssport, + [9] = (iw_handler) orinoco_ioctl_getrid, }; static const struct iw_handler_def orinoco_handler_def = { diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index 16a2e6ae37f..725a14119f2 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -34,7 +34,7 @@ config PARPORT config PARPORT_PC tristate "PC-style hardware" - depends on PARPORT && (!SPARC64 || PCI) && !SPARC32 + depends on PARPORT && (!SPARC64 || PCI) && !SPARC32 && !M32R ---help--- You should say Y here if you have a PC-style parallel port. All IBM PC compatible computers and some Alphas have PC-style diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index 00498e2f120..d3dad0aac7c 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c @@ -23,13 +23,8 @@ #include <linux/pci.h> #include <linux/parport.h> #include <linux/parport_pc.h> -#include <linux/serial.h> -#include <linux/serialP.h> -#include <linux/list.h> #include <linux/8250_pci.h> -#include <asm/serial.h> - enum parport_pc_pci_cards { titan_110l = 0, titan_210l, @@ -168,182 +163,147 @@ static struct pci_device_id parport_serial_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl); -struct pci_board_no_ids { - int flags; - int num_ports; - int base_baud; - int uart_offset; - int reg_shift; - int (*init_fn)(struct pci_dev *dev, struct pci_board_no_ids *board, - int enable); - int first_uart_offset; -}; - -static int __devinit siig10x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable) -{ - return pci_siig10x_fn(dev, enable); -} - -static int __devinit siig20x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable) -{ - return pci_siig20x_fn(dev, enable); -} - -static int __devinit netmos_serial_init(struct pci_dev *dev, struct pci_board_no_ids *board, int enable) -{ - board->num_ports = dev->subsystem_device & 0xf; - return 0; -} - -static struct pci_board_no_ids pci_boards[] __devinitdata = { - /* - * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, - * Offset to get to next UART's registers, - * Register shift to use for memory-mapped I/O, - * Initialization function, first UART offset - */ - -// Cards not tested are marked n/t -// If you have one of these cards and it works for you, please tell me.. - -/* titan_110l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 1, 921600 }, -/* titan_210l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 }, -/* netmos_9xx5_combo */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200, 0, 0, netmos_serial_init }, -/* netmos_9855 */ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200, 0, 0, netmos_serial_init }, -/* avlab_1s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, -/* avlab_1s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, -/* avlab_1s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, -/* avlab_1s2p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, -/* avlab_1s2p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, -/* avlab_1s2p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, -/* avlab_2s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, -/* avlab_2s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, -/* avlab_2s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, -/* siig_1s1p_10x */ { SPCI_FL_BASE2, 1, 460800, 0, 0, siig10x_init_fn }, -/* siig_2s1p_10x */ { SPCI_FL_BASE2, 1, 921600, 0, 0, siig10x_init_fn }, -/* siig_2p1s_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn }, -/* siig_1s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn }, -/* siig_2s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn }, +/* + * This table describes the serial "geometry" of these boards. Any + * quirks for these can be found in drivers/serial/8250_pci.c + * + * Cards not tested are marked n/t + * If you have one of these cards and it works for you, please tell me.. + */ +static struct pciserial_board pci_parport_serial_boards[] __devinitdata = { + [titan_110l] = { + .flags = FL_BASE1 | FL_BASE_BARS, + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 8, + }, + [titan_210l] = { + .flags = FL_BASE1 | FL_BASE_BARS, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 8, + }, + [netmos_9xx5_combo] = { + .flags = FL_BASE0 | FL_BASE_BARS, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [netmos_9855] = { + .flags = FL_BASE2 | FL_BASE_BARS, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [avlab_1s1p] = { /* n/t */ + .flags = FL_BASE0 | FL_BASE_BARS, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [avlab_1s1p_650] = { /* nt */ + .flags = FL_BASE0 | FL_BASE_BARS, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [avlab_1s1p_850] = { /* nt */ + .flags = FL_BASE0 | FL_BASE_BARS, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [avlab_1s2p] = { /* n/t */ + .flags = FL_BASE0 | FL_BASE_BARS, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [avlab_1s2p_650] = { /* nt */ + .flags = FL_BASE0 | FL_BASE_BARS, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [avlab_1s2p_850] = { /* nt */ + .flags = FL_BASE0 | FL_BASE_BARS, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [avlab_2s1p] = { /* n/t */ + .flags = FL_BASE0 | FL_BASE_BARS, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + }, + [avlab_2s1p_650] = { /* nt */ + .flags = FL_BASE0 | FL_BASE_BARS, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + }, + [avlab_2s1p_850] = { /* nt */ + .flags = FL_BASE0 | FL_BASE_BARS, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + }, + [siig_1s1p_10x] = { + .flags = FL_BASE2, + .num_ports = 1, + .base_baud = 460800, + .uart_offset = 8, + }, + [siig_2s1p_10x] = { + .flags = FL_BASE2, + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 8, + }, + [siig_2p1s_20x] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 8, + }, + [siig_1s1p_20x] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 8, + }, + [siig_2s1p_20x] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 8, + }, }; struct parport_serial_private { - int num_ser; - int line[20]; - struct pci_board_no_ids ser; + struct serial_private *serial; int num_par; struct parport *port[PARPORT_MAX]; struct parport_pc_pci par; }; -static int __devinit get_pci_port (struct pci_dev *dev, - struct pci_board_no_ids *board, - struct serial_struct *req, - int idx) -{ - unsigned long port; - int base_idx; - int max_port; - int offset; - - base_idx = SPCI_FL_GET_BASE(board->flags); - if (board->flags & SPCI_FL_BASE_TABLE) - base_idx += idx; - - if (board->flags & SPCI_FL_REGION_SZ_CAP) { - max_port = pci_resource_len(dev, base_idx) / 8; - if (idx >= max_port) - return 1; - } - - offset = board->first_uart_offset; - - /* Timedia/SUNIX uses a mixture of BARs and offsets */ - /* Ugh, this is ugly as all hell --- TYT */ - if(dev->vendor == PCI_VENDOR_ID_TIMEDIA ) /* 0x1409 */ - switch(idx) { - case 0: base_idx=0; - break; - case 1: base_idx=0; offset=8; - break; - case 2: base_idx=1; - break; - case 3: base_idx=1; offset=8; - break; - case 4: /* BAR 2*/ - case 5: /* BAR 3 */ - case 6: /* BAR 4*/ - case 7: base_idx=idx-2; /* BAR 5*/ - } - - port = pci_resource_start(dev, base_idx) + offset; - - if ((board->flags & SPCI_FL_BASE_TABLE) == 0) - port += idx * (board->uart_offset ? board->uart_offset : 8); - - if (pci_resource_flags (dev, base_idx) & IORESOURCE_IO) { - int high_bits_offset = ((sizeof(long)-sizeof(int))*8); - req->port = port; - if (high_bits_offset) - req->port_high = port >> high_bits_offset; - else - req->port_high = 0; - return 0; - } - req->io_type = SERIAL_IO_MEM; - req->iomem_base = ioremap(port, board->uart_offset); - req->iomem_reg_shift = board->reg_shift; - req->port = 0; - return req->iomem_base ? 0 : 1; -} - /* Register the serial port(s) of a PCI card. */ static int __devinit serial_register (struct pci_dev *dev, const struct pci_device_id *id) { - struct pci_board_no_ids *board; struct parport_serial_private *priv = pci_get_drvdata (dev); - struct serial_struct serial_req; - int base_baud; - int k; - int success = 0; - - priv->ser = pci_boards[id->driver_data]; - board = &priv->ser; - if (board->init_fn && ((board->init_fn) (dev, board, 1) != 0)) - return 1; - - base_baud = board->base_baud; - if (!base_baud) - base_baud = BASE_BAUD; - memset (&serial_req, 0, sizeof (serial_req)); - - for (k = 0; k < board->num_ports; k++) { - int line; + struct pciserial_board *board; + struct serial_private *serial; - if (priv->num_ser == ARRAY_SIZE (priv->line)) { - printk (KERN_WARNING - "parport_serial: %s: only %u serial lines " - "supported (%d reported)\n", pci_name (dev), - ARRAY_SIZE (priv->line), board->num_ports); - break; - } + board = &pci_parport_serial_boards[id->driver_data]; + serial = pciserial_init_ports(dev, board); - serial_req.irq = dev->irq; - if (get_pci_port (dev, board, &serial_req, k)) - break; - serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; - serial_req.baud_base = base_baud; - line = register_serial (&serial_req); - if (line < 0) { - printk (KERN_DEBUG - "parport_serial: register_serial failed\n"); - continue; - } - priv->line[priv->num_ser++] = line; - success = 1; - } + if (IS_ERR(serial)) + return PTR_ERR(serial); - return success ? 0 : 1; + priv->serial = serial; + return 0; } /* Register the parallel port(s) of a PCI card. */ @@ -411,7 +371,7 @@ static int __devinit parport_serial_pci_probe (struct pci_dev *dev, priv = kmalloc (sizeof *priv, GFP_KERNEL); if (!priv) return -ENOMEM; - priv->num_ser = priv->num_par = 0; + memset(priv, 0, sizeof(struct parport_serial_private)); pci_set_drvdata (dev, priv); err = pci_enable_device (dev); @@ -444,15 +404,12 @@ static void __devexit parport_serial_pci_remove (struct pci_dev *dev) struct parport_serial_private *priv = pci_get_drvdata (dev); int i; + pci_set_drvdata(dev, NULL); + // Serial ports - for (i = 0; i < priv->num_ser; i++) { - unregister_serial (priv->line[i]); + if (priv->serial) + pciserial_remove_ports(priv->serial); - if (priv->ser.init_fn) - (priv->ser.init_fn) (dev, &priv->ser, 0); - } - pci_set_drvdata (dev, NULL); - // Parallel ports for (i = 0; i < priv->num_par; i++) parport_pc_unregister_port (priv->port[i]); @@ -461,11 +418,47 @@ static void __devexit parport_serial_pci_remove (struct pci_dev *dev) return; } +static int parport_serial_pci_suspend(struct pci_dev *dev, pm_message_t state) +{ + struct parport_serial_private *priv = pci_get_drvdata(dev); + + if (priv->serial) + pciserial_suspend_ports(priv->serial); + + /* FIXME: What about parport? */ + + pci_save_state(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); + return 0; +} + +static int parport_serial_pci_resume(struct pci_dev *dev) +{ + struct parport_serial_private *priv = pci_get_drvdata(dev); + + pci_set_power_state(dev, PCI_D0); + pci_restore_state(dev); + + /* + * The device may have been disabled. Re-enable it. + */ + pci_enable_device(dev); + + if (priv->serial) + pciserial_resume_ports(priv->serial); + + /* FIXME: What about parport? */ + + return 0; +} + static struct pci_driver parport_serial_pci_driver = { .name = "parport_serial", .id_table = parport_serial_pci_tbl, .probe = parport_serial_pci_probe, .remove = __devexit_p(parport_serial_pci_remove), + .suspend = parport_serial_pci_suspend, + .resume = parport_serial_pci_resume, }; diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index a2eebc6eaac..6d864c502a1 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -40,7 +40,7 @@ * FIXME: IO should be max 256 bytes. However, since we may * have a P2P bridge below a cardbus bridge, we need 4K. */ -#define CARDBUS_IO_SIZE (4096) +#define CARDBUS_IO_SIZE (256) #define CARDBUS_MEM_SIZE (32*1024*1024) static void __devinit diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 84eedc96568..5598b4714f7 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -53,7 +53,9 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno) if (resno < 6) { reg = PCI_BASE_ADDRESS_0 + 4 * resno; } else if (resno == PCI_ROM_RESOURCE) { - new |= res->flags & IORESOURCE_ROM_ENABLE; + if (!(res->flags & IORESOURCE_ROM_ENABLE)) + return; + new |= PCI_ROM_ADDRESS_ENABLE; reg = dev->rom_base_reg; } else { /* Hmm, non-standard resource. */ diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 6f9fdb27640..599b116d974 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -41,6 +41,7 @@ module_param(io_speed, int, 0444); #ifdef CONFIG_PCMCIA_PROBE +#include <asm/irq.h> /* mask of IRQs already reserved by other cards, we should avoid using them */ static u8 pcmcia_used_irq[NR_IRQS]; #endif diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c index add12f7c489..6e5229e92fb 100644 --- a/drivers/pnp/card.c +++ b/drivers/pnp/card.c @@ -312,6 +312,8 @@ found: if (drv->link.driver.probe) { if (drv->link.driver.probe(&dev->dev)) { dev->dev.driver = NULL; + dev->card_link = NULL; + up_write(&dev->dev.bus->subsys.rwsem); return NULL; } } diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index d36258d6665..381f339e320 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -112,7 +112,7 @@ qdio_min(int a,int b) /***************** SCRUBBER HELPER ROUTINES **********************/ -static inline volatile __u64 +static inline __u64 qdio_get_micros(void) { return (get_clock() >> 10); /* time>>12 is microseconds */ @@ -230,7 +230,7 @@ qdio_siga_input(struct qdio_q *q) } /* locked by the locks in qdio_activate and qdio_cleanup */ -static __u32 * volatile +static __u32 volatile * qdio_get_indicator(void) { int i; diff --git a/drivers/s390/crypto/z90crypt.h b/drivers/s390/crypto/z90crypt.h index 82a1d97001d..0a3bb5a10dd 100644 --- a/drivers/s390/crypto/z90crypt.h +++ b/drivers/s390/crypto/z90crypt.h @@ -36,15 +36,6 @@ #define z90crypt_VARIANT 2 // 2 = added PCIXCC MCL3 and CEX2C support /** - * If we are not using the sparse checker, __user has no use. - */ -#ifdef __CHECKER__ -# define __user __attribute__((noderef, address_space(1))) -#else -# define __user -#endif - -/** * struct ica_rsa_modexpo * * Requirements: diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index e17b4d58a9f..bfe3ba73bc0 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -1299,13 +1299,10 @@ struct zfcp_port * zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, u32 d_id) { - struct zfcp_port *port, *tmp_port; + struct zfcp_port *port; int check_wwpn; - scsi_id_t scsi_id; - int found; check_wwpn = !(status & ZFCP_STATUS_PORT_NO_WWPN); - /* * check that there is no port with this WWPN already in list */ @@ -1368,7 +1365,7 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, } else { snprintf(port->sysfs_device.bus_id, BUS_ID_SIZE, "0x%016llx", wwpn); - port->sysfs_device.parent = &adapter->ccw_device->dev; + port->sysfs_device.parent = &adapter->ccw_device->dev; } port->sysfs_device.release = zfcp_sysfs_port_release; dev_set_drvdata(&port->sysfs_device, port); @@ -1388,24 +1385,8 @@ zfcp_port_enqueue(struct zfcp_adapter *adapter, wwn_t wwpn, u32 status, zfcp_port_get(port); - scsi_id = 1; - found = 0; write_lock_irq(&zfcp_data.config_lock); - list_for_each_entry(tmp_port, &adapter->port_list_head, list) { - if (atomic_test_mask(ZFCP_STATUS_PORT_NO_SCSI_ID, - &tmp_port->status)) - continue; - if (tmp_port->scsi_id != scsi_id) { - found = 1; - break; - } - scsi_id++; - } - port->scsi_id = scsi_id; - if (found) - list_add_tail(&port->list, &tmp_port->list); - else - list_add_tail(&port->list, &adapter->port_list_head); + list_add_tail(&port->list, &adapter->port_list_head); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status); atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &port->status); if (d_id == ZFCP_DID_DIRECTORY_SERVICE) @@ -1427,6 +1408,9 @@ zfcp_port_dequeue(struct zfcp_port *port) list_del(&port->list); port->adapter->ports--; write_unlock_irq(&zfcp_data.config_lock); + if (port->rport) + fc_remote_port_delete(port->rport); + port->rport = NULL; zfcp_adapter_put(port->adapter); zfcp_sysfs_port_remove_files(&port->sysfs_device, atomic_read(&port->status)); diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 0fc46381fc2..b30abab77da 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -202,9 +202,19 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device) { struct zfcp_adapter *adapter; + struct zfcp_port *port; + struct fc_rport *rport; down(&zfcp_data.config_sema); adapter = dev_get_drvdata(&ccw_device->dev); + /* might be racy, but we cannot take config_lock due to the fact that + fc_remote_port_delete might sleep */ + list_for_each_entry(port, &adapter->port_list_head, list) + if (port->rport) { + rport = port->rport; + port->rport = NULL; + fc_remote_port_delete(rport); + } zfcp_erp_adapter_shutdown(adapter, 0); zfcp_erp_wait(adapter); zfcp_adapter_scsi_unregister(adapter); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 4103b5be768..455e902533a 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -906,6 +906,7 @@ struct zfcp_adapter { */ struct zfcp_port { struct device sysfs_device; /* sysfs device */ + struct fc_rport *rport; /* rport of fc transport class */ struct list_head list; /* list of remote ports */ atomic_t refcount; /* reference count */ wait_queue_head_t remove_wq; /* can be used to wait for @@ -916,7 +917,6 @@ struct zfcp_port { list */ u32 units; /* # of logical units in list */ atomic_t status; /* status of this remote port */ - scsi_id_t scsi_id; /* own SCSI ID */ wwn_t wwnn; /* WWNN if known */ wwn_t wwpn; /* WWPN */ fc_id_t d_id; /* D_ID */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 0cf31f7d1c0..cb4f612550b 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -3360,13 +3360,32 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, if ((result == ZFCP_ERP_SUCCEEDED) && (!atomic_test_mask(ZFCP_STATUS_UNIT_TEMPORARY, &unit->status)) - && (!unit->device)) - scsi_add_device(unit->port->adapter->scsi_host, 0, - unit->port->scsi_id, unit->scsi_lun); + && !unit->device + && port->rport) + scsi_add_device(port->adapter->scsi_host, 0, + port->rport->scsi_target_id, + unit->scsi_lun); zfcp_unit_put(unit); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: case ZFCP_ERP_ACTION_REOPEN_PORT: + if ((result == ZFCP_ERP_SUCCEEDED) + && !atomic_test_mask(ZFCP_STATUS_PORT_NO_WWPN, + &port->status) + && !port->rport) { + struct fc_rport_identifiers ids; + ids.node_name = port->wwnn; + ids.port_name = port->wwpn; + ids.port_id = port->d_id; + ids.roles = FC_RPORT_ROLE_FCP_TARGET; + port->rport = + fc_remote_port_add(adapter->scsi_host, 0, &ids); + if (!port->rport) + ZFCP_LOG_NORMAL("failed registration of rport" + "(adapter %s, wwpn=0x%016Lx)\n", + zfcp_get_busid_by_port(port), + port->wwpn); + } zfcp_port_put(port); break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 42df7e57eea..cd98a2de9f8 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -143,6 +143,8 @@ extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *, struct scsi_cmnd *, struct timer_list *); extern int zfcp_scsi_command_sync(struct zfcp_unit *, struct scsi_cmnd *, struct timer_list *); +extern void zfcp_set_fc_host_attrs(struct zfcp_adapter *); +extern void zfcp_set_fc_rport_attrs(struct zfcp_port *); extern struct scsi_transport_template *zfcp_transport_template; extern struct fc_function_template zfcp_transport_functions; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 0d9f20edc49..c007b6424e7 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -2062,6 +2062,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) zfcp_erp_adapter_shutdown(adapter, 0); return -EIO; } + zfcp_set_fc_host_attrs(adapter); return 0; } diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index b61d309352c..31a76065cf2 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -389,7 +389,7 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id, struct zfcp_unit *unit, *retval = NULL; list_for_each_entry(port, &adapter->port_list_head, list) { - if (id != port->scsi_id) + if (!port->rport || (id != port->rport->scsi_target_id)) continue; list_for_each_entry(unit, &port->unit_list_head, list) { if (lun == unit->scsi_lun) { @@ -408,7 +408,7 @@ zfcp_port_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id) struct zfcp_port *port; list_for_each_entry(port, &adapter->port_list_head, list) { - if (id == port->scsi_id) + if (port->rport && (id == port->rport->scsi_target_id)) return port; } return (struct zfcp_port *) NULL; @@ -634,7 +634,6 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) { int retval; struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata; - struct Scsi_Host *scsi_host = scpnt->device->host; if (!unit) { ZFCP_LOG_NORMAL("bug: Tried reset for nonexistent unit\n"); @@ -729,7 +728,6 @@ zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt) { int retval = 0; struct zfcp_unit *unit; - struct Scsi_Host *scsi_host = scpnt->device->host; unit = (struct zfcp_unit *) scpnt->device->hostdata; ZFCP_LOG_NORMAL("bus reset because of problems with " @@ -753,7 +751,6 @@ zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { int retval = 0; struct zfcp_unit *unit; - struct Scsi_Host *scsi_host = scpnt->device->host; unit = (struct zfcp_unit *) scpnt->device->hostdata; ZFCP_LOG_NORMAL("host reset because of problems with " @@ -833,6 +830,7 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) shost = adapter->scsi_host; if (!shost) return; + fc_remove_host(shost); scsi_remove_host(shost); scsi_host_put(shost); adapter->scsi_host = NULL; @@ -906,6 +904,18 @@ zfcp_get_node_name(struct scsi_target *starget) read_unlock_irqrestore(&zfcp_data.config_lock, flags); } +void +zfcp_set_fc_host_attrs(struct zfcp_adapter *adapter) +{ + struct Scsi_Host *shost = adapter->scsi_host; + + fc_host_node_name(shost) = adapter->wwnn; + fc_host_port_name(shost) = adapter->wwpn; + strncpy(fc_host_serial_number(shost), adapter->serial_number, + min(FC_SERIAL_NUMBER_SIZE, 32)); + fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; +} + struct fc_function_template zfcp_transport_functions = { .get_starget_port_id = zfcp_get_port_id, .get_starget_port_name = zfcp_get_port_name, @@ -913,6 +923,11 @@ struct fc_function_template zfcp_transport_functions = { .show_starget_port_id = 1, .show_starget_port_name = 1, .show_starget_node_name = 1, + .show_rport_supported_classes = 1, + .show_host_node_name = 1, + .show_host_port_name = 1, + .show_host_supported_classes = 1, + .show_host_serial_number = 1, }; /** diff --git a/drivers/s390/scsi/zfcp_sysfs_port.c b/drivers/s390/scsi/zfcp_sysfs_port.c index 7a84c7d474d..c55e82d91de 100644 --- a/drivers/s390/scsi/zfcp_sysfs_port.c +++ b/drivers/s390/scsi/zfcp_sysfs_port.c @@ -67,7 +67,6 @@ static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_port_##_name##_show, NULL); ZFCP_DEFINE_PORT_ATTR(status, "0x%08x\n", atomic_read(&port->status)); ZFCP_DEFINE_PORT_ATTR(wwnn, "0x%016llx\n", port->wwnn); ZFCP_DEFINE_PORT_ATTR(d_id, "0x%06x\n", port->d_id); -ZFCP_DEFINE_PORT_ATTR(scsi_id, "0x%x\n", port->scsi_id); ZFCP_DEFINE_PORT_ATTR(in_recovery, "%d\n", atomic_test_mask (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)); ZFCP_DEFINE_PORT_ATTR(access_denied, "%d\n", atomic_test_mask @@ -263,7 +262,6 @@ static struct attribute_group zfcp_port_common_attr_group = { static struct attribute *zfcp_port_no_ns_attrs[] = { &dev_attr_unit_add.attr, &dev_attr_unit_remove.attr, - &dev_attr_scsi_id.attr, NULL }; diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index f1e8c4223ed..12c208fb18c 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1696,7 +1696,7 @@ config TT_DMA_EMUL config MAC_SCSI bool "Macintosh NCR5380 SCSI" - depends on MAC && SCSI + depends on MAC && SCSI=y help This is the NCR 5380 SCSI controller included on most of the 68030 based Macintoshes. If you have one of these say Y and read the @@ -1717,7 +1717,7 @@ config SCSI_MAC_ESP config MVME147_SCSI bool "WD33C93 SCSI driver for MVME147" - depends on MVME147 && SCSI + depends on MVME147 && SCSI=y help Support for the on-board SCSI controller on the Motorola MVME147 single-board computer. @@ -1758,7 +1758,7 @@ config SUN3_SCSI config SUN3X_ESP bool "Sun3x ESP SCSI" - depends on SUN3X && SCSI + depends on SUN3X && SCSI=y help The ESP was an on-board SCSI controller used on Sun 3/80 machines. Say Y here to compile in support for it. diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index c5623694d10..841f4e2cfe0 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -269,6 +269,8 @@ static struct pci_device_id ahci_pci_tbl[] = { board_ahci }, /* ESB2 */ { PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_ahci }, /* ESB2 */ + { PCI_VENDOR_ID_INTEL, 0x27c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_ahci }, /* ICH7-M DH */ { } /* terminate list */ }; @@ -584,12 +586,16 @@ static void ahci_intr_error(struct ata_port *ap, u32 irq_stat) static void ahci_eng_timeout(struct ata_port *ap) { - void *mmio = ap->host_set->mmio_base; + struct ata_host_set *host_set = ap->host_set; + void *mmio = host_set->mmio_base; void *port_mmio = ahci_port_base(mmio, ap->port_no); struct ata_queued_cmd *qc; + unsigned long flags; DPRINTK("ENTER\n"); + spin_lock_irqsave(&host_set->lock, flags); + ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT)); qc = ata_qc_from_tag(ap, ap->active_tag); @@ -607,6 +613,7 @@ static void ahci_eng_timeout(struct ata_port *ap) ata_qc_complete(qc, ATA_ERR); } + spin_unlock_irqrestore(&host_set->lock, flags); } static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc) @@ -696,9 +703,6 @@ static int ahci_qc_issue(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; void *port_mmio = (void *) ap->ioaddr.cmd_addr; - writel(1, port_mmio + PORT_SCR_ACT); - readl(port_mmio + PORT_SCR_ACT); /* flush */ - writel(1, port_mmio + PORT_CMD_ISSUE); readl(port_mmio + PORT_CMD_ISSUE); /* flush */ @@ -1105,6 +1109,7 @@ MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("AHCI SATA low-level driver"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, ahci_pci_tbl); +MODULE_VERSION(DRV_VERSION); module_init(ahci_init); module_exit(ahci_exit); diff --git a/drivers/scsi/arm/Kconfig b/drivers/scsi/arm/Kconfig index 54b32868aaf..13f23043c8a 100644 --- a/drivers/scsi/arm/Kconfig +++ b/drivers/scsi/arm/Kconfig @@ -3,7 +3,7 @@ # config SCSI_ACORNSCSI_3 tristate "Acorn SCSI card (aka30) support" - depends on ARCH_ACORN && SCSI + depends on ARCH_ACORN && SCSI && BROKEN help This enables support for the Acorn SCSI card (aka30). If you have an Acorn system with one of these, say Y. If unsure, say N. diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index a2cfade2c1c..03695616e59 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -32,7 +32,7 @@ #include <linux/libata.h> #define DRV_NAME "ata_piix" -#define DRV_VERSION "1.03" +#define DRV_VERSION "1.04" enum { PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ @@ -629,13 +629,13 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) port_info[1] = NULL; if (port_info[0]->host_flags & PIIX_FLAG_AHCI) { - u8 tmp; - pci_read_config_byte(pdev, PIIX_SCC, &tmp); - if (tmp == PIIX_AHCI_DEVICE) { - int rc = piix_disable_ahci(pdev); - if (rc) - return rc; - } + u8 tmp; + pci_read_config_byte(pdev, PIIX_SCC, &tmp); + if (tmp == PIIX_AHCI_DEVICE) { + int rc = piix_disable_ahci(pdev); + if (rc) + return rc; + } } if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) { diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 73b1f72b7e4..f15a07f9f47 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1304,12 +1304,12 @@ static inline u8 ata_dev_knobble(struct ata_port *ap) /** * ata_dev_config - Run device specific handlers and check for * SATA->PATA bridges - * @ap: Bus + * @ap: Bus * @i: Device * * LOCKING: */ - + void ata_dev_config(struct ata_port *ap, unsigned int i) { /* limit bridge transfers to udma5, 200 sectors */ @@ -2268,19 +2268,6 @@ void ata_qc_prep(struct ata_queued_cmd *qc) * spin_lock_irqsave(host_set lock) */ - - -/** - * ata_sg_init_one - Prepare a one-entry scatter-gather list. - * @qc: Queued command - * @buf: transfer buffer - * @buflen: length of buf - * - * Builds a single-entry scatter-gather list to initiate a - * transfer utilizing the specified buffer. - * - * LOCKING: - */ void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen) { struct scatterlist *sg; @@ -2312,18 +2299,6 @@ void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen) * spin_lock_irqsave(host_set lock) */ - -/** - * ata_sg_init - Assign a scatter gather list to a queued command - * @qc: Queued command - * @sg: Scatter-gather list - * @n_elem: length of sg list - * - * Attaches a scatter-gather list to a queued command. - * - * LOCKING: - */ - void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, unsigned int n_elem) { @@ -2402,6 +2377,27 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) } /** + * ata_poll_qc_complete - turn irq back on and finish qc + * @qc: Command to complete + * @drv_stat: ATA status register content + * + * LOCKING: + * None. (grabs host lock) + */ + +void ata_poll_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +{ + struct ata_port *ap = qc->ap; + unsigned long flags; + + spin_lock_irqsave(&ap->host_set->lock, flags); + ap->flags &= ~ATA_FLAG_NOINTR; + ata_irq_on(ap); + ata_qc_complete(qc, drv_stat); + spin_unlock_irqrestore(&ap->host_set->lock, flags); +} + +/** * ata_pio_poll - * @ap: * @@ -2463,11 +2459,10 @@ static void ata_pio_complete (struct ata_port *ap) u8 drv_stat; /* - * This is purely hueristic. This is a fast path. - * Sometimes when we enter, BSY will be cleared in - * a chk-status or two. If not, the drive is probably seeking - * or something. Snooze for a couple msecs, then - * chk-status again. If still busy, fall back to + * This is purely heuristic. This is a fast path. Sometimes when + * we enter, BSY will be cleared in a chk-status or two. If not, + * the drive is probably seeking or something. Snooze for a couple + * msecs, then chk-status again. If still busy, fall back to * PIO_ST_POLL state. */ drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10); @@ -2492,9 +2487,7 @@ static void ata_pio_complete (struct ata_port *ap) ap->pio_task_state = PIO_ST_IDLE; - ata_irq_on(ap); - - ata_qc_complete(qc, drv_stat); + ata_poll_qc_complete(qc, drv_stat); } @@ -2519,6 +2512,20 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) #endif /* __BIG_ENDIAN */ } +/** + * ata_mmio_data_xfer - Transfer data by MMIO + * @ap: port to read/write + * @buf: data buffer + * @buflen: buffer length + * @do_write: read/write + * + * Transfer data from/to the device data register by MMIO. + * + * LOCKING: + * Inherited from caller. + * + */ + static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, unsigned int buflen, int write_data) { @@ -2527,6 +2534,7 @@ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, u16 *buf16 = (u16 *) buf; void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr; + /* Transfer multiple of 2 bytes */ if (write_data) { for (i = 0; i < words; i++) writew(le16_to_cpu(buf16[i]), mmio); @@ -2534,19 +2542,76 @@ static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, for (i = 0; i < words; i++) buf16[i] = cpu_to_le16(readw(mmio)); } + + /* Transfer trailing 1 byte, if any. */ + if (unlikely(buflen & 0x01)) { + u16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (write_data) { + memcpy(align_buf, trailing_buf, 1); + writew(le16_to_cpu(align_buf[0]), mmio); + } else { + align_buf[0] = cpu_to_le16(readw(mmio)); + memcpy(trailing_buf, align_buf, 1); + } + } } +/** + * ata_pio_data_xfer - Transfer data by PIO + * @ap: port to read/write + * @buf: data buffer + * @buflen: buffer length + * @do_write: read/write + * + * Transfer data from/to the device data register by PIO. + * + * LOCKING: + * Inherited from caller. + * + */ + static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, unsigned int buflen, int write_data) { - unsigned int dwords = buflen >> 1; + unsigned int words = buflen >> 1; + /* Transfer multiple of 2 bytes */ if (write_data) - outsw(ap->ioaddr.data_addr, buf, dwords); + outsw(ap->ioaddr.data_addr, buf, words); else - insw(ap->ioaddr.data_addr, buf, dwords); + insw(ap->ioaddr.data_addr, buf, words); + + /* Transfer trailing 1 byte, if any. */ + if (unlikely(buflen & 0x01)) { + u16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (write_data) { + memcpy(align_buf, trailing_buf, 1); + outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr); + } else { + align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr)); + memcpy(trailing_buf, align_buf, 1); + } + } } +/** + * ata_data_xfer - Transfer data from/to the data register. + * @ap: port to read/write + * @buf: data buffer + * @buflen: buffer length + * @do_write: read/write + * + * Transfer data from/to the device data register. + * + * LOCKING: + * Inherited from caller. + * + */ + static void ata_data_xfer(struct ata_port *ap, unsigned char *buf, unsigned int buflen, int do_write) { @@ -2556,6 +2621,16 @@ static void ata_data_xfer(struct ata_port *ap, unsigned char *buf, ata_pio_data_xfer(ap, buf, buflen, do_write); } +/** + * ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data. + * @qc: Command on going + * + * Transfer ATA_SECT_SIZE of data from/to the ATA device. + * + * LOCKING: + * Inherited from caller. + */ + static void ata_pio_sector(struct ata_queued_cmd *qc) { int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); @@ -2594,6 +2669,18 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) kunmap(page); } +/** + * __atapi_pio_bytes - Transfer data from/to the ATAPI device. + * @qc: Command on going + * @bytes: number of bytes + * + * Transfer Transfer data from/to the ATAPI device. + * + * LOCKING: + * Inherited from caller. + * + */ + static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) { int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); @@ -2603,10 +2690,33 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) unsigned char *buf; unsigned int offset, count; - if (qc->curbytes == qc->nbytes - bytes) + if (qc->curbytes + bytes >= qc->nbytes) ap->pio_task_state = PIO_ST_LAST; next_sg: + if (unlikely(qc->cursg >= qc->n_elem)) { + /* + * The end of qc->sg is reached and the device expects + * more data to transfer. In order not to overrun qc->sg + * and fulfill length specified in the byte count register, + * - for read case, discard trailing data from the device + * - for write case, padding zero data to the device + */ + u16 pad_buf[1] = { 0 }; + unsigned int words = bytes >> 1; + unsigned int i; + + if (words) /* warning if bytes > 1 */ + printk(KERN_WARNING "ata%u: %u bytes trailing data\n", + ap->id, bytes); + + for (i = 0; i < words; i++) + ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write); + + ap->pio_task_state = PIO_ST_LAST; + return; + } + sg = &qc->sg[qc->cursg]; page = sg->page; @@ -2640,11 +2750,21 @@ next_sg: kunmap(page); - if (bytes) { + if (bytes) goto next_sg; - } } +/** + * atapi_pio_bytes - Transfer data from/to the ATAPI device. + * @qc: Command on going + * + * Transfer Transfer data from/to the ATAPI device. + * + * LOCKING: + * Inherited from caller. + * + */ + static void atapi_pio_bytes(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -2717,9 +2837,7 @@ static void ata_pio_block(struct ata_port *ap) if ((status & ATA_DRQ) == 0) { ap->pio_task_state = PIO_ST_IDLE; - ata_irq_on(ap); - - ata_qc_complete(qc, status); + ata_poll_qc_complete(qc, status); return; } @@ -2749,9 +2867,7 @@ static void ata_pio_error(struct ata_port *ap) ap->pio_task_state = PIO_ST_IDLE; - ata_irq_on(ap); - - ata_qc_complete(qc, drv_stat | ATA_ERR); + ata_poll_qc_complete(qc, drv_stat | ATA_ERR); } static void ata_pio_task(void *_data) @@ -2857,8 +2973,10 @@ static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, static void ata_qc_timeout(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + struct ata_host_set *host_set = ap->host_set; struct ata_device *dev = qc->dev; u8 host_stat = 0, drv_stat; + unsigned long flags; DPRINTK("ENTER\n"); @@ -2869,7 +2987,9 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) if (!(cmd->eh_eflags & SCSI_EH_CANCEL_CMD)) { /* finish completing original command */ + spin_lock_irqsave(&host_set->lock, flags); __ata_qc_complete(qc); + spin_unlock_irqrestore(&host_set->lock, flags); atapi_request_sense(ap, dev, cmd); @@ -2880,6 +3000,8 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) } } + spin_lock_irqsave(&host_set->lock, flags); + /* hack alert! We cannot use the supplied completion * function from inside the ->eh_strategy_handler() thread. * libata is the only user of ->eh_strategy_handler() in @@ -2895,7 +3017,7 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) host_stat = ap->ops->bmdma_status(ap); /* before we do anything else, clear DMA-Start bit */ - ap->ops->bmdma_stop(ap); + ap->ops->bmdma_stop(qc); /* fall through */ @@ -2913,6 +3035,9 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc) ata_qc_complete(qc, drv_stat); break; } + + spin_unlock_irqrestore(&host_set->lock, flags); + out: DPRINTK("EXIT\n"); } @@ -3086,9 +3211,14 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) if (likely(qc->flags & ATA_QCFLAG_DMAMAP)) ata_sg_clean(qc); + /* atapi: mark qc as inactive to prevent the interrupt handler + * from completing the command twice later, before the error handler + * is called. (when rc != 0 and atapi request sense is needed) + */ + qc->flags &= ~ATA_QCFLAG_ACTIVE; + /* call completion callback */ rc = qc->complete_fn(qc, drv_stat); - qc->flags &= ~ATA_QCFLAG_ACTIVE; /* if callback indicates not to complete command (non-zero), * return immediately @@ -3218,11 +3348,13 @@ int ata_qc_issue_prot(struct ata_queued_cmd *qc) break; case ATA_PROT_ATAPI_NODATA: + ap->flags |= ATA_FLAG_NOINTR; ata_tf_to_host_nolock(ap, &qc->tf); queue_work(ata_wq, &ap->packet_task); break; case ATA_PROT_ATAPI_DMA: + ap->flags |= ATA_FLAG_NOINTR; ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ ap->ops->bmdma_setup(qc); /* set up bmdma */ queue_work(ata_wq, &ap->packet_task); @@ -3267,7 +3399,7 @@ static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc) } /** - * ata_bmdma_start - Start a PCI IDE BMDMA transaction + * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. * * LOCKING: @@ -3438,7 +3570,7 @@ u8 ata_bmdma_status(struct ata_port *ap) /** * ata_bmdma_stop - Stop PCI IDE BMDMA transfer - * @ap: Port associated with this ATA transaction. + * @qc: Command we are ending DMA for * * Clears the ATA_DMA_START flag in the dma control register * @@ -3448,8 +3580,9 @@ u8 ata_bmdma_status(struct ata_port *ap) * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_stop(struct ata_port *ap) +void ata_bmdma_stop(struct ata_queued_cmd *qc) { + struct ata_port *ap = qc->ap; if (ap->flags & ATA_FLAG_MMIO) { void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; @@ -3501,7 +3634,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, goto idle_irq; /* before we do anything else, clear DMA-Start bit */ - ap->ops->bmdma_stop(ap); + ap->ops->bmdma_stop(qc); /* fall through */ @@ -3576,7 +3709,8 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) struct ata_port *ap; ap = host_set->ports[i]; - if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (ap && + !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); @@ -3628,19 +3762,27 @@ static void atapi_packet_task(void *_data) /* send SCSI cdb */ DPRINTK("send cdb\n"); assert(ap->cdb_len >= 12); - ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); - /* if we are DMA'ing, irq handler takes over from here */ - if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) - ap->ops->bmdma_start(qc); /* initiate bmdma */ + if (qc->tf.protocol == ATA_PROT_ATAPI_DMA || + qc->tf.protocol == ATA_PROT_ATAPI_NODATA) { + unsigned long flags; - /* non-data commands are also handled via irq */ - else if (qc->tf.protocol == ATA_PROT_ATAPI_NODATA) { - /* do nothing */ - } + /* Once we're done issuing command and kicking bmdma, + * irq handler takes over. To not lose irq, we need + * to clear NOINTR flag before sending cdb, but + * interrupt handler shouldn't be invoked before we're + * finished. Hence, the following locking. + */ + spin_lock_irqsave(&ap->host_set->lock, flags); + ap->flags &= ~ATA_FLAG_NOINTR; + ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); + if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) + ap->ops->bmdma_start(qc); /* initiate bmdma */ + spin_unlock_irqrestore(&ap->host_set->lock, flags); + } else { + ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); - /* PIO commands are handled by polling */ - else { + /* PIO commands are handled by polling */ ap->pio_task_state = PIO_ST; queue_work(ata_wq, &ap->pio_task); } @@ -3648,7 +3790,7 @@ static void atapi_packet_task(void *_data) return; err_out: - ata_qc_complete(qc, ATA_ERR); + ata_poll_qc_complete(qc, ATA_ERR); } diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 6a75ec2187f..4074e7877ba 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -392,6 +392,60 @@ int ata_scsi_error(struct Scsi_Host *host) } /** + * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command + * @qc: Storage for translated ATA taskfile + * @scsicmd: SCSI command to translate + * + * Sets up an ATA taskfile to issue STANDBY (to stop) or READ VERIFY + * (to start). Perhaps these commands should be preceded by + * CHECK POWER MODE to see what power mode the device is already in. + * [See SAT revision 5 at www.t10.org] + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Zero on success, non-zero on error. + */ + +static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, + u8 *scsicmd) +{ + struct ata_taskfile *tf = &qc->tf; + + tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; + tf->protocol = ATA_PROT_NODATA; + if (scsicmd[1] & 0x1) { + ; /* ignore IMMED bit, violates sat-r05 */ + } + if (scsicmd[4] & 0x2) + return 1; /* LOEJ bit set not supported */ + if (((scsicmd[4] >> 4) & 0xf) != 0) + return 1; /* power conditions not supported */ + if (scsicmd[4] & 0x1) { + tf->nsect = 1; /* 1 sector, lba=0 */ + tf->lbah = 0x0; + tf->lbam = 0x0; + tf->lbal = 0x0; + tf->device |= ATA_LBA; + tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ + } else { + tf->nsect = 0; /* time period value (0 implies now) */ + tf->command = ATA_CMD_STANDBY; + /* Consider: ATA STANDBY IMMEDIATE command */ + } + /* + * Standby and Idle condition timers could be implemented but that + * would require libata to implement the Power condition mode page + * and allow the user to change it. Changing mode pages requires + * MODE SELECT to be implemented. + */ + + return 0; +} + + +/** * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command * @qc: Storage for translated ATA taskfile * @scsicmd: SCSI command to translate (ignored) @@ -576,11 +630,19 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) tf->lbah = scsicmd[3]; VPRINTK("ten-byte command\n"); + if (qc->nsect == 0) /* we don't support length==0 cmds */ + return 1; return 0; } if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) { qc->nsect = tf->nsect = scsicmd[4]; + if (!qc->nsect) { + qc->nsect = 256; + if (lba48) + tf->hob_nsect = 1; + } + tf->lbal = scsicmd[3]; tf->lbam = scsicmd[2]; tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */ @@ -620,6 +682,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) tf->lbah = scsicmd[7]; VPRINTK("sixteen-byte command\n"); + if (qc->nsect == 0) /* we don't support length==0 cmds */ + return 1; return 0; } @@ -1435,6 +1499,8 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) case VERIFY: case VERIFY_16: return ata_scsi_verify_xlat; + case START_STOP: + return ata_scsi_start_stop_xlat; } return NULL; diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index d90430bbb0d..620d21772bd 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -26,7 +26,7 @@ #define __LIBATA_H__ #define DRV_NAME "libata" -#define DRV_VERSION "1.11" /* must be exactly four chars */ +#define DRV_VERSION "1.12" /* must be exactly four chars */ struct ata_scsi_args { u16 *id; @@ -72,7 +72,7 @@ extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, extern void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq); -extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, +extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen)); diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index b0403ccd8a2..41a3421b02b 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -20,6 +20,12 @@ * If you do not delete the provisions above, a recipient may use your * version of this file under either the OSL or the GPL. * + * 0.08 + * - Added support for MCP51 and MCP55. + * + * 0.07 + * - Added support for RAID class code. + * * 0.06 * - Added generic SATA support by using a pci_device_id that filters on * the IDE storage class code. @@ -48,7 +54,7 @@ #include <linux/libata.h> #define DRV_NAME "sata_nv" -#define DRV_VERSION "0.6" +#define DRV_VERSION "0.8" #define NV_PORTS 2 #define NV_PIO_MASK 0x1f @@ -116,7 +122,9 @@ enum nv_host_type GENERIC, NFORCE2, NFORCE3, - CK804 + CK804, + MCP51, + MCP55 }; static struct pci_device_id nv_pci_tbl[] = { @@ -134,9 +142,18 @@ static struct pci_device_id nv_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP51 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP51 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP55 }, { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC }, + { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_RAID<<8, 0xffff00, GENERIC }, { 0, } /* terminate list */ }; @@ -274,7 +291,8 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance, struct ata_port *ap; ap = host_set->ports[i]; - if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (ap && + !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index 5c1d4411457..b8dc49fed76 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -40,7 +40,7 @@ #include "sata_promise.h" #define DRV_NAME "sata_promise" -#define DRV_VERSION "1.01" +#define DRV_VERSION "1.02" enum { @@ -181,6 +181,10 @@ static struct pci_device_id pdc_ata_pci_tbl[] = { board_20319 }, { PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20319 }, + { PCI_VENDOR_ID_PROMISE, 0x3519, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_20319 }, + { PCI_VENDOR_ID_PROMISE, 0x3d17, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_20319 }, { PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20319 }, @@ -321,11 +325,15 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc) static void pdc_eng_timeout(struct ata_port *ap) { + struct ata_host_set *host_set = ap->host_set; u8 drv_stat; struct ata_queued_cmd *qc; + unsigned long flags; DPRINTK("ENTER\n"); + spin_lock_irqsave(&host_set->lock, flags); + qc = ata_qc_from_tag(ap, ap->active_tag); if (!qc) { printk(KERN_ERR "ata%u: BUG: timeout without command\n", @@ -359,6 +367,7 @@ static void pdc_eng_timeout(struct ata_port *ap) } out: + spin_unlock_irqrestore(&host_set->lock, flags); DPRINTK("EXIT\n"); } @@ -441,7 +450,8 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r VPRINTK("port %u\n", i); ap = host_set->ports[i]; tmp = mask & (1 << (i + 1)); - if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (tmp && ap && + !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c index 1383e8a28d7..93fd06fb4f1 100644 --- a/drivers/scsi/sata_qstor.c +++ b/drivers/scsi/sata_qstor.c @@ -117,7 +117,7 @@ static void qs_phy_reset(struct ata_port *ap); static void qs_qc_prep(struct ata_queued_cmd *qc); static int qs_qc_issue(struct ata_queued_cmd *qc); static int qs_check_atapi_dma(struct ata_queued_cmd *qc); -static void qs_bmdma_stop(struct ata_port *ap); +static void qs_bmdma_stop(struct ata_queued_cmd *qc); static u8 qs_bmdma_status(struct ata_port *ap); static void qs_irq_clear(struct ata_port *ap); static void qs_eng_timeout(struct ata_port *ap); @@ -198,7 +198,7 @@ static int qs_check_atapi_dma(struct ata_queued_cmd *qc) return 1; /* ATAPI DMA not supported */ } -static void qs_bmdma_stop(struct ata_port *ap) +static void qs_bmdma_stop(struct ata_queued_cmd *qc) { /* nothing */ } @@ -386,7 +386,8 @@ static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set) DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n", sff1, sff0, port_no, sHST, sDST); handled = 1; - if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (ap && !(ap->flags & + (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_pkt) @@ -417,7 +418,8 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set) for (port_no = 0; port_no < host_set->n_ports; ++port_no) { struct ata_port *ap; ap = host_set->ports[port_no]; - if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (ap && + !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_mmio) @@ -431,7 +433,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set) continue; DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", ap->id, qc->tf.protocol, status); - + /* complete taskfile transaction */ pp->state = qs_state_idle; ata_qc_complete(qc, status); diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index 49ed557a4b6..9d24d6c328b 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -24,6 +24,11 @@ * If you do not delete the provisions above, a recipient may use your * version of this file under either the OSL or the GPL. * + * Documentation for SiI 3112: + * http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2 + * + * Other errata and documentation available under NDA. + * */ #include <linux/kernel.h> @@ -41,8 +46,11 @@ #define DRV_VERSION "0.9" enum { + SIL_FLAG_MOD15WRITE = (1 << 30), + sil_3112 = 0, - sil_3114 = 1, + sil_3112_m15w = 1, + sil_3114 = 2, SIL_FIFO_R0 = 0x40, SIL_FIFO_W0 = 0x41, @@ -76,13 +84,13 @@ static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static void sil_post_set_mode (struct ata_port *ap); static struct pci_device_id sil_pci_tbl[] = { - { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, - { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, + { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w }, + { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w }, { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 }, - { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, - { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, - { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, + { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w }, + { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w }, + { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w }, { } /* terminate list */ }; @@ -174,6 +182,16 @@ static struct ata_port_info sil_port_info[] = { .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, + }, /* sil_3112_15w - keep it sync'd w/ sil_3112 */ + { + .sht = &sil_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SRST | ATA_FLAG_MMIO | + SIL_FLAG_MOD15WRITE, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &sil_ops, }, /* sil_3114 */ { .sht = &sil_sht, @@ -323,15 +341,15 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) while ((len > 0) && (s[len - 1] == ' ')) len--; - for (n = 0; sil_blacklist[n].product; n++) + for (n = 0; sil_blacklist[n].product; n++) if (!memcmp(sil_blacklist[n].product, s, strlen(sil_blacklist[n].product))) { quirks = sil_blacklist[n].quirk; break; } - + /* limit requests to 15 sectors */ - if (quirks & SIL_QUIRK_MOD15WRITE) { + if ((ap->flags & SIL_FLAG_MOD15WRITE) && (quirks & SIL_QUIRK_MOD15WRITE)) { printk(KERN_INFO "ata%u(%u): applying Seagate errata fix\n", ap->id, dev->devno); ap->host->max_sectors = 15; diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index e418b89c6b9..b250ae0c777 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c @@ -234,7 +234,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) pci_read_config_dword(pdev, SIS_GENCTL, &genctl); if ((genctl & GENCTL_IOMAPPED_SCR) == 0) probe_ent->host_flags |= SIS_FLAG_CFGSCR; - + /* if hardware thinks SCRs are in IO space, but there are * no IO resources assigned, change to PCI cfg space. */ diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index 858e07185db..6fd2ce1ffcd 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -195,18 +195,18 @@ static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc) /* start host DMA transaction */ dmactl = readb(mmio + ATA_DMA_CMD); writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD); - /* There is a race condition in certain SATA controllers that can - be seen when the r/w command is given to the controller before the + /* There is a race condition in certain SATA controllers that can + be seen when the r/w command is given to the controller before the host DMA is started. On a Read command, the controller would initiate the command to the drive even before it sees the DMA start. When there - are very fast drives connected to the controller, or when the data request + are very fast drives connected to the controller, or when the data request hits in the drive cache, there is the possibility that the drive returns a part or all of the requested data to the controller before the DMA start is issued. In this case, the controller would become confused as to what to do with the data. In the worst case when all the data is returned back to the controller, the controller could hang. In other cases it could return partial data returning in data corruption. This problem has been seen in PPC systems and can also appear - on an system with very fast disks, where the SATA controller is sitting behind a + on an system with very fast disks, where the SATA controller is sitting behind a number of bridges, and hence there is significant latency between the r/w command and the start command. */ /* issue r/w command if the access is to ATA*/ @@ -214,7 +214,7 @@ static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc) ap->ops->exec_command(ap, &qc->tf); } - + static u8 k2_stat_check_status(struct ata_port *ap) { return readl((void *) ap->ioaddr.status_addr); diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index efd7d7a6113..a20d4285090 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -94,7 +94,7 @@ enum { PDC_DIMM1_CONTROL_OFFSET = 0x84, PDC_SDRAM_CONTROL_OFFSET = 0x88, PDC_I2C_WRITE = 0x00000000, - PDC_I2C_READ = 0x00000040, + PDC_I2C_READ = 0x00000040, PDC_I2C_START = 0x00000080, PDC_I2C_MASK_INT = 0x00000020, PDC_I2C_COMPLETE = 0x00010000, @@ -105,16 +105,16 @@ enum { PDC_DIMM_SPD_COLUMN_NUM = 4, PDC_DIMM_SPD_MODULE_ROW = 5, PDC_DIMM_SPD_TYPE = 11, - PDC_DIMM_SPD_FRESH_RATE = 12, - PDC_DIMM_SPD_BANK_NUM = 17, + PDC_DIMM_SPD_FRESH_RATE = 12, + PDC_DIMM_SPD_BANK_NUM = 17, PDC_DIMM_SPD_CAS_LATENCY = 18, - PDC_DIMM_SPD_ATTRIBUTE = 21, + PDC_DIMM_SPD_ATTRIBUTE = 21, PDC_DIMM_SPD_ROW_PRE_CHARGE = 27, - PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28, + PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28, PDC_DIMM_SPD_RAS_CAS_DELAY = 29, PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30, PDC_DIMM_SPD_SYSTEM_FREQ = 126, - PDC_CTL_STATUS = 0x08, + PDC_CTL_STATUS = 0x08, PDC_DIMM_WINDOW_CTLR = 0x0C, PDC_TIME_CONTROL = 0x3C, PDC_TIME_PERIOD = 0x40, @@ -157,15 +157,15 @@ static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc20621_host_stop(struct ata_host_set *host_set); static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe); static int pdc20621_detect_dimm(struct ata_probe_ent *pe); -static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, +static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, u32 subaddr, u32 *pdata); static int pdc20621_prog_dimm0(struct ata_probe_ent *pe); static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe); #ifdef ATA_VERBOSE_DEBUG -static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, +static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size); #endif -static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, +static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size); static void pdc20621_irq_clear(struct ata_port *ap); static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc); @@ -825,7 +825,8 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re ap = host_set->ports[port_no]; tmp = mask & (1 << i); VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp); - if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (tmp && ap && + !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); @@ -847,10 +848,14 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re static void pdc_eng_timeout(struct ata_port *ap) { u8 drv_stat; + struct ata_host_set *host_set = ap->host_set; struct ata_queued_cmd *qc; + unsigned long flags; DPRINTK("ENTER\n"); + spin_lock_irqsave(&host_set->lock, flags); + qc = ata_qc_from_tag(ap, ap->active_tag); if (!qc) { printk(KERN_ERR "ata%u: BUG: timeout without command\n", @@ -884,6 +889,7 @@ static void pdc_eng_timeout(struct ata_port *ap) } out: + spin_unlock_irqrestore(&host_set->lock, flags); DPRINTK("EXIT\n"); } @@ -922,7 +928,7 @@ static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base) #ifdef ATA_VERBOSE_DEBUG -static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, +static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size) { u32 window_size; @@ -936,9 +942,9 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; - page_mask = 0x00; - window_size = 0x2000 * 4; /* 32K byte uchar size */ - idx = (u16) (offset / window_size); + page_mask = 0x00; + window_size = 0x2000 * 4; /* 32K byte uchar size */ + idx = (u16) (offset / window_size); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); @@ -947,19 +953,19 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, offset -= (idx * window_size); idx++; - dist = ((long) (window_size - (offset + size))) >= 0 ? size : + dist = ((long) (window_size - (offset + size))) >= 0 ? size : (long) (window_size - offset); - memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4), + memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4), dist); - psource += dist; + psource += dist; size -= dist; for (; (long) size >= (long) window_size ;) { writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_fromio((char *) psource, (char *) (dimm_mmio), + memcpy_fromio((char *) psource, (char *) (dimm_mmio), window_size / 4); psource += window_size; size -= window_size; @@ -971,14 +977,14 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, readl(mmio + PDC_GENERAL_CTLR); writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_fromio((char *) psource, (char *) (dimm_mmio), + memcpy_fromio((char *) psource, (char *) (dimm_mmio), size / 4); } } #endif -static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, +static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size) { u32 window_size; @@ -989,16 +995,16 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, struct pdc_host_priv *hpriv = pe->private_data; void *dimm_mmio = hpriv->dimm_mmio; - /* hard-code chip #0 */ + /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; - page_mask = 0x00; - window_size = 0x2000 * 4; /* 32K byte uchar size */ + page_mask = 0x00; + window_size = 0x2000 * 4; /* 32K byte uchar size */ idx = (u16) (offset / window_size); writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - offset -= (idx * window_size); + offset -= (idx * window_size); idx++; dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size : (long) (window_size - offset); @@ -1006,12 +1012,12 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); - psource += dist; + psource += dist; size -= dist; for (; (long) size >= (long) window_size ;) { writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_toio((char *) (dimm_mmio), (char *) psource, + memcpy_toio((char *) (dimm_mmio), (char *) psource, window_size / 4); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); @@ -1019,7 +1025,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, size -= window_size; idx ++; } - + if (size) { writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); @@ -1030,12 +1036,12 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, } -static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, +static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, u32 subaddr, u32 *pdata) { void *mmio = pe->mmio_base; u32 i2creg = 0; - u32 status; + u32 status; u32 count =0; /* hard-code chip #0 */ @@ -1049,7 +1055,7 @@ static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, readl(mmio + PDC_I2C_ADDR_DATA_OFFSET); /* Write Control to perform read operation, mask int */ - writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, + writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, mmio + PDC_I2C_CONTROL_OFFSET); for (count = 0; count <= 1000; count ++) { @@ -1062,26 +1068,26 @@ static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, } *pdata = (status >> 8) & 0x000000ff; - return 1; + return 1; } static int pdc20621_detect_dimm(struct ata_probe_ent *pe) { u32 data=0 ; - if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, + if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_SYSTEM_FREQ, &data)) { if (data == 100) return 100; } else return 0; - + if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) { - if(data <= 0x75) + if(data <= 0x75) return 133; } else return 0; - + return 0; } @@ -1091,15 +1097,15 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe) u32 spd0[50]; u32 data = 0; int size, i; - u8 bdimmsize; + u8 bdimmsize; void *mmio = pe->mmio_base; static const struct { unsigned int reg; unsigned int ofs; } pdc_i2c_read_data [] = { - { PDC_DIMM_SPD_TYPE, 11 }, + { PDC_DIMM_SPD_TYPE, 11 }, { PDC_DIMM_SPD_FRESH_RATE, 12 }, - { PDC_DIMM_SPD_COLUMN_NUM, 4 }, + { PDC_DIMM_SPD_COLUMN_NUM, 4 }, { PDC_DIMM_SPD_ATTRIBUTE, 21 }, { PDC_DIMM_SPD_ROW_NUM, 3 }, { PDC_DIMM_SPD_BANK_NUM, 17 }, @@ -1108,7 +1114,7 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe) { PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 }, { PDC_DIMM_SPD_RAS_CAS_DELAY, 29 }, { PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 }, - { PDC_DIMM_SPD_CAS_LATENCY, 18 }, + { PDC_DIMM_SPD_CAS_LATENCY, 18 }, }; /* hard-code chip #0 */ @@ -1116,17 +1122,17 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe) for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++) pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, - pdc_i2c_read_data[i].reg, + pdc_i2c_read_data[i].reg, &spd0[pdc_i2c_read_data[i].ofs]); - + data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4); - data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) | + data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) | ((((spd0[27] + 9) / 10) - 1) << 8) ; - data |= (((((spd0[29] > spd0[28]) - ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10; + data |= (((((spd0[29] > spd0[28]) + ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10; data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12; - - if (spd0[18] & 0x08) + + if (spd0[18] & 0x08) data |= ((0x03) << 14); else if (spd0[18] & 0x04) data |= ((0x02) << 14); @@ -1135,7 +1141,7 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe) else data |= (0 << 14); - /* + /* Calculate the size of bDIMMSize (power of 2) and merge the DIMM size by program start/end address. */ @@ -1145,9 +1151,9 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe) data |= (((size / 16) - 1) << 16); data |= (0 << 23); data |= 8; - writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET); + writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET); readl(mmio + PDC_DIMM0_CONTROL_OFFSET); - return size; + return size; } @@ -1167,12 +1173,12 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe) Refresh Enable (bit 17) */ - data = 0x022259F1; + data = 0x022259F1; writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); readl(mmio + PDC_SDRAM_CONTROL_OFFSET); /* Turn on for ECC */ - pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, + pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE, &spd0); if (spd0 == 0x02) { data |= (0x01 << 16); @@ -1186,22 +1192,22 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe) data |= (1<<19); writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); - error = 1; + error = 1; for (i = 1; i <= 10; i++) { /* polling ~5 secs */ data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET); if (!(data & (1<<19))) { error = 0; - break; + break; } msleep(i*100); } return error; } - + static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe) { - int speed, size, length; + int speed, size, length; u32 addr,spd0,pci_status; u32 tmp=0; u32 time_period=0; @@ -1228,7 +1234,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe) /* Wait 3 seconds */ msleep(3000); - /* + /* When timer is enabled, counter is decreased every internal clock cycle. */ @@ -1236,24 +1242,24 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe) tcount = readl(mmio + PDC_TIME_COUNTER); VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount); - /* + /* If SX4 is on PCI-X bus, after 3 seconds, the timer counter register should be >= (0xffffffff - 3x10^8). */ if(tcount >= PCI_X_TCOUNT) { ticks = (time_period - tcount); VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks); - + clock = (ticks / 300000); VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock); - + clock = (clock * 33); VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock); /* PLL F Param (bit 22:16) */ fparam = (1400000 / clock) - 2; VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam); - + /* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */ pci_status = (0x8a001824 | (fparam << 16)); } else @@ -1264,21 +1270,21 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe) writel(pci_status, mmio + PDC_CTL_STATUS); readl(mmio + PDC_CTL_STATUS); - /* + /* Read SPD of DIMM by I2C interface, and program the DIMM Module Controller. */ if (!(speed = pdc20621_detect_dimm(pe))) { - printk(KERN_ERR "Detect Local DIMM Fail\n"); + printk(KERN_ERR "Detect Local DIMM Fail\n"); return 1; /* DIMM error */ } VPRINTK("Local DIMM Speed = %d\n", speed); - /* Programming DIMM0 Module Control Register (index_CID0:80h) */ + /* Programming DIMM0 Module Control Register (index_CID0:80h) */ size = pdc20621_prog_dimm0(pe); VPRINTK("Local DIMM Size = %dMB\n",size); - /* Programming DIMM Module Global Control Register (index_CID0:88h) */ + /* Programming DIMM Module Global Control Register (index_CID0:88h) */ if (pdc20621_prog_dimm_global(pe)) { printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n"); return 1; @@ -1297,30 +1303,30 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe) pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40); pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40); - printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], + printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); - pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040, + pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040, 40); - printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], + printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40); pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40); - printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], + printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); } #endif /* ECC initiliazation. */ - pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, + pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE, &spd0); if (spd0 == 0x02) { VPRINTK("Start ECC initialization\n"); addr = 0; length = size * 1024 * 1024; while (addr < length) { - pdc20621_put_to_dimm(pe, (void *) &tmp, addr, + pdc20621_put_to_dimm(pe, (void *) &tmp, addr, sizeof(u32)); addr += sizeof(u32); } diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c index a71fb54eebd..eb202a73bc0 100644 --- a/drivers/scsi/sata_uli.c +++ b/drivers/scsi/sata_uli.c @@ -214,7 +214,7 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) rc = -ENOMEM; goto err_out_regions; } - + switch (board_idx) { case uli_5287: probe_ent->port[0].scr_addr = ULI5287_BASE; diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index f43183c19a1..feff1098048 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c @@ -347,7 +347,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent = vt6420_init_probe_ent(pdev); else probe_ent = vt6421_init_probe_ent(pdev); - + if (!probe_ent) { printk(KERN_ERR DRV_NAME "(%s): out of memory\n", pci_name(pdev)); diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index c5e09dc6f3d..6f2562171be 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -173,7 +173,8 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, struct ata_port *ap; ap = host_set->ports[i]; - if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (ap && !(ap->flags & + (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); @@ -342,7 +343,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d pci_set_master(pdev); - /* + /* * Config offset 0x98 is "Extended Control and Status Register 0" * Default value is (1 << 28). All bits except bit 28 are reserved in * DPA mode. If bit 28 is set, LED 0 reflects all ports' activity. diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 51292f269ce..e822ca0e97c 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2971,23 +2971,22 @@ static void * dev_seq_start(struct seq_file *s, loff_t *pos) { struct sg_proc_deviter * it = kmalloc(sizeof(*it), GFP_KERNEL); + s->private = it; if (! it) return NULL; + if (NULL == sg_dev_arr) - goto err1; + return NULL; it->index = *pos; it->max = sg_last_dev(); if (it->index >= it->max) - goto err1; + return NULL; return it; -err1: - kfree(it); - return NULL; } static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos) { - struct sg_proc_deviter * it = (struct sg_proc_deviter *) v; + struct sg_proc_deviter * it = s->private; *pos = ++it->index; return (it->index < it->max) ? it : NULL; @@ -2995,7 +2994,7 @@ static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos) static void dev_seq_stop(struct seq_file *s, void *v) { - kfree (v); + kfree(s->private); } static int sg_proc_open_dev(struct inode *inode, struct file *file) diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 07f05e9d095..0e21f583690 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -34,36 +34,6 @@ #undef SERIAL_DEBUG_PCI /* - * Definitions for PCI support. - */ -#define FL_BASE_MASK 0x0007 -#define FL_BASE0 0x0000 -#define FL_BASE1 0x0001 -#define FL_BASE2 0x0002 -#define FL_BASE3 0x0003 -#define FL_BASE4 0x0004 -#define FL_GET_BASE(x) (x & FL_BASE_MASK) - -/* Use successive BARs (PCI base address registers), - else use offset into some specified BAR */ -#define FL_BASE_BARS 0x0008 - -/* do not assign an irq */ -#define FL_NOIRQ 0x0080 - -/* Use the Base address register size to cap number of ports */ -#define FL_REGION_SZ_CAP 0x0100 - -struct pci_board { - unsigned int flags; - unsigned int num_ports; - unsigned int base_baud; - unsigned int uart_offset; - unsigned int reg_shift; - unsigned int first_offset; -}; - -/* * init function returns: * > 0 - number of ports * = 0 - use board->num_ports @@ -75,14 +45,15 @@ struct pci_serial_quirk { u32 subvendor; u32 subdevice; int (*init)(struct pci_dev *dev); - int (*setup)(struct pci_dev *dev, struct pci_board *board, - struct uart_port *port, int idx); + int (*setup)(struct serial_private *, struct pciserial_board *, + struct uart_port *, int); void (*exit)(struct pci_dev *dev); }; #define PCI_NUM_BAR_RESOURCES 6 struct serial_private { + struct pci_dev *dev; unsigned int nr; void __iomem *remapped_bar[PCI_NUM_BAR_RESOURCES]; struct pci_serial_quirk *quirk; @@ -101,17 +72,18 @@ static void moan_device(const char *str, struct pci_dev *dev) } static int -setup_port(struct pci_dev *dev, struct uart_port *port, +setup_port(struct serial_private *priv, struct uart_port *port, int bar, int offset, int regshift) { - struct serial_private *priv = pci_get_drvdata(dev); + struct pci_dev *dev = priv->dev; unsigned long base, len; if (bar >= PCI_NUM_BAR_RESOURCES) return -EINVAL; + base = pci_resource_start(dev, bar); + if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) { - base = pci_resource_start(dev, bar); len = pci_resource_len(dev, bar); if (!priv->remapped_bar[bar]) @@ -120,13 +92,16 @@ setup_port(struct pci_dev *dev, struct uart_port *port, return -ENOMEM; port->iotype = UPIO_MEM; + port->iobase = 0; port->mapbase = base + offset; port->membase = priv->remapped_bar[bar] + offset; port->regshift = regshift; } else { - base = pci_resource_start(dev, bar) + offset; port->iotype = UPIO_PORT; - port->iobase = base; + port->iobase = base + offset; + port->mapbase = 0; + port->membase = NULL; + port->regshift = 0; } return 0; } @@ -136,7 +111,7 @@ setup_port(struct pci_dev *dev, struct uart_port *port, * Not that ugly ;) -- HW */ static int -afavlab_setup(struct pci_dev *dev, struct pci_board *board, +afavlab_setup(struct serial_private *priv, struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar, offset = board->first_offset; @@ -149,7 +124,7 @@ afavlab_setup(struct pci_dev *dev, struct pci_board *board, offset += (idx - 4) * board->uart_offset; } - return setup_port(dev, port, bar, offset, board->reg_shift); + return setup_port(priv, port, bar, offset, board->reg_shift); } /* @@ -189,13 +164,13 @@ static int __devinit pci_hp_diva_init(struct pci_dev *dev) * some serial ports are supposed to be hidden on certain models. */ static int -pci_hp_diva_setup(struct pci_dev *dev, struct pci_board *board, +pci_hp_diva_setup(struct serial_private *priv, struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int offset = board->first_offset; unsigned int bar = FL_GET_BASE(board->flags); - switch (dev->subsystem_device) { + switch (priv->dev->subsystem_device) { case PCI_DEVICE_ID_HP_DIVA_MAESTRO: if (idx == 3) idx++; @@ -212,7 +187,7 @@ pci_hp_diva_setup(struct pci_dev *dev, struct pci_board *board, offset += idx * board->uart_offset; - return setup_port(dev, port, bar, offset, board->reg_shift); + return setup_port(priv, port, bar, offset, board->reg_shift); } /* @@ -307,7 +282,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev) /* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */ static int -sbs_setup(struct pci_dev *dev, struct pci_board *board, +sbs_setup(struct serial_private *priv, struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar, offset = board->first_offset; @@ -323,7 +298,7 @@ sbs_setup(struct pci_dev *dev, struct pci_board *board, } else /* we have only 8 ports on PMC-OCTALPRO */ return 1; - return setup_port(dev, port, bar, offset, board->reg_shift); + return setup_port(priv, port, bar, offset, board->reg_shift); } /* @@ -389,6 +364,9 @@ static void __devexit sbs_exit(struct pci_dev *dev) * - 10x cards have control registers in IO and/or memory space; * - 20x cards have control registers in standard PCI configuration space. * + * Note: all 10x cards have PCI device ids 0x10.. + * all 20x cards have PCI device ids 0x20.. + * * There are also Quartet Serial cards which use Oxford Semiconductor * 16954 quad UART PCI chip clocked by 18.432 MHz quartz. * @@ -445,24 +423,18 @@ static int pci_siig20x_init(struct pci_dev *dev) return 0; } -int pci_siig10x_fn(struct pci_dev *dev, int enable) +static int pci_siig_init(struct pci_dev *dev) { - int ret = 0; - if (enable) - ret = pci_siig10x_init(dev); - return ret; -} + unsigned int type = dev->device & 0xff00; -int pci_siig20x_fn(struct pci_dev *dev, int enable) -{ - int ret = 0; - if (enable) - ret = pci_siig20x_init(dev); - return ret; -} + if (type == 0x1000) + return pci_siig10x_init(dev); + else if (type == 0x2000) + return pci_siig20x_init(dev); -EXPORT_SYMBOL(pci_siig10x_fn); -EXPORT_SYMBOL(pci_siig20x_fn); + moan_device("Unknown SIIG card", dev); + return -ENODEV; +} /* * Timedia has an explosion of boards, and to avoid the PCI table from @@ -523,7 +495,7 @@ static int __devinit pci_timedia_init(struct pci_dev *dev) * Ugh, this is ugly as all hell --- TYT */ static int -pci_timedia_setup(struct pci_dev *dev, struct pci_board *board, +pci_timedia_setup(struct serial_private *priv, struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar = 0, offset = board->first_offset; @@ -549,14 +521,15 @@ pci_timedia_setup(struct pci_dev *dev, struct pci_board *board, bar = idx - 2; } - return setup_port(dev, port, bar, offset, board->reg_shift); + return setup_port(priv, port, bar, offset, board->reg_shift); } /* * Some Titan cards are also a little weird */ static int -titan_400l_800l_setup(struct pci_dev *dev, struct pci_board *board, +titan_400l_800l_setup(struct serial_private *priv, + struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar, offset = board->first_offset; @@ -573,7 +546,7 @@ titan_400l_800l_setup(struct pci_dev *dev, struct pci_board *board, offset = (idx - 2) * board->uart_offset; } - return setup_port(dev, port, bar, offset, board->reg_shift); + return setup_port(priv, port, bar, offset, board->reg_shift); } static int __devinit pci_xircom_init(struct pci_dev *dev) @@ -593,7 +566,7 @@ static int __devinit pci_netmos_init(struct pci_dev *dev) } static int -pci_default_setup(struct pci_dev *dev, struct pci_board *board, +pci_default_setup(struct serial_private *priv, struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar, offset = board->first_offset, maxnr; @@ -604,13 +577,13 @@ pci_default_setup(struct pci_dev *dev, struct pci_board *board, else offset += idx * board->uart_offset; - maxnr = (pci_resource_len(dev, bar) - board->first_offset) / + maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) / (8 << board->reg_shift); if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) return 1; - return setup_port(dev, port, bar, offset, board->reg_shift); + return setup_port(priv, port, bar, offset, board->reg_shift); } /* This should be in linux/pci_ids.h */ @@ -754,152 +727,15 @@ static struct pci_serial_quirk pci_serial_quirks[] = { .setup = sbs_setup, .exit = __devexit_p(sbs_exit), }, - /* * SIIG cards. - * It is not clear whether these could be collapsed. */ { .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_1S_10x_550, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig10x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_1S_10x_650, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig10x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_1S_10x_850, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig10x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_2S_10x_550, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig10x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_2S_10x_650, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig10x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_2S_10x_850, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig10x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_4S_10x_550, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig10x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_4S_10x_650, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig10x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_4S_10x_850, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig10x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_1S_20x_550, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig20x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_1S_20x_650, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig20x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_1S_20x_850, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig20x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_2S_20x_550, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig20x_init, - .setup = pci_default_setup, - }, - { .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_2S_20x_650, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig20x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_2S_20x_850, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig20x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_4S_20x_550, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig20x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_4S_20x_650, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .init = pci_siig20x_init, - .setup = pci_default_setup, - }, - { - .vendor = PCI_VENDOR_ID_SIIG, - .device = PCI_DEVICE_ID_SIIG_4S_20x_850, + .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .init = pci_siig20x_init, + .init = pci_siig_init, .setup = pci_default_setup, }, /* @@ -990,7 +826,7 @@ static struct pci_serial_quirk *find_quirk(struct pci_dev *dev) } static _INLINE_ int -get_pci_irq(struct pci_dev *dev, struct pci_board *board, int idx) +get_pci_irq(struct pci_dev *dev, struct pciserial_board *board) { if (board->flags & FL_NOIRQ) return 0; @@ -1115,7 +951,7 @@ enum pci_board_num_t { * see first lines of serial_in() and serial_out() in 8250.c */ -static struct pci_board pci_boards[] __devinitdata = { +static struct pciserial_board pci_boards[] __devinitdata = { [pbn_default] = { .flags = FL_BASE0, .num_ports = 1, @@ -1575,7 +1411,7 @@ static struct pci_board pci_boards[] __devinitdata = { * serial specs. Returns 0 on success, 1 on failure. */ static int __devinit -serial_pci_guess_board(struct pci_dev *dev, struct pci_board *board) +serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) { int num_iomem, num_port, first_port = -1, i; @@ -1640,7 +1476,8 @@ serial_pci_guess_board(struct pci_dev *dev, struct pci_board *board) } static inline int -serial_pci_matches(struct pci_board *board, struct pci_board *guessed) +serial_pci_matches(struct pciserial_board *board, + struct pciserial_board *guessed) { return board->num_ports == guessed->num_ports && @@ -1650,58 +1487,14 @@ serial_pci_matches(struct pci_board *board, struct pci_board *guessed) board->first_offset == guessed->first_offset; } -/* - * Probe one serial board. Unfortunately, there is no rhyme nor reason - * to the arrangement of serial ports on a PCI card. - */ -static int __devinit -pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) +struct serial_private * +pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board) { + struct uart_port serial_port; struct serial_private *priv; - struct pci_board *board, tmp; struct pci_serial_quirk *quirk; int rc, nr_ports, i; - if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { - printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n", - ent->driver_data); - return -EINVAL; - } - - board = &pci_boards[ent->driver_data]; - - rc = pci_enable_device(dev); - if (rc) - return rc; - - if (ent->driver_data == pbn_default) { - /* - * Use a copy of the pci_board entry for this; - * avoid changing entries in the table. - */ - memcpy(&tmp, board, sizeof(struct pci_board)); - board = &tmp; - - /* - * We matched one of our class entries. Try to - * determine the parameters of this board. - */ - rc = serial_pci_guess_board(dev, board); - if (rc) - goto disable; - } else { - /* - * We matched an explicit entry. If we are able to - * detect this boards settings with our heuristic, - * then we no longer need this entry. - */ - memcpy(&tmp, &pci_boards[pbn_default], sizeof(struct pci_board)); - rc = serial_pci_guess_board(dev, &tmp); - if (rc == 0 && serial_pci_matches(board, &tmp)) - moan_device("Redundant entry in serial pci_table.", - dev); - } - nr_ports = board->num_ports; /* @@ -1718,8 +1511,10 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) */ if (quirk->init) { rc = quirk->init(dev); - if (rc < 0) - goto disable; + if (rc < 0) { + priv = ERR_PTR(rc); + goto err_out; + } if (rc) nr_ports = rc; } @@ -1728,27 +1523,26 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) sizeof(unsigned int) * nr_ports, GFP_KERNEL); if (!priv) { - rc = -ENOMEM; - goto deinit; + priv = ERR_PTR(-ENOMEM); + goto err_deinit; } memset(priv, 0, sizeof(struct serial_private) + sizeof(unsigned int) * nr_ports); + priv->dev = dev; priv->quirk = quirk; - pci_set_drvdata(dev, priv); + + memset(&serial_port, 0, sizeof(struct uart_port)); + serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; + serial_port.uartclk = board->base_baud * 16; + serial_port.irq = get_pci_irq(dev, board); + serial_port.dev = &dev->dev; for (i = 0; i < nr_ports; i++) { - struct uart_port serial_port; - memset(&serial_port, 0, sizeof(struct uart_port)); - - serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | - UPF_SHARE_IRQ; - serial_port.uartclk = board->base_baud * 16; - serial_port.irq = get_pci_irq(dev, board, i); - serial_port.dev = &dev->dev; - if (quirk->setup(dev, board, &serial_port, i)) + if (quirk->setup(priv, board, &serial_port, i)) break; + #ifdef SERIAL_DEBUG_PCI printk("Setup PCI port: port %x, irq %d, type %d\n", serial_port.iobase, serial_port.irq, serial_port.iotype); @@ -1763,24 +1557,21 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) priv->nr = i; - return 0; + return priv; - deinit: + err_deinit: if (quirk->exit) quirk->exit(dev); - disable: - pci_disable_device(dev); - return rc; + err_out: + return priv; } +EXPORT_SYMBOL_GPL(pciserial_init_ports); -static void __devexit pciserial_remove_one(struct pci_dev *dev) +void pciserial_remove_ports(struct serial_private *priv) { - struct serial_private *priv = pci_get_drvdata(dev); struct pci_serial_quirk *quirk; int i; - pci_set_drvdata(dev, NULL); - for (i = 0; i < priv->nr; i++) serial8250_unregister_port(priv->line[i]); @@ -1793,25 +1584,123 @@ static void __devexit pciserial_remove_one(struct pci_dev *dev) /* * Find the exit quirks. */ - quirk = find_quirk(dev); + quirk = find_quirk(priv->dev); if (quirk->exit) - quirk->exit(dev); + quirk->exit(priv->dev); + + kfree(priv); +} +EXPORT_SYMBOL_GPL(pciserial_remove_ports); + +void pciserial_suspend_ports(struct serial_private *priv) +{ + int i; + + for (i = 0; i < priv->nr; i++) + if (priv->line[i] >= 0) + serial8250_suspend_port(priv->line[i]); +} +EXPORT_SYMBOL_GPL(pciserial_suspend_ports); + +void pciserial_resume_ports(struct serial_private *priv) +{ + int i; + + /* + * Ensure that the board is correctly configured. + */ + if (priv->quirk->init) + priv->quirk->init(priv->dev); + + for (i = 0; i < priv->nr; i++) + if (priv->line[i] >= 0) + serial8250_resume_port(priv->line[i]); +} +EXPORT_SYMBOL_GPL(pciserial_resume_ports); + +/* + * Probe one serial board. Unfortunately, there is no rhyme nor reason + * to the arrangement of serial ports on a PCI card. + */ +static int __devinit +pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) +{ + struct serial_private *priv; + struct pciserial_board *board, tmp; + int rc; + + if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { + printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n", + ent->driver_data); + return -EINVAL; + } + + board = &pci_boards[ent->driver_data]; + + rc = pci_enable_device(dev); + if (rc) + return rc; + + if (ent->driver_data == pbn_default) { + /* + * Use a copy of the pci_board entry for this; + * avoid changing entries in the table. + */ + memcpy(&tmp, board, sizeof(struct pciserial_board)); + board = &tmp; + + /* + * We matched one of our class entries. Try to + * determine the parameters of this board. + */ + rc = serial_pci_guess_board(dev, board); + if (rc) + goto disable; + } else { + /* + * We matched an explicit entry. If we are able to + * detect this boards settings with our heuristic, + * then we no longer need this entry. + */ + memcpy(&tmp, &pci_boards[pbn_default], + sizeof(struct pciserial_board)); + rc = serial_pci_guess_board(dev, &tmp); + if (rc == 0 && serial_pci_matches(board, &tmp)) + moan_device("Redundant entry in serial pci_table.", + dev); + } + priv = pciserial_init_ports(dev, board); + if (!IS_ERR(priv)) { + pci_set_drvdata(dev, priv); + return 0; + } + + rc = PTR_ERR(priv); + + disable: pci_disable_device(dev); + return rc; +} - kfree(priv); +static void __devexit pciserial_remove_one(struct pci_dev *dev) +{ + struct serial_private *priv = pci_get_drvdata(dev); + + pci_set_drvdata(dev, NULL); + + pciserial_remove_ports(priv); + + pci_disable_device(dev); } static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state) { struct serial_private *priv = pci_get_drvdata(dev); - if (priv) { - int i; + if (priv) + pciserial_suspend_ports(priv); - for (i = 0; i < priv->nr; i++) - serial8250_suspend_port(priv->line[i]); - } pci_save_state(dev); pci_set_power_state(dev, pci_choose_state(dev, state)); return 0; @@ -1825,21 +1714,12 @@ static int pciserial_resume_one(struct pci_dev *dev) pci_restore_state(dev); if (priv) { - int i; - /* * The device may have been disabled. Re-enable it. */ pci_enable_device(dev); - /* - * Ensure that the board is correctly configured. - */ - if (priv->quirk->init) - priv->quirk->init(dev); - - for (i = 0; i < priv->nr; i++) - serial8250_resume_port(priv->line[i]); + pciserial_resume_ports(priv); } return 0; } diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 97034d3937f..d5797618a3b 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -211,7 +211,7 @@ comment "Non-8250 serial port support" config SERIAL_AMBA_PL010 tristate "ARM AMBA PL010 serial port support" - depends on ARM_AMBA + depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE) select SERIAL_CORE help This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have @@ -819,7 +819,7 @@ config SERIAL_M32R_SIO_CONSOLE config SERIAL_M32R_PLDSIO bool "M32R SIO I/F on a PLD" - depends on SERIAL_M32R_SIO=y + depends on SERIAL_M32R_SIO=y && (PLAT_OPSPUT || PALT_USRV || PLAT_M32700UT) default n help Say Y here if you want to use the M32R serial controller diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c index 0301feacbde..9b50560b9d1 100644 --- a/drivers/serial/m32r_sio.c +++ b/drivers/serial/m32r_sio.c @@ -1123,7 +1123,7 @@ static int __init m32r_sio_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -extern struct uart_driver m32r_sio_reg; +static struct uart_driver m32r_sio_reg; static struct console m32r_sio_console = { .name = "ttyS", .write = m32r_sio_console_write, diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 576f3b852fc..4528a00c45b 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -1922,7 +1922,7 @@ static int genelink_rx_fixup (struct usbnet *dev, struct sk_buff *skb) // copy the packet data to the new skb memcpy(skb_put(gl_skb, size), packet->packet_data, size); - skb_return (dev, skb); + skb_return (dev, gl_skb); } // advance to the next packet diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index 29cd801eb95..e32a80b3918 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -346,8 +346,7 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs) if (datalen<14) goto resubmit; if ((seq & IEEE802_11_SCTL_FRAG) == 0) { - frag = kmalloc(sizeof(struct zd1201_frag*), - GFP_ATOMIC); + frag = kmalloc(sizeof(*frag), GFP_ATOMIC); if (!frag) goto resubmit; skb = dev_alloc_skb(IEEE802_11_DATA_LEN +14+2); diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index cbff98337aa..5fe182d6e4a 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -6,7 +6,7 @@ menu "Console display driver support" config VGA_CONSOLE bool "VGA text console" if EMBEDDED || !X86 - depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC32 && !SPARC64 && !M68K && !PARISC + depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC32 && !SPARC64 && !M68K && !PARISC && !ARCH_VERSATILE default y help Saying Y here will allow you to use Linux in text mode through a diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c index c46387024b1..a78b9bd8f89 100644 --- a/drivers/video/radeonfb.c +++ b/drivers/video/radeonfb.c @@ -80,7 +80,7 @@ #include <video/radeon.h> #include <linux/radeonfb.h> -#define DEBUG 1 +#define DEBUG 0 #if DEBUG #define RTRACE printk diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index bfc28abe1cb..31ee06590de 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -30,7 +30,7 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd); static int afs_mntpt_open(struct inode *inode, struct file *file); -static int afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd); +static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd); struct file_operations afs_mntpt_file_operations = { .open = afs_mntpt_open, @@ -233,7 +233,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) /* * follow a link from a mountpoint directory, thus causing it to be mounted */ -static int afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) { struct vfsmount *newmnt; struct dentry *old_dentry; @@ -249,7 +249,7 @@ static int afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) newmnt = afs_mntpt_do_automount(dentry); if (IS_ERR(newmnt)) { path_release(nd); - return PTR_ERR(newmnt); + return (void *)newmnt; } old_dentry = nd->dentry; @@ -267,7 +267,7 @@ static int afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) } kleave(" = %d", err); - return err; + return ERR_PTR(err); } /* end afs_mntpt_follow_link() */ /*****************************************************************************/ diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c index f028396f138..52e8772b066 100644 --- a/fs/autofs/symlink.c +++ b/fs/autofs/symlink.c @@ -12,11 +12,12 @@ #include "autofs_i.h" -static int autofs_follow_link(struct dentry *dentry, struct nameidata *nd) +/* Nothing to release.. */ +static void *autofs_follow_link(struct dentry *dentry, struct nameidata *nd) { char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data; nd_set_link(nd, s); - return 0; + return NULL; } struct inode_operations autofs_symlink_inode_operations = { diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c index c265a66edf0..2ea2c98fd84 100644 --- a/fs/autofs4/symlink.c +++ b/fs/autofs4/symlink.c @@ -12,11 +12,11 @@ #include "autofs_i.h" -static int autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) { struct autofs_info *ino = autofs4_dentry_ino(dentry); nd_set_link(nd, (char *)ino->u.symlink); - return 0; + return NULL; } struct inode_operations autofs4_symlink_inode_operations = { diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index de5bb280a82..e0a6025f1d0 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -41,8 +41,8 @@ static struct inode *befs_alloc_inode(struct super_block *sb); static void befs_destroy_inode(struct inode *inode); static int befs_init_inodecache(void); static void befs_destroy_inodecache(void); -static int befs_follow_link(struct dentry *, struct nameidata *); -static void befs_put_link(struct dentry *, struct nameidata *); +static void *befs_follow_link(struct dentry *, struct nameidata *); +static void befs_put_link(struct dentry *, struct nameidata *, void *); static int befs_utf2nls(struct super_block *sb, const char *in, int in_len, char **out, int *out_len); static int befs_nls2utf(struct super_block *sb, const char *in, int in_len, @@ -461,7 +461,7 @@ befs_destroy_inodecache(void) * The data stream become link name. Unless the LONG_SYMLINK * flag is set. */ -static int +static void * befs_follow_link(struct dentry *dentry, struct nameidata *nd) { befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); @@ -487,10 +487,10 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd) } nd_set_link(nd, link); - return 0; + return NULL; } -static void befs_put_link(struct dentry *dentry, struct nameidata *nd) +static void befs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) { befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 78af5850c55..1fd21f66f24 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -83,8 +83,8 @@ extern int cifs_dir_notify(struct file *, unsigned long arg); extern struct dentry_operations cifs_dentry_ops; /* Functions related to symlinks */ -extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd); -extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd); +extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); +extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *); extern int cifs_readlink(struct dentry *direntry, char __user *buffer, int buflen); extern int cifs_symlink(struct inode *inode, struct dentry *direntry, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 30ab70ce554..3497125189d 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -643,7 +643,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) netfid, length, pfLock->fl_start, numUnlock, numLock, lockType, wait_flag); - if (rc == 0 && (pfLock->fl_flags & FL_POSIX)) + if (pfLock->fl_flags & FL_POSIX) posix_lock_file_wait(file, pfLock); FreeXid(xid); return rc; diff --git a/fs/cifs/link.c b/fs/cifs/link.c index bde0fabfece..ab925ef4f86 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -92,7 +92,7 @@ cifs_hl_exit: return rc; } -int +void * cifs_follow_link(struct dentry *direntry, struct nameidata *nd) { struct inode *inode = direntry->d_inode; @@ -148,7 +148,7 @@ out: out_no_free: FreeXid(xid); nd_set_link(nd, target_path); - return 0; + return NULL; /* No cookie */ } int @@ -330,7 +330,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) return rc; } -void cifs_put_link(struct dentry *direntry, struct nameidata *nd) +void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie) { char *p = nd_get_link(nd); if (!IS_ERR(p)) diff --git a/fs/devfs/base.c b/fs/devfs/base.c index 1ecfe1f184d..8b679b67e5e 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -2491,11 +2491,11 @@ static int devfs_mknod(struct inode *dir, struct dentry *dentry, int mode, return 0; } /* End Function devfs_mknod */ -static int devfs_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *devfs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct devfs_entry *p = get_devfs_entry_from_vfs_inode(dentry->d_inode); nd_set_link(nd, p ? p->u.symlink.linkname : ERR_PTR(-ENODEV)); - return 0; + return NULL; } /* End Function devfs_follow_link */ static struct inode_operations devfs_iops = { diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c index 9f7bac01d55..1e67d87cfa9 100644 --- a/fs/ext2/symlink.c +++ b/fs/ext2/symlink.c @@ -21,11 +21,11 @@ #include "xattr.h" #include <linux/namei.h> -static int ext2_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *ext2_follow_link(struct dentry *dentry, struct nameidata *nd) { struct ext2_inode_info *ei = EXT2_I(dentry->d_inode); nd_set_link(nd, (char *)ei->i_data); - return 0; + return NULL; } struct inode_operations ext2_symlink_inode_operations = { diff --git a/fs/ext3/symlink.c b/fs/ext3/symlink.c index 8c3e72818fb..4f79122cde6 100644 --- a/fs/ext3/symlink.c +++ b/fs/ext3/symlink.c @@ -23,11 +23,11 @@ #include <linux/namei.h> #include "xattr.h" -static int ext3_follow_link(struct dentry *dentry, struct nameidata *nd) +static void * ext3_follow_link(struct dentry *dentry, struct nameidata *nd) { struct ext3_inode_info *ei = EXT3_I(dentry->d_inode); nd_set_link(nd, (char*)ei->i_data); - return 0; + return NULL; } struct inode_operations ext3_symlink_inode_operations = { diff --git a/fs/freevxfs/vxfs_immed.c b/fs/freevxfs/vxfs_immed.c index ac677ab262b..d0401dc68d4 100644 --- a/fs/freevxfs/vxfs_immed.c +++ b/fs/freevxfs/vxfs_immed.c @@ -38,7 +38,7 @@ #include "vxfs_inode.h" -static int vxfs_immed_follow_link(struct dentry *, struct nameidata *); +static void * vxfs_immed_follow_link(struct dentry *, struct nameidata *); static int vxfs_immed_readpage(struct file *, struct page *); @@ -72,12 +72,12 @@ struct address_space_operations vxfs_immed_aops = { * Returns: * Zero on success, else a negative error code. */ -static int +static void * vxfs_immed_follow_link(struct dentry *dp, struct nameidata *np) { struct vxfs_inode_info *vip = VXFS_INO(dp->d_inode); nd_set_link(np, vip->vii_immed.vi_immed); - return 0; + return NULL; } /** diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c index ff150fedb98..52930915bad 100644 --- a/fs/hppfs/hppfs_kern.c +++ b/fs/hppfs/hppfs_kern.c @@ -38,7 +38,7 @@ struct hppfs_inode_info { static inline struct hppfs_inode_info *HPPFS_I(struct inode *inode) { - return(list_entry(inode, struct hppfs_inode_info, vfs_inode)); + return container_of(inode, struct hppfs_inode_info, vfs_inode); } #define HPPFS_SUPER_MAGIC 0xb00000ee @@ -662,42 +662,36 @@ static int hppfs_readlink(struct dentry *dentry, char *buffer, int buflen) { struct file *proc_file; struct dentry *proc_dentry; - int (*readlink)(struct dentry *, char *, int); - int err, n; + int ret; proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; proc_file = dentry_open(dget(proc_dentry), NULL, O_RDONLY); - err = PTR_ERR(proc_dentry); - if(IS_ERR(proc_dentry)) - return(err); + if (IS_ERR(proc_file)) + return PTR_ERR(proc_file); - readlink = proc_dentry->d_inode->i_op->readlink; - n = (*readlink)(proc_dentry, buffer, buflen); + ret = proc_dentry->d_inode->i_op->readlink(proc_dentry, buffer, buflen); fput(proc_file); - return(n); + return ret; } -static int hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) +static void* hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct file *proc_file; struct dentry *proc_dentry; - int (*follow_link)(struct dentry *, struct nameidata *); - int err, n; + void *ret; proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry; proc_file = dentry_open(dget(proc_dentry), NULL, O_RDONLY); - err = PTR_ERR(proc_dentry); - if(IS_ERR(proc_dentry)) - return(err); + if (IS_ERR(proc_file)) + return proc_file; - follow_link = proc_dentry->d_inode->i_op->follow_link; - n = (*follow_link)(proc_dentry, nd); + ret = proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd); fput(proc_file); - return(n); + return ret; } static struct inode_operations hppfs_dir_iops = { diff --git a/fs/inotify.c b/fs/inotify.c index 868901b1e77..2e4e2a57708 100644 --- a/fs/inotify.c +++ b/fs/inotify.c @@ -353,7 +353,7 @@ static int inotify_dev_get_wd(struct inotify_device *dev, do { if (unlikely(!idr_pre_get(&dev->idr, GFP_KERNEL))) return -ENOSPC; - ret = idr_get_new_above(&dev->idr, watch, dev->last_wd, &watch->wd); + ret = idr_get_new_above(&dev->idr, watch, dev->last_wd+1, &watch->wd); } while (ret == -EAGAIN); return ret; diff --git a/fs/ioprio.c b/fs/ioprio.c index 97e1f088ba0..d1c1f2b2c9d 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -62,6 +62,8 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio) break; case IOPRIO_CLASS_IDLE: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; break; default: return -EINVAL; diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index 65ab6b001dc..82ef484f5e1 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c @@ -18,7 +18,7 @@ #include <linux/namei.h> #include "nodelist.h" -static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); +static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); struct inode_operations jffs2_symlink_inode_operations = { @@ -27,9 +27,10 @@ struct inode_operations jffs2_symlink_inode_operations = .setattr = jffs2_setattr }; -static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); + char *p = (char *)f->dents; /* * We don't acquire the f->sem mutex here since the only data we @@ -45,19 +46,20 @@ static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) * nd_set_link() call. */ - if (!f->dents) { + if (!p) { printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n"); - return -EIO; + p = ERR_PTR(-EIO); + } else { + D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents)); } - D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents)); - nd_set_link(nd, (char *)f->dents); + nd_set_link(nd, p); /* * We unlock the f->sem mutex but VFS will use the f->dents string. This is safe * since the only way that may cause f->dents to be changed is iput() operation. * But VFS will not use f->dents after iput() has been called. */ - return 0; + return NULL; } diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c index 287d8d6c3cf..16477b3835e 100644 --- a/fs/jfs/symlink.c +++ b/fs/jfs/symlink.c @@ -22,11 +22,11 @@ #include "jfs_inode.h" #include "jfs_xattr.h" -static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *jfs_follow_link(struct dentry *dentry, struct nameidata *nd) { char *s = JFS_IP(dentry->d_inode)->i_inline; nd_set_link(nd, s); - return 0; + return NULL; } struct inode_operations jfs_symlink_inode_operations = { diff --git a/fs/namei.c b/fs/namei.c index b85f158aef0..6ec1f0fefc5 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -501,6 +501,7 @@ struct path { static inline int __do_follow_link(struct path *path, struct nameidata *nd) { int error; + void *cookie; struct dentry *dentry = path->dentry; touch_atime(path->mnt, dentry); @@ -508,13 +509,15 @@ static inline int __do_follow_link(struct path *path, struct nameidata *nd) if (path->mnt == nd->mnt) mntget(path->mnt); - error = dentry->d_inode->i_op->follow_link(dentry, nd); - if (!error) { + cookie = dentry->d_inode->i_op->follow_link(dentry, nd); + error = PTR_ERR(cookie); + if (!IS_ERR(cookie)) { char *s = nd_get_link(nd); + error = 0; if (s) error = __vfs_follow_link(nd, s); if (dentry->d_inode->i_op->put_link) - dentry->d_inode->i_op->put_link(dentry, nd); + dentry->d_inode->i_op->put_link(dentry, nd, cookie); } dput(dentry); mntput(path->mnt); @@ -2344,15 +2347,17 @@ out: int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) { struct nameidata nd; - int res; + void *cookie; + nd.depth = 0; - res = dentry->d_inode->i_op->follow_link(dentry, &nd); - if (!res) { - res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd)); + cookie = dentry->d_inode->i_op->follow_link(dentry, &nd); + if (!IS_ERR(cookie)) { + int res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd)); if (dentry->d_inode->i_op->put_link) - dentry->d_inode->i_op->put_link(dentry, &nd); + dentry->d_inode->i_op->put_link(dentry, &nd, cookie); + cookie = ERR_PTR(res); } - return res; + return PTR_ERR(cookie); } int vfs_follow_link(struct nameidata *nd, const char *link) @@ -2395,23 +2400,20 @@ int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) return res; } -int page_follow_link_light(struct dentry *dentry, struct nameidata *nd) +void *page_follow_link_light(struct dentry *dentry, struct nameidata *nd) { - struct page *page; + struct page *page = NULL; nd_set_link(nd, page_getlink(dentry, &page)); - return 0; + return page; } -void page_put_link(struct dentry *dentry, struct nameidata *nd) +void page_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) { - if (!IS_ERR(nd_get_link(nd))) { - struct page *page; - page = find_get_page(dentry->d_inode->i_mapping, 0); - if (!page) - BUG(); + struct page *page = cookie; + + if (page) { kunmap(page); page_cache_release(page); - page_cache_release(page); } } diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index b38a57e78a6..2df639f143e 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -182,14 +182,16 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) /* We requested READDIRPLUS, but the server doesn't grok it */ if (error == -ENOTSUPP && desc->plus) { NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS; - NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS; + clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode)); desc->plus = 0; goto again; } goto error; } SetPageUptodate(page); - NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME; + spin_unlock(&inode->i_lock); /* Ensure consistent page alignment of the data. * Note: assumes we have exclusive access to this mapping either * through inode->i_sem or some other mechanism. @@ -462,7 +464,9 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, page, NFS_SERVER(inode)->dtsize, desc->plus); - NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME; + spin_unlock(&inode->i_lock); desc->page = page; desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ if (desc->error >= 0) { @@ -545,7 +549,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) break; } if (res == -ETOOSMALL && desc->plus) { - NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS; + clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode)); nfs_zap_caches(inode); desc->plus = 0; desc->entry->eof = 0; @@ -608,7 +612,7 @@ static inline int nfs_check_verifier(struct inode *dir, struct dentry *dentry) { if (IS_ROOT(dentry)) return 1; - if ((NFS_FLAGS(dir) & NFS_INO_INVALID_ATTR) != 0 + if ((NFS_I(dir)->cache_validity & NFS_INO_INVALID_ATTR) != 0 || nfs_attribute_timeout(dir)) return 0; return nfs_verify_change_attribute(dir, (unsigned long)dentry->d_fsdata); @@ -935,6 +939,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry error = nfs_revalidate_inode(NFS_SERVER(dir), dir); if (error < 0) { res = ERR_PTR(error); + unlock_kernel(); goto out; } @@ -1575,11 +1580,12 @@ out: int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) { - struct nfs_access_entry *cache = &NFS_I(inode)->cache_access; + struct nfs_inode *nfsi = NFS_I(inode); + struct nfs_access_entry *cache = &nfsi->cache_access; if (cache->cred != cred || time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)) - || (NFS_FLAGS(inode) & NFS_INO_INVALID_ACCESS)) + || (nfsi->cache_validity & NFS_INO_INVALID_ACCESS)) return -ENOENT; memcpy(res, cache, sizeof(*res)); return 0; @@ -1587,14 +1593,18 @@ int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) { - struct nfs_access_entry *cache = &NFS_I(inode)->cache_access; + struct nfs_inode *nfsi = NFS_I(inode); + struct nfs_access_entry *cache = &nfsi->cache_access; if (cache->cred != set->cred) { if (cache->cred) put_rpccred(cache->cred); cache->cred = get_rpccred(set->cred); } - NFS_FLAGS(inode) &= ~NFS_INO_INVALID_ACCESS; + /* FIXME: replace current access_cache BKL reliance with inode->i_lock */ + spin_lock(&inode->i_lock); + nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; + spin_unlock(&inode->i_lock); cache->jiffies = set->jiffies; cache->mask = set->mask; } diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 5621ba9885f..f6b9eda925c 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -134,9 +134,10 @@ nfs_file_release(struct inode *inode, struct file *filp) */ static int nfs_revalidate_file(struct inode *inode, struct file *filp) { + struct nfs_inode *nfsi = NFS_I(inode); int retval = 0; - if ((NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) || nfs_attribute_timeout(inode)) + if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) || nfs_attribute_timeout(inode)) retval = __nfs_revalidate_inode(NFS_SERVER(inode), inode); nfs_revalidate_mapping(inode, filp->f_mapping); return 0; @@ -164,7 +165,7 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) goto force_reval; if (nfsi->npages != 0) return 0; - if (!(NFS_FLAGS(inode) & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode)) + if (!(nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode)) return 0; force_reval: return __nfs_revalidate_inode(server, inode); diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index bb7ca022bcb..541b418327c 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -615,14 +615,18 @@ nfs_zap_caches(struct inode *inode) struct nfs_inode *nfsi = NFS_I(inode); int mode = inode->i_mode; + spin_lock(&inode->i_lock); + NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO_UPDATE(inode) = jiffies; memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) - nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; + nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; else - nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; + nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; + + spin_unlock(&inode->i_lock); } static void nfs_zap_acl_cache(struct inode *inode) @@ -632,7 +636,9 @@ static void nfs_zap_acl_cache(struct inode *inode) clear_acl_cache = NFS_PROTO(inode)->clear_acl_cache; if (clear_acl_cache != NULL) clear_acl_cache(inode); - NFS_I(inode)->flags &= ~NFS_INO_INVALID_ACL; + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_ACL; + spin_unlock(&inode->i_lock); } /* @@ -739,7 +745,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) inode->i_fop = &nfs_dir_operations; if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS) && fattr->size <= NFS_LIMIT_READDIRPLUS) - NFS_FLAGS(inode) |= NFS_INO_ADVISE_RDPLUS; + set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode)); } else if (S_ISLNK(inode->i_mode)) inode->i_op = &nfs_symlink_inode_operations; else @@ -841,7 +847,9 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr) inode->i_uid = attr->ia_uid; if ((attr->ia_valid & ATTR_GID) != 0) inode->i_gid = attr->ia_gid; - NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; + spin_unlock(&inode->i_lock); } if ((attr->ia_valid & ATTR_SIZE) != 0) { inode->i_size = attr->ia_size; @@ -849,31 +857,47 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr) } } +static int nfs_wait_schedule(void *word) +{ + if (signal_pending(current)) + return -ERESTARTSYS; + schedule(); + return 0; +} + /* * Wait for the inode to get unlocked. - * (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING). */ -static int -nfs_wait_on_inode(struct inode *inode, int flag) +static int nfs_wait_on_inode(struct inode *inode) { struct rpc_clnt *clnt = NFS_CLIENT(inode); struct nfs_inode *nfsi = NFS_I(inode); - + sigset_t oldmask; int error; - if (!(NFS_FLAGS(inode) & flag)) - return 0; + atomic_inc(&inode->i_count); - error = nfs_wait_event(clnt, nfsi->nfs_i_wait, - !(NFS_FLAGS(inode) & flag)); + rpc_clnt_sigmask(clnt, &oldmask); + error = wait_on_bit_lock(&nfsi->flags, NFS_INO_REVALIDATING, + nfs_wait_schedule, TASK_INTERRUPTIBLE); + rpc_clnt_sigunmask(clnt, &oldmask); iput(inode); + return error; } +static void nfs_wake_up_inode(struct inode *inode) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + clear_bit(NFS_INO_REVALIDATING, &nfsi->flags); + smp_mb__after_clear_bit(); + wake_up_bit(&nfsi->flags, NFS_INO_REVALIDATING); +} + int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct inode *inode = dentry->d_inode; - struct nfs_inode *nfsi = NFS_I(inode); - int need_atime = nfsi->flags & NFS_INO_INVALID_ATIME; + int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; int err; if (__IS_FLG(inode, MS_NOATIME)) @@ -1019,7 +1043,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) struct nfs_fattr fattr; struct nfs_inode *nfsi = NFS_I(inode); unsigned long verifier; - unsigned int flags; + unsigned long cache_validity; dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); @@ -1030,18 +1054,19 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) if (NFS_STALE(inode)) goto out_nowait; - while (NFS_REVALIDATING(inode)) { - status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING); - if (status < 0) - goto out_nowait; - if (NFS_ATTRTIMEO(inode) == 0) - continue; - if (NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME)) - continue; - status = NFS_STALE(inode) ? -ESTALE : 0; - goto out_nowait; + status = nfs_wait_on_inode(inode); + if (status < 0) + goto out; + if (NFS_STALE(inode)) { + status = -ESTALE; + /* Do we trust the cached ESTALE? */ + if (NFS_ATTRTIMEO(inode) != 0) { + if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME)) { + /* no */ + } else + goto out; + } } - NFS_FLAGS(inode) |= NFS_INO_REVALIDATING; /* Protect against RPC races by saving the change attribute */ verifier = nfs_save_change_attribute(inode); @@ -1053,7 +1078,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) if (status == -ESTALE) { nfs_zap_caches(inode); if (!S_ISDIR(inode->i_mode)) - NFS_FLAGS(inode) |= NFS_INO_STALE; + set_bit(NFS_INO_STALE, &NFS_FLAGS(inode)); } goto out; } @@ -1065,25 +1090,30 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) (long long)NFS_FILEID(inode), status); goto out; } - flags = nfsi->flags; - nfsi->flags &= ~NFS_INO_REVAL_PAGECACHE; + spin_lock(&inode->i_lock); + cache_validity = nfsi->cache_validity; + nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE; + /* * We may need to keep the attributes marked as invalid if * we raced with nfs_end_attr_update(). */ if (verifier == nfsi->cache_change_attribute) - nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); - /* Do the page cache invalidation */ + nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); + spin_unlock(&inode->i_lock); + nfs_revalidate_mapping(inode, inode->i_mapping); - if (flags & NFS_INO_INVALID_ACL) + + if (cache_validity & NFS_INO_INVALID_ACL) nfs_zap_acl_cache(inode); + dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); -out: - NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING; - wake_up(&nfsi->nfs_i_wait); + out: + nfs_wake_up_inode(inode); + out_nowait: unlock_kernel(); return status; @@ -1107,7 +1137,7 @@ int nfs_attribute_timeout(struct inode *inode) */ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) { - if (!(NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) + if (!(NFS_I(inode)->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) && !nfs_attribute_timeout(inode)) return NFS_STALE(inode) ? -ESTALE : 0; return __nfs_revalidate_inode(server, inode); @@ -1122,19 +1152,23 @@ void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) { struct nfs_inode *nfsi = NFS_I(inode); - if (nfsi->flags & NFS_INO_INVALID_DATA) { + if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { if (S_ISREG(inode->i_mode)) { if (filemap_fdatawrite(mapping) == 0) filemap_fdatawait(mapping); nfs_wb_all(inode); } invalidate_inode_pages2(mapping); - nfsi->flags &= ~NFS_INO_INVALID_DATA; + + spin_lock(&inode->i_lock); + nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; if (S_ISDIR(inode->i_mode)) { memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); /* This ensures we revalidate child dentries */ nfsi->cache_change_attribute++; } + spin_unlock(&inode->i_lock); + dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); @@ -1164,10 +1198,12 @@ void nfs_end_data_update(struct inode *inode) if (!nfs_have_delegation(inode, FMODE_READ)) { /* Mark the attribute cache for revalidation */ - nfsi->flags |= NFS_INO_INVALID_ATTR; + spin_lock(&inode->i_lock); + nfsi->cache_validity |= NFS_INO_INVALID_ATTR; /* Directories and symlinks: invalidate page cache too */ if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) - nfsi->flags |= NFS_INO_INVALID_DATA; + nfsi->cache_validity |= NFS_INO_INVALID_DATA; + spin_unlock(&inode->i_lock); } nfsi->cache_change_attribute ++; atomic_dec(&nfsi->data_updates); @@ -1192,6 +1228,8 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) if (nfs_have_delegation(inode, FMODE_READ)) return 0; + spin_lock(&inode->i_lock); + /* Are we in the process of updating data on the server? */ data_unstable = nfs_caches_unstable(inode); @@ -1200,19 +1238,23 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) && nfsi->change_attr == fattr->pre_change_attr) nfsi->change_attr = fattr->change_attr; if (nfsi->change_attr != fattr->change_attr) { - nfsi->flags |= NFS_INO_INVALID_ATTR; + nfsi->cache_validity |= NFS_INO_INVALID_ATTR; if (!data_unstable) - nfsi->flags |= NFS_INO_REVAL_PAGECACHE; + nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; } } - if ((fattr->valid & NFS_ATTR_FATTR) == 0) + if ((fattr->valid & NFS_ATTR_FATTR) == 0) { + spin_unlock(&inode->i_lock); return 0; + } /* Has the inode gone and changed behind our back? */ if (nfsi->fileid != fattr->fileid - || (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) + || (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) { + spin_unlock(&inode->i_lock); return -EIO; + } cur_size = i_size_read(inode); new_isize = nfs_size_to_loff_t(fattr->size); @@ -1227,30 +1269,31 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) /* Verify a few of the more important attributes */ if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { - nfsi->flags |= NFS_INO_INVALID_ATTR; + nfsi->cache_validity |= NFS_INO_INVALID_ATTR; if (!data_unstable) - nfsi->flags |= NFS_INO_REVAL_PAGECACHE; + nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; } if (cur_size != new_isize) { - nfsi->flags |= NFS_INO_INVALID_ATTR; + nfsi->cache_validity |= NFS_INO_INVALID_ATTR; if (nfsi->npages == 0) - nfsi->flags |= NFS_INO_REVAL_PAGECACHE; + nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE; } /* Have any file permissions changed? */ if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || inode->i_uid != fattr->uid || inode->i_gid != fattr->gid) - nfsi->flags |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; + nfsi->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; /* Has the link count changed? */ if (inode->i_nlink != fattr->nlink) - nfsi->flags |= NFS_INO_INVALID_ATTR; + nfsi->cache_validity |= NFS_INO_INVALID_ATTR; if (!timespec_equal(&inode->i_atime, &fattr->atime)) - nfsi->flags |= NFS_INO_INVALID_ATIME; + nfsi->cache_validity |= NFS_INO_INVALID_ATIME; nfsi->read_cache_jiffies = fattr->timestamp; + spin_unlock(&inode->i_lock); return 0; } @@ -1289,11 +1332,15 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign goto out_err; } + spin_lock(&inode->i_lock); + /* * Make sure the inode's type hasn't changed. */ - if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) + if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) { + spin_unlock(&inode->i_lock); goto out_changed; + } /* * Update the read time so we don't revalidate too often. @@ -1384,8 +1431,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign || S_ISLNK(inode->i_mode))) invalid &= ~NFS_INO_INVALID_DATA; if (!nfs_have_delegation(inode, FMODE_READ)) - nfsi->flags |= invalid; + nfsi->cache_validity |= invalid; + spin_unlock(&inode->i_lock); return 0; out_changed: /* @@ -1402,7 +1450,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign */ nfs_invalidate_inode(inode); out_err: - NFS_FLAGS(inode) |= NFS_INO_STALE; + set_bit(NFS_INO_STALE, &NFS_FLAGS(inode)); return -ESTALE; } @@ -1961,7 +2009,8 @@ static struct inode *nfs_alloc_inode(struct super_block *sb) nfsi = (struct nfs_inode *)kmem_cache_alloc(nfs_inode_cachep, SLAB_KERNEL); if (!nfsi) return NULL; - nfsi->flags = 0; + nfsi->flags = 0UL; + nfsi->cache_validity = 0UL; #ifdef CONFIG_NFS_V3_ACL nfsi->acl_access = ERR_PTR(-EAGAIN); nfsi->acl_default = ERR_PTR(-EAGAIN); @@ -1993,7 +2042,6 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) nfsi->ndirty = 0; nfsi->ncommit = 0; nfsi->npages = 0; - init_waitqueue_head(&nfsi->nfs_i_wait); nfs4_init_once(nfsi); } } diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 1b7a3ef2f81..6a5bbc0ae94 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -308,7 +308,9 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, nfs_begin_data_update(inode); status = rpc_call(server->client_acl, ACLPROC3_SETACL, &args, &fattr, 0); - NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS; + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS; + spin_unlock(&inode->i_lock); nfs_end_data_update(inode); dprintk("NFS reply setacl: %d\n", status); diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 6f866b8aa2d..6ceb1d471f2 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -140,7 +140,9 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, if (rdata->res.eof != 0 || result == 0) break; } while (count); - NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME; + spin_unlock(&inode->i_lock); if (count) memclear_highpage_flush(page, rdata->args.pgbase, count); @@ -473,7 +475,9 @@ void nfs_readpage_result(struct rpc_task *task) } task->tk_status = -EIO; } - NFS_FLAGS(data->inode) |= NFS_INO_INVALID_ATIME; + spin_lock(&data->inode->i_lock); + NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME; + spin_unlock(&data->inode->i_lock); data->complete(data, status); } diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 35f10659914..18dc95b0b64 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c @@ -27,26 +27,14 @@ /* Symlink caching in the page cache is even more simplistic * and straight-forward than readdir caching. - * - * At the beginning of the page we store pointer to struct page in question, - * simplifying nfs_put_link() (if inode got invalidated we can't find the page - * to be freed via pagecache lookup). - * The NUL-terminated string follows immediately thereafter. */ -struct nfs_symlink { - struct page *page; - char body[0]; -}; - static int nfs_symlink_filler(struct inode *inode, struct page *page) { - const unsigned int pgbase = offsetof(struct nfs_symlink, body); - const unsigned int pglen = PAGE_SIZE - pgbase; int error; lock_kernel(); - error = NFS_PROTO(inode)->readlink(inode, page, pgbase, pglen); + error = NFS_PROTO(inode)->readlink(inode, page, 0, PAGE_SIZE); unlock_kernel(); if (error < 0) goto error; @@ -60,11 +48,10 @@ error: return -EIO; } -static int nfs_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; struct page *page; - struct nfs_symlink *p; void *err = ERR_PTR(nfs_revalidate_inode(NFS_SERVER(inode), inode)); if (err) goto read_failed; @@ -78,28 +65,20 @@ static int nfs_follow_link(struct dentry *dentry, struct nameidata *nd) err = ERR_PTR(-EIO); goto getlink_read_error; } - p = kmap(page); - p->page = page; - nd_set_link(nd, p->body); - return 0; + nd_set_link(nd, kmap(page)); + return page; getlink_read_error: page_cache_release(page); read_failed: nd_set_link(nd, err); - return 0; + return NULL; } -static void nfs_put_link(struct dentry *dentry, struct nameidata *nd) +static void nfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) { - char *s = nd_get_link(nd); - if (!IS_ERR(s)) { - struct nfs_symlink *p; - struct page *page; - - p = container_of(s, struct nfs_symlink, body[0]); - page = p->page; - + if (cookie) { + struct page *page = cookie; kunmap(page); page_cache_release(page); } diff --git a/fs/proc/base.c b/fs/proc/base.c index ace151fa487..491f2d9f89a 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -890,7 +890,7 @@ static struct file_operations proc_seccomp_operations = { }; #endif /* CONFIG_SECCOMP */ -static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; int error = -EACCES; @@ -907,7 +907,7 @@ static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt); nd->last_type = LAST_BIND; out: - return error; + return ERR_PTR(error); } static int do_proc_readlink(struct dentry *dentry, struct vfsmount *mnt, @@ -1692,11 +1692,11 @@ static int proc_self_readlink(struct dentry *dentry, char __user *buffer, return vfs_readlink(dentry,buffer,buflen,tmp); } -static int proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) { char tmp[30]; sprintf(tmp, "%d", current->tgid); - return vfs_follow_link(nd,tmp); + return ERR_PTR(vfs_follow_link(nd,tmp)); } static struct inode_operations proc_self_inode_operations = { diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 6c6315d0402..abe8920313f 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -329,10 +329,10 @@ static void release_inode_number(unsigned int inum) spin_unlock(&proc_inum_lock); } -static int proc_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd) { nd_set_link(nd, PDE(dentry->d_inode)->data); - return 0; + return NULL; } static struct inode_operations proc_link_inode_operations = { diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index d9f614a5773..ff291c973a5 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1985,7 +1985,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, * iput doesn't deadlock in reiserfs_delete_xattrs. The locking * code really needs to be reworked, but this will take care of it * for now. -jeffm */ - if (REISERFS_I(dir)->i_acl_default) { + if (REISERFS_I(dir)->i_acl_default && !IS_ERR(REISERFS_I(dir)->i_acl_default)) { reiserfs_write_unlock_xattrs(dir->i_sb); iput(inode); reiserfs_write_lock_xattrs(dir->i_sb); diff --git a/fs/smbfs/symlink.c b/fs/smbfs/symlink.c index 8b069e06433..0c64bc3a012 100644 --- a/fs/smbfs/symlink.c +++ b/fs/smbfs/symlink.c @@ -34,7 +34,7 @@ int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname) return smb_proc_symlink(server_from_dentry(dentry), dentry, oldname); } -static int smb_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *smb_follow_link(struct dentry *dentry, struct nameidata *nd) { char *link = __getname(); DEBUG1("followlink of %s/%s\n", DENTRY_PATH(dentry)); @@ -52,10 +52,10 @@ static int smb_follow_link(struct dentry *dentry, struct nameidata *nd) } } nd_set_link(nd, link); - return 0; + return NULL; } -static void smb_put_link(struct dentry *dentry, struct nameidata *nd) +static void smb_put_link(struct dentry *dentry, struct nameidata *nd, void *p) { char *s = nd_get_link(nd); if (!IS_ERR(s)) diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index d727dc96063..970a33f0329 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -228,6 +228,10 @@ void sysfs_hash_and_remove(struct dentry * dir, const char * name) struct sysfs_dirent * sd; struct sysfs_dirent * parent_sd = dir->d_fsdata; + if (dir->d_inode == NULL) + /* no inode means this hasn't been made visible yet */ + return; + down(&dir->d_inode->i_sem); list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { if (!sd->s_element) diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index fae57c83a72..de402fa915f 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -151,17 +151,17 @@ static int sysfs_getlink(struct dentry *dentry, char * path) } -static int sysfs_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd) { int error = -ENOMEM; unsigned long page = get_zeroed_page(GFP_KERNEL); if (page) error = sysfs_getlink(dentry, (char *) page); nd_set_link(nd, error ? ERR_PTR(error) : (char *)page); - return 0; + return NULL; } -static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd) +static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) { char *page = nd_get_link(nd); if (!IS_ERR(page)) diff --git a/fs/sysv/symlink.c b/fs/sysv/symlink.c index ed637db2dcb..b85ce61d635 100644 --- a/fs/sysv/symlink.c +++ b/fs/sysv/symlink.c @@ -8,10 +8,10 @@ #include "sysv.h" #include <linux/namei.h> -static int sysv_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *sysv_follow_link(struct dentry *dentry, struct nameidata *nd) { nd_set_link(nd, (char *)SYSV_I(dentry->d_inode)->i_data); - return 0; + return NULL; } struct inode_operations sysv_fast_symlink_inode_operations = { diff --git a/fs/ufs/symlink.c b/fs/ufs/symlink.c index a0e49149098..337512ed578 100644 --- a/fs/ufs/symlink.c +++ b/fs/ufs/symlink.c @@ -29,11 +29,11 @@ #include <linux/namei.h> #include <linux/ufs_fs.h> -static int ufs_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *ufs_follow_link(struct dentry *dentry, struct nameidata *nd) { struct ufs_inode_info *p = UFS_I(dentry->d_inode); nd_set_link(nd, (char*)p->i_u1.i_symlink); - return 0; + return NULL; } struct inode_operations ufs_fast_symlink_inode_operations = { diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 407e9935939..f252605514e 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -374,7 +374,7 @@ linvfs_rename( * we need to be very careful about how much stack we use. * uio is kmalloced for this reason... */ -STATIC int +STATIC void * linvfs_follow_link( struct dentry *dentry, struct nameidata *nd) @@ -391,14 +391,14 @@ linvfs_follow_link( link = (char *)kmalloc(MAXNAMELEN+1, GFP_KERNEL); if (!link) { nd_set_link(nd, ERR_PTR(-ENOMEM)); - return 0; + return NULL; } uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL); if (!uio) { kfree(link); nd_set_link(nd, ERR_PTR(-ENOMEM)); - return 0; + return NULL; } vp = LINVFS_GET_VP(dentry->d_inode); @@ -422,10 +422,10 @@ linvfs_follow_link( kfree(uio); nd_set_link(nd, link); - return 0; + return NULL; } -static void linvfs_put_link(struct dentry *dentry, struct nameidata *nd) +static void linvfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) { char *s = nd_get_link(nd); if (!IS_ERR(s)) diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h index c08ce970ff8..bdb4d66418f 100644 --- a/include/asm-alpha/system.h +++ b/include/asm-alpha/system.h @@ -443,22 +443,19 @@ __xchg_u64(volatile long *m, unsigned long val) if something tries to do an invalid xchg(). */ extern void __xchg_called_with_bad_pointer(void); -static inline unsigned long -__xchg(volatile void *ptr, unsigned long x, int size) -{ - switch (size) { - case 1: - return __xchg_u8(ptr, x); - case 2: - return __xchg_u16(ptr, x); - case 4: - return __xchg_u32(ptr, x); - case 8: - return __xchg_u64(ptr, x); - } - __xchg_called_with_bad_pointer(); - return x; -} +#define __xchg(ptr, x, size) \ +({ \ + unsigned long __xchg__res; \ + volatile void *__xchg__ptr = (ptr); \ + switch (size) { \ + case 1: __xchg__res = __xchg_u8(__xchg__ptr, x); break; \ + case 2: __xchg__res = __xchg_u16(__xchg__ptr, x); break; \ + case 4: __xchg__res = __xchg_u32(__xchg__ptr, x); break; \ + case 8: __xchg__res = __xchg_u64(__xchg__ptr, x); break; \ + default: __xchg_called_with_bad_pointer(); __xchg__res = x; \ + } \ + __xchg__res; \ +}) #define xchg(ptr,x) \ ({ \ diff --git a/include/asm-arm/arch-ixp4xx/timex.h b/include/asm-arm/arch-ixp4xx/timex.h index 38c9d77d372..3745e35cc03 100644 --- a/include/asm-arm/arch-ixp4xx/timex.h +++ b/include/asm-arm/arch-ixp4xx/timex.h @@ -7,7 +7,9 @@ /* * We use IXP425 General purpose timer for our timer needs, it runs at - * 66.66... MHz + * 66.66... MHz. We do a convulted calculation of CLOCK_TICK_RATE b/c the + * timer register ignores the bottom 2 bits of the LATCH value. */ -#define CLOCK_TICK_RATE (66666666) +#define FREQ 66666666 +#define CLOCK_TICK_RATE (((FREQ / HZ & ~IXP4XX_OST_RELOAD_MASK) + 1) * HZ) diff --git a/include/asm-arm/arch-sa1100/mcp.h b/include/asm-arm/arch-sa1100/mcp.h new file mode 100644 index 00000000000..f58a22755c6 --- /dev/null +++ b/include/asm-arm/arch-sa1100/mcp.h @@ -0,0 +1,21 @@ +/* + * linux/include/asm-arm/arch-sa1100/mcp.h + * + * Copyright (C) 2005 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_ARM_ARCH_MCP_H +#define __ASM_ARM_ARCH_MCP_H + +#include <linux/types.h> + +struct mcp_plat_data { + u32 mccr0; + u32 mccr1; + unsigned int sclk_rate; +}; + +#endif diff --git a/include/asm-arm/bug.h b/include/asm-arm/bug.h index 24d11672eb6..7fb02138f58 100644 --- a/include/asm-arm/bug.h +++ b/include/asm-arm/bug.h @@ -5,7 +5,7 @@ #ifdef CONFIG_BUG #ifdef CONFIG_DEBUG_BUGVERBOSE -extern volatile void __bug(const char *file, int line, void *data); +extern void __bug(const char *file, int line, void *data) __attribute__((noreturn)); /* give file/line information */ #define BUG() __bug(__FILE__, __LINE__, NULL) diff --git a/include/asm-arm/cpu-multi32.h b/include/asm-arm/cpu-multi32.h index ff48022e472..4679f63688e 100644 --- a/include/asm-arm/cpu-multi32.h +++ b/include/asm-arm/cpu-multi32.h @@ -31,7 +31,7 @@ extern struct processor { /* * Special stuff for a reset */ - volatile void (*reset)(unsigned long addr); + void (*reset)(unsigned long addr) __attribute__((noreturn)); /* * Idle the processor */ diff --git a/include/asm-arm/cpu-single.h b/include/asm-arm/cpu-single.h index b5ec5d54665..6723e67244f 100644 --- a/include/asm-arm/cpu-single.h +++ b/include/asm-arm/cpu-single.h @@ -41,4 +41,4 @@ extern int cpu_do_idle(void); extern void cpu_dcache_clean_area(void *, int); extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); extern void cpu_set_pte(pte_t *ptep, pte_t pte); -extern volatile void cpu_reset(unsigned long addr); +extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h index 491e9d1fc53..54e7637a326 100644 --- a/include/asm-ia64/io.h +++ b/include/asm-ia64/io.h @@ -120,14 +120,6 @@ static inline void ___ia64_mmiowb(void) ia64_mfa(); } -static inline const unsigned long -__ia64_get_io_port_base (void) -{ - extern unsigned long ia64_iobase; - - return ia64_iobase; -} - static inline void* __ia64_mk_io_addr (unsigned long port) { diff --git a/include/asm-m32r/smp.h b/include/asm-m32r/smp.h index b9a20cdad65..7885b7df84a 100644 --- a/include/asm-m32r/smp.h +++ b/include/asm-m32r/smp.h @@ -61,9 +61,7 @@ extern physid_mask_t phys_cpu_present_map; * Some lowlevel functions might want to know about * the real CPU ID <-> CPU # mapping. */ -extern volatile int physid_2_cpu[NR_CPUS]; extern volatile int cpu_2_physid[NR_CPUS]; -#define physid_to_cpu(physid) physid_2_cpu[physid] #define cpu_to_physid(cpu_id) cpu_2_physid[cpu_id] #define raw_smp_processor_id() (current_thread_info()->cpu) diff --git a/include/asm-m68k/page.h b/include/asm-m68k/page.h index 99a51670921..206313e2a81 100644 --- a/include/asm-m68k/page.h +++ b/include/asm-m68k/page.h @@ -138,13 +138,13 @@ extern unsigned long m68k_memoffset; #define __pa(vaddr) ((unsigned long)(vaddr)+m68k_memoffset) #define __va(paddr) ((void *)((unsigned long)(paddr)-m68k_memoffset)) #else -#define __pa(vaddr) virt_to_phys((void *)vaddr) -#define __va(paddr) phys_to_virt((unsigned long)paddr) +#define __pa(vaddr) virt_to_phys((void *)(vaddr)) +#define __va(paddr) phys_to_virt((unsigned long)(paddr)) #endif #else /* !CONFIG_SUN3 */ /* This #define is a horrible hack to suppress lots of warnings. --m */ -#define __pa(x) ___pa((unsigned long)x) +#define __pa(x) ___pa((unsigned long)(x)) static inline unsigned long ___pa(unsigned long x) { if(x == 0) diff --git a/include/asm-ppc/ibm44x.h b/include/asm-ppc/ibm44x.h index 21e41c9b726..e5374be86ae 100644 --- a/include/asm-ppc/ibm44x.h +++ b/include/asm-ppc/ibm44x.h @@ -423,11 +423,7 @@ #define MQ0_CONFIG_SIZE_2G 0x0000c000 /* Internal SRAM Controller 440GX/440SP */ -#ifdef CONFIG_440SP -#define DCRN_SRAM0_BASE 0x100 -#else /* 440GX */ #define DCRN_SRAM0_BASE 0x000 -#endif #define DCRN_SRAM0_SB0CR (DCRN_SRAM0_BASE + 0x020) #define DCRN_SRAM0_SB1CR (DCRN_SRAM0_BASE + 0x021) diff --git a/include/asm-ppc/ppc4xx_dma.h b/include/asm-ppc/ppc4xx_dma.h index 8636cdbf6f8..a415001165f 100644 --- a/include/asm-ppc/ppc4xx_dma.h +++ b/include/asm-ppc/ppc4xx_dma.h @@ -285,7 +285,7 @@ typedef uint32_t sgl_handle_t; #define GET_DMA_POLARITY(chan) (DMAReq_ActiveLow(chan) | DMAAck_ActiveLow(chan) | EOT_ActiveLow(chan)) -#elif defined(CONFIG_STBXXX_DMA) /* stb03xxx */ +#elif defined(CONFIG_STB03xxx) /* stb03xxx */ #define DMA_PPC4xx_SIZE 4096 diff --git a/include/asm-ppc/time.h b/include/asm-ppc/time.h index ce09b47fa81..321fb75b5f2 100644 --- a/include/asm-ppc/time.h +++ b/include/asm-ppc/time.h @@ -58,7 +58,7 @@ static __inline__ void set_dec(unsigned int val) /* Accessor functions for the timebase (RTC on 601) registers. */ /* If one day CONFIG_POWER is added just define __USE_RTC as 1 */ #ifdef CONFIG_6xx -extern __inline__ int const __USE_RTC(void) { +extern __inline__ int __attribute_pure__ __USE_RTC(void) { return (mfspr(SPRN_PVR)>>16) == 1; } #else diff --git a/include/asm-ppc64/bug.h b/include/asm-ppc64/bug.h index 169868fa307..16017827886 100644 --- a/include/asm-ppc64/bug.h +++ b/include/asm-ppc64/bug.h @@ -43,8 +43,8 @@ struct bug_entry *find_bug(unsigned long bugaddr); ".section __bug_table,\"a\"\n\t" \ " .llong 1b,%1,%2,%3\n" \ ".previous" \ - : : "r" (x), "i" (__LINE__), "i" (__FILE__), \ - "i" (__FUNCTION__)); \ + : : "r" ((long long)(x)), "i" (__LINE__), \ + "i" (__FILE__), "i" (__FUNCTION__)); \ } while (0) #define WARN_ON(x) do { \ @@ -53,7 +53,8 @@ struct bug_entry *find_bug(unsigned long bugaddr); ".section __bug_table,\"a\"\n\t" \ " .llong 1b,%1,%2,%3\n" \ ".previous" \ - : : "r" (x), "i" (__LINE__ + BUG_WARNING_TRAP), \ + : : "r" ((long long)(x)), \ + "i" (__LINE__ + BUG_WARNING_TRAP), \ "i" (__FILE__), "i" (__FUNCTION__)); \ } while (0) diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h index a7f43a251f8..3e3bfe6a8fa 100644 --- a/include/asm-s390/uaccess.h +++ b/include/asm-s390/uaccess.h @@ -149,11 +149,11 @@ struct exception_table_entry }) #endif -#ifndef __CHECKER__ #define __put_user(x, ptr) \ ({ \ __typeof__(*(ptr)) __x = (x); \ int __pu_err; \ + __chk_user_ptr(ptr); \ switch (sizeof (*(ptr))) { \ case 1: \ case 2: \ @@ -167,14 +167,6 @@ struct exception_table_entry } \ __pu_err; \ }) -#else -#define __put_user(x, ptr) \ -({ \ - void __user *p; \ - p = (ptr); \ - 0; \ -}) -#endif #define put_user(x, ptr) \ ({ \ @@ -213,11 +205,11 @@ extern int __put_user_bad(void) __attribute__((noreturn)); }) #endif -#ifndef __CHECKER__ #define __get_user(x, ptr) \ ({ \ __typeof__(*(ptr)) __x; \ int __gu_err; \ + __chk_user_ptr(ptr); \ switch (sizeof(*(ptr))) { \ case 1: \ case 2: \ @@ -232,15 +224,6 @@ extern int __put_user_bad(void) __attribute__((noreturn)); (x) = __x; \ __gu_err; \ }) -#else -#define __get_user(x, ptr) \ -({ \ - void __user *p; \ - p = (ptr); \ - 0; \ -}) -#endif - #define get_user(x, ptr) \ ({ \ diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h index 4e7701d6d23..ea89e8f223e 100644 --- a/include/asm-sh/unistd.h +++ b/include/asm-sh/unistd.h @@ -295,8 +295,14 @@ #define __NR_add_key 285 #define __NR_request_key 286 #define __NR_keyctl 287 +#define __NR_ioprio_set 288 +#define __NR_ioprio_get 289 +#define __NR_inotify_init 290 +#define __NR_inotify_add_watch 291 +#define __NR_inotify_rm_watch 292 -#define NR_syscalls 288 + +#define NR_syscalls 293 /* user-visible error numbers are in the range -1 - -124: see <asm-sh/errno.h> */ diff --git a/include/asm-sh64/unistd.h b/include/asm-sh64/unistd.h index 95f0b130405..2a1cfa404ea 100644 --- a/include/asm-sh64/unistd.h +++ b/include/asm-sh64/unistd.h @@ -338,8 +338,13 @@ #define __NR_add_key 313 #define __NR_request_key 314 #define __NR_keyctl 315 +#define __NR_ioprio_set 316 +#define __NR_ioprio_get 317 +#define __NR_inotify_init 318 +#define __NR_inotify_add_watch 319 +#define __NR_inotify_rm_watch 320 -#define NR_syscalls 316 +#define NR_syscalls 321 /* user-visible error numbers are in the range -1 - -125: see <asm-sh64/errno.h> */ diff --git a/include/asm-sparc64/thread_info.h b/include/asm-sparc64/thread_info.h index 352d9943661..c94d8b3991b 100644 --- a/include/asm-sparc64/thread_info.h +++ b/include/asm-sparc64/thread_info.h @@ -68,6 +68,9 @@ struct thread_info { struct restart_block restart_block; + struct pt_regs *kern_una_regs; + unsigned int kern_una_insn; + unsigned long fpregs[0] __attribute__ ((aligned(64))); }; @@ -103,6 +106,8 @@ struct thread_info { #define TI_PCR 0x00000490 #define TI_CEE_STUFF 0x00000498 #define TI_RESTART_BLOCK 0x000004a0 +#define TI_KUNA_REGS 0x000004c8 +#define TI_KUNA_INSN 0x000004d0 #define TI_FPREGS 0x00000500 /* We embed this in the uppermost byte of thread_info->flags */ diff --git a/include/asm-x86_64/e820.h b/include/asm-x86_64/e820.h index 8e94edf0b98..e682edc24a6 100644 --- a/include/asm-x86_64/e820.h +++ b/include/asm-x86_64/e820.h @@ -51,6 +51,8 @@ extern int e820_mapped(unsigned long start, unsigned long end, unsigned type); extern void e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end); extern void e820_setup_gap(void); +extern unsigned long e820_hole_size(unsigned long start_pfn, + unsigned long end_pfn); extern void __init parse_memopt(char *p, char **end); diff --git a/include/linux/8250_pci.h b/include/linux/8250_pci.h index 5f3ab21b339..3209dd46ea7 100644 --- a/include/linux/8250_pci.h +++ b/include/linux/8250_pci.h @@ -1,2 +1,37 @@ -int pci_siig10x_fn(struct pci_dev *dev, int enable); -int pci_siig20x_fn(struct pci_dev *dev, int enable); +/* + * Definitions for PCI support. + */ +#define FL_BASE_MASK 0x0007 +#define FL_BASE0 0x0000 +#define FL_BASE1 0x0001 +#define FL_BASE2 0x0002 +#define FL_BASE3 0x0003 +#define FL_BASE4 0x0004 +#define FL_GET_BASE(x) (x & FL_BASE_MASK) + +/* Use successive BARs (PCI base address registers), + else use offset into some specified BAR */ +#define FL_BASE_BARS 0x0008 + +/* do not assign an irq */ +#define FL_NOIRQ 0x0080 + +/* Use the Base address register size to cap number of ports */ +#define FL_REGION_SZ_CAP 0x0100 + +struct pciserial_board { + unsigned int flags; + unsigned int num_ports; + unsigned int base_baud; + unsigned int uart_offset; + unsigned int reg_shift; + unsigned int first_offset; +}; + +struct serial_private; + +struct serial_private * +pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board); +void pciserial_remove_ports(struct serial_private *priv); +void pciserial_suspend_ports(struct serial_private *priv); +void pciserial_resume_ports(struct serial_private *priv); diff --git a/include/linux/ata.h b/include/linux/ata.h index ca5fcadf998..9d25e9886d6 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -108,6 +108,8 @@ enum { /* ATA device commands */ ATA_CMD_CHK_POWER = 0xE5, /* check power mode */ + ATA_CMD_STANDBY = 0xE2, /* place in standby power mode */ + ATA_CMD_IDLE = 0xE3, /* place in idle power mode */ ATA_CMD_EDD = 0x90, /* execute device diagnostic */ ATA_CMD_FLUSH = 0xE7, ATA_CMD_FLUSH_EXT = 0xEA, diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index a0ab26aab45..d7021c391b2 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -408,6 +408,8 @@ struct ethtool_ops { #define SUPPORTED_FIBRE (1 << 10) #define SUPPORTED_BNC (1 << 11) #define SUPPORTED_10000baseT_Full (1 << 12) +#define SUPPORTED_Pause (1 << 13) +#define SUPPORTED_Asym_Pause (1 << 14) /* Indicates what features are advertised by the interface. */ #define ADVERTISED_10baseT_Half (1 << 0) @@ -423,6 +425,8 @@ struct ethtool_ops { #define ADVERTISED_FIBRE (1 << 10) #define ADVERTISED_BNC (1 << 11) #define ADVERTISED_10000baseT_Full (1 << 12) +#define ADVERTISED_Pause (1 << 13) +#define ADVERTISED_Asym_Pause (1 << 14) /* The following are all involved in forcing a particular link * mode for the device for setting things. When getting the diff --git a/include/linux/fs.h b/include/linux/fs.h index f9adf75fd9b..67e6732d4fd 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -993,8 +993,8 @@ struct inode_operations { int (*rename) (struct inode *, struct dentry *, struct inode *, struct dentry *); int (*readlink) (struct dentry *, char __user *,int); - int (*follow_link) (struct dentry *, struct nameidata *); - void (*put_link) (struct dentry *, struct nameidata *); + void * (*follow_link) (struct dentry *, struct nameidata *); + void (*put_link) (struct dentry *, struct nameidata *, void *); void (*truncate) (struct inode *); int (*permission) (struct inode *, int, struct nameidata *); int (*setattr) (struct dentry *, struct iattr *); @@ -1602,8 +1602,8 @@ extern struct file_operations generic_ro_fops; extern int vfs_readlink(struct dentry *, char __user *, int, const char *); extern int vfs_follow_link(struct nameidata *, const char *); extern int page_readlink(struct dentry *, char __user *, int); -extern int page_follow_link_light(struct dentry *, struct nameidata *); -extern void page_put_link(struct dentry *, struct nameidata *); +extern void *page_follow_link_light(struct dentry *, struct nameidata *); +extern void page_put_link(struct dentry *, struct nameidata *, void *); extern int page_symlink(struct inode *inode, const char *symname, int len); extern struct inode_operations page_symlink_inode_operations; extern int generic_readlink(struct dentry *, char __user *, int); diff --git a/include/linux/libata.h b/include/linux/libata.h index 6cd9ba63563..7c09540c52b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -113,6 +113,8 @@ enum { ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */ ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */ ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */ + ATA_FLAG_NOINTR = (1 << 9), /* FIXME: Remove this once + * proper HSM is in place. */ ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ @@ -363,7 +365,7 @@ struct ata_port_operations { void (*host_stop) (struct ata_host_set *host_set); - void (*bmdma_stop) (struct ata_port *ap); + void (*bmdma_stop) (struct ata_queued_cmd *qc); u8 (*bmdma_status) (struct ata_port *ap); }; @@ -424,7 +426,7 @@ extern void ata_dev_id_string(u16 *id, unsigned char *s, extern void ata_dev_config(struct ata_port *ap, unsigned int i); extern void ata_bmdma_setup (struct ata_queued_cmd *qc); extern void ata_bmdma_start (struct ata_queued_cmd *qc); -extern void ata_bmdma_stop(struct ata_port *ap); +extern void ata_bmdma_stop(struct ata_queued_cmd *qc); extern u8 ata_bmdma_status(struct ata_port *ap); extern void ata_bmdma_irq_clear(struct ata_port *ap); extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat); @@ -644,7 +646,7 @@ static inline void scr_write(struct ata_port *ap, unsigned int reg, u32 val) ap->ops->scr_write(ap, reg, val); } -static inline void scr_write_flush(struct ata_port *ap, unsigned int reg, +static inline void scr_write_flush(struct ata_port *ap, unsigned int reg, u32 val) { ap->ops->scr_write(ap, reg, val); diff --git a/include/linux/mii.h b/include/linux/mii.h index 374b615ea9e..9b8d0476988 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -22,6 +22,7 @@ #define MII_EXPANSION 0x06 /* Expansion register */ #define MII_CTRL1000 0x09 /* 1000BASE-T control */ #define MII_STAT1000 0x0a /* 1000BASE-T status */ +#define MII_ESTATUS 0x0f /* Extended Status */ #define MII_DCOUNTER 0x12 /* Disconnect counter */ #define MII_FCSCOUNTER 0x13 /* False carrier counter */ #define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */ @@ -54,7 +55,10 @@ #define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ #define BMSR_RFAULT 0x0010 /* Remote fault detected */ #define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ -#define BMSR_RESV 0x07c0 /* Unused... */ +#define BMSR_RESV 0x00c0 /* Unused... */ +#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ +#define BMSR_100FULL2 0x0200 /* Can do 100BASE-T2 HDX */ +#define BMSR_100HALF2 0x0400 /* Can do 100BASE-T2 FDX */ #define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ #define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ #define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ @@ -114,6 +118,9 @@ #define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */ #define EXPANSION_RESV 0xffe0 /* Unused... */ +#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */ +#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */ + /* N-way test register. */ #define NWAYTEST_RESV1 0x00ff /* Unused... */ #define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */ diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index f90f674eb3b..9a0893f3249 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -63,11 +63,12 @@ struct device; struct mmc_host { struct device *dev; + struct class_device class_dev; + int index; struct mmc_host_ops *ops; unsigned int f_min; unsigned int f_max; u32 ocr_avail; - char host_name[8]; /* host specific block data */ unsigned int max_seg_size; /* see blk_queue_max_segment_size */ @@ -97,6 +98,7 @@ extern void mmc_free_host(struct mmc_host *); #define mmc_priv(x) ((void *)((x) + 1)) #define mmc_dev(x) ((x)->dev) +#define mmc_hostname(x) ((x)->class_dev.class_id) extern int mmc_suspend_host(struct mmc_host *, pm_message_t); extern int mmc_resume_host(struct mmc_host *); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 7d78a783c64..9a6047ff1b2 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -112,7 +112,8 @@ struct nfs_inode { /* * Various flags */ - unsigned int flags; + unsigned long flags; /* atomic bit ops */ + unsigned long cache_validity; /* bit mask */ /* * read_cache_jiffies is when we started read-caching this inode, @@ -174,8 +175,6 @@ struct nfs_inode { /* Open contexts for shared mmap writes */ struct list_head open_files; - wait_queue_head_t nfs_i_wait; - #ifdef CONFIG_NFS_V4 struct nfs4_cached_acl *nfs4_acl; /* NFSv4 state */ @@ -188,17 +187,21 @@ struct nfs_inode { }; /* - * Legal inode flag values + * Cache validity bit flags */ -#define NFS_INO_STALE 0x0001 /* possible stale inode */ -#define NFS_INO_ADVISE_RDPLUS 0x0002 /* advise readdirplus */ -#define NFS_INO_REVALIDATING 0x0004 /* revalidating attrs */ -#define NFS_INO_INVALID_ATTR 0x0008 /* cached attrs are invalid */ -#define NFS_INO_INVALID_DATA 0x0010 /* cached data is invalid */ -#define NFS_INO_INVALID_ATIME 0x0020 /* cached atime is invalid */ -#define NFS_INO_INVALID_ACCESS 0x0040 /* cached access cred invalid */ -#define NFS_INO_INVALID_ACL 0x0080 /* cached acls are invalid */ -#define NFS_INO_REVAL_PAGECACHE 0x1000 /* must revalidate pagecache */ +#define NFS_INO_INVALID_ATTR 0x0001 /* cached attrs are invalid */ +#define NFS_INO_INVALID_DATA 0x0002 /* cached data is invalid */ +#define NFS_INO_INVALID_ATIME 0x0004 /* cached atime is invalid */ +#define NFS_INO_INVALID_ACCESS 0x0008 /* cached access cred invalid */ +#define NFS_INO_INVALID_ACL 0x0010 /* cached acls are invalid */ +#define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */ + +/* + * Bit offsets in flags field + */ +#define NFS_INO_REVALIDATING (0) /* revalidating attrs */ +#define NFS_INO_ADVISE_RDPLUS (1) /* advise readdirplus */ +#define NFS_INO_STALE (2) /* possible stale inode */ static inline struct nfs_inode *NFS_I(struct inode *inode) { @@ -224,8 +227,7 @@ static inline struct nfs_inode *NFS_I(struct inode *inode) #define NFS_ATTRTIMEO_UPDATE(inode) (NFS_I(inode)->attrtimeo_timestamp) #define NFS_FLAGS(inode) (NFS_I(inode)->flags) -#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING) -#define NFS_STALE(inode) (NFS_FLAGS(inode) & NFS_INO_STALE) +#define NFS_STALE(inode) (test_bit(NFS_INO_STALE, &NFS_FLAGS(inode))) #define NFS_FILEID(inode) (NFS_I(inode)->fileid) @@ -236,8 +238,11 @@ static inline int nfs_caches_unstable(struct inode *inode) static inline void NFS_CACHEINV(struct inode *inode) { - if (!nfs_caches_unstable(inode)) - NFS_FLAGS(inode) |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS; + if (!nfs_caches_unstable(inode)) { + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS; + spin_unlock(&inode->i_lock); + } } static inline int nfs_server_capable(struct inode *inode, int cap) @@ -247,7 +252,7 @@ static inline int nfs_server_capable(struct inode *inode, int cap) static inline int NFS_USE_READDIRPLUS(struct inode *inode) { - return NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS; + return test_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode)); } /** diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 51e61e96051..499a5325f67 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -881,7 +881,7 @@ #define PCI_DEVICE_ID_APPLE_UNI_N_PCI15 0x002e #define PCI_DEVICE_ID_APPLE_UNI_N_FW2 0x0030 #define PCI_DEVICE_ID_APPLE_UNI_N_GMAC2 0x0032 -#define PCI_DEVIEC_ID_APPLE_UNI_N_ATA 0x0033 +#define PCI_DEVICE_ID_APPLE_UNI_N_ATA 0x0033 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP2 0x0034 #define PCI_DEVICE_ID_APPLE_IPID_ATA100 0x003b #define PCI_DEVICE_ID_APPLE_KEYLARGO_I 0x003e @@ -1249,6 +1249,7 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2 0x0267 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE 0x036E +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x036F #define PCI_DEVICE_ID_NVIDIA_NVENET_12 0x0268 #define PCI_DEVICE_ID_NVIDIA_NVENET_13 0x0269 #define PCI_DEVICE_ID_NVIDIA_MCP51_AUDIO 0x026B @@ -1580,6 +1581,7 @@ #define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211 #define PCI_DEVICE_ID_SERVERWORKS_CSB5IDE 0x0212 #define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE 0x0213 +#define PCI_DEVICE_ID_SERVERWORKS_HT1000IDE 0x0214 #define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 0x0217 #define PCI_DEVICE_ID_SERVERWORKS_OSB4USB 0x0220 #define PCI_DEVICE_ID_SERVERWORKS_CSB5USB PCI_DEVICE_ID_SERVERWORKS_OSB4USB @@ -2184,6 +2186,9 @@ #define PCI_VENDOR_ID_SIBYTE 0x166d #define PCI_DEVICE_ID_BCM1250_HT 0x0002 +#define PCI_VENDOR_ID_NETCELL 0x169c +#define PCI_DEVICE_ID_REVOLUTION 0x0044 + #define PCI_VENDOR_ID_LINKSYS 0x1737 #define PCI_DEVICE_ID_LINKSYS_EG1032 0x1032 #define PCI_DEVICE_ID_LINKSYS_EG1064 0x1064 diff --git a/include/linux/phy.h b/include/linux/phy.h new file mode 100644 index 00000000000..72cb67b66e0 --- /dev/null +++ b/include/linux/phy.h @@ -0,0 +1,377 @@ +/* + * include/linux/phy.h + * + * Framework and drivers for configuring and reading different PHYs + * Based on code in sungem_phy.c and gianfar_phy.c + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * 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. + * + */ + +#ifndef __PHY_H +#define __PHY_H + +#include <linux/spinlock.h> +#include <linux/device.h> + +#define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ + SUPPORTED_10baseT_Full | \ + SUPPORTED_100baseT_Half | \ + SUPPORTED_100baseT_Full | \ + SUPPORTED_Autoneg | \ + SUPPORTED_TP | \ + SUPPORTED_MII) + +#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \ + SUPPORTED_1000baseT_Half | \ + SUPPORTED_1000baseT_Full) + +/* Set phydev->irq to PHY_POLL if interrupts are not supported, + * or not desired for this PHY. Set to PHY_IGNORE_INTERRUPT if + * the attached driver handles the interrupt + */ +#define PHY_POLL -1 +#define PHY_IGNORE_INTERRUPT -2 + +#define PHY_HAS_INTERRUPT 0x00000001 +#define PHY_HAS_MAGICANEG 0x00000002 + +#define MII_BUS_MAX 4 + + +#define PHY_INIT_TIMEOUT 100000 +#define PHY_STATE_TIME 1 +#define PHY_FORCE_TIMEOUT 10 +#define PHY_AN_TIMEOUT 10 + +#define PHY_MAX_ADDR 32 + +/* The Bus class for PHYs. Devices which provide access to + * PHYs should register using this structure */ +struct mii_bus { + const char *name; + int id; + void *priv; + int (*read)(struct mii_bus *bus, int phy_id, int regnum); + int (*write)(struct mii_bus *bus, int phy_id, int regnum, u16 val); + int (*reset)(struct mii_bus *bus); + + /* A lock to ensure that only one thing can read/write + * the MDIO bus at a time */ + spinlock_t mdio_lock; + + struct device *dev; + + /* list of all PHYs on bus */ + struct phy_device *phy_map[PHY_MAX_ADDR]; + + /* Pointer to an array of interrupts, each PHY's + * interrupt at the index matching its address */ + int *irq; +}; + +#define PHY_INTERRUPT_DISABLED 0x0 +#define PHY_INTERRUPT_ENABLED 0x80000000 + +/* PHY state machine states: + * + * DOWN: PHY device and driver are not ready for anything. probe + * should be called if and only if the PHY is in this state, + * given that the PHY device exists. + * - PHY driver probe function will, depending on the PHY, set + * the state to STARTING or READY + * + * STARTING: PHY device is coming up, and the ethernet driver is + * not ready. PHY drivers may set this in the probe function. + * If they do, they are responsible for making sure the state is + * eventually set to indicate whether the PHY is UP or READY, + * depending on the state when the PHY is done starting up. + * - PHY driver will set the state to READY + * - start will set the state to PENDING + * + * READY: PHY is ready to send and receive packets, but the + * controller is not. By default, PHYs which do not implement + * probe will be set to this state by phy_probe(). If the PHY + * driver knows the PHY is ready, and the PHY state is STARTING, + * then it sets this STATE. + * - start will set the state to UP + * + * PENDING: PHY device is coming up, but the ethernet driver is + * ready. phy_start will set this state if the PHY state is + * STARTING. + * - PHY driver will set the state to UP when the PHY is ready + * + * UP: The PHY and attached device are ready to do work. + * Interrupts should be started here. + * - timer moves to AN + * + * AN: The PHY is currently negotiating the link state. Link is + * therefore down for now. phy_timer will set this state when it + * detects the state is UP. config_aneg will set this state + * whenever called with phydev->autoneg set to AUTONEG_ENABLE. + * - If autonegotiation finishes, but there's no link, it sets + * the state to NOLINK. + * - If aneg finishes with link, it sets the state to RUNNING, + * and calls adjust_link + * - If autonegotiation did not finish after an arbitrary amount + * of time, autonegotiation should be tried again if the PHY + * supports "magic" autonegotiation (back to AN) + * - If it didn't finish, and no magic_aneg, move to FORCING. + * + * NOLINK: PHY is up, but not currently plugged in. + * - If the timer notes that the link comes back, we move to RUNNING + * - config_aneg moves to AN + * - phy_stop moves to HALTED + * + * FORCING: PHY is being configured with forced settings + * - if link is up, move to RUNNING + * - If link is down, we drop to the next highest setting, and + * retry (FORCING) after a timeout + * - phy_stop moves to HALTED + * + * RUNNING: PHY is currently up, running, and possibly sending + * and/or receiving packets + * - timer will set CHANGELINK if we're polling (this ensures the + * link state is polled every other cycle of this state machine, + * which makes it every other second) + * - irq will set CHANGELINK + * - config_aneg will set AN + * - phy_stop moves to HALTED + * + * CHANGELINK: PHY experienced a change in link state + * - timer moves to RUNNING if link + * - timer moves to NOLINK if the link is down + * - phy_stop moves to HALTED + * + * HALTED: PHY is up, but no polling or interrupts are done. Or + * PHY is in an error state. + * + * - phy_start moves to RESUMING + * + * RESUMING: PHY was halted, but now wants to run again. + * - If we are forcing, or aneg is done, timer moves to RUNNING + * - If aneg is not done, timer moves to AN + * - phy_stop moves to HALTED + */ +enum phy_state { + PHY_DOWN=0, + PHY_STARTING, + PHY_READY, + PHY_PENDING, + PHY_UP, + PHY_AN, + PHY_RUNNING, + PHY_NOLINK, + PHY_FORCING, + PHY_CHANGELINK, + PHY_HALTED, + PHY_RESUMING +}; + +/* phy_device: An instance of a PHY + * + * drv: Pointer to the driver for this PHY instance + * bus: Pointer to the bus this PHY is on + * dev: driver model device structure for this PHY + * phy_id: UID for this device found during discovery + * state: state of the PHY for management purposes + * dev_flags: Device-specific flags used by the PHY driver. + * addr: Bus address of PHY + * link_timeout: The number of timer firings to wait before the + * giving up on the current attempt at acquiring a link + * irq: IRQ number of the PHY's interrupt (-1 if none) + * phy_timer: The timer for handling the state machine + * phy_queue: A work_queue for the interrupt + * attached_dev: The attached enet driver's device instance ptr + * adjust_link: Callback for the enet controller to respond to + * changes in the link state. + * adjust_state: Callback for the enet driver to respond to + * changes in the state machine. + * + * speed, duplex, pause, supported, advertising, and + * autoneg are used like in mii_if_info + * + * interrupts currently only supports enabled or disabled, + * but could be changed in the future to support enabling + * and disabling specific interrupts + * + * Contains some infrastructure for polling and interrupt + * handling, as well as handling shifts in PHY hardware state + */ +struct phy_device { + /* Information about the PHY type */ + /* And management functions */ + struct phy_driver *drv; + + struct mii_bus *bus; + + struct device dev; + + u32 phy_id; + + enum phy_state state; + + u32 dev_flags; + + /* Bus address of the PHY (0-32) */ + int addr; + + /* forced speed & duplex (no autoneg) + * partner speed & duplex & pause (autoneg) + */ + int speed; + int duplex; + int pause; + int asym_pause; + + /* The most recently read link state */ + int link; + + /* Enabled Interrupts */ + u32 interrupts; + + /* Union of PHY and Attached devices' supported modes */ + /* See mii.h for more info */ + u32 supported; + u32 advertising; + + int autoneg; + + int link_timeout; + + /* Interrupt number for this PHY + * -1 means no interrupt */ + int irq; + + /* private data pointer */ + /* For use by PHYs to maintain extra state */ + void *priv; + + /* Interrupt and Polling infrastructure */ + struct work_struct phy_queue; + struct timer_list phy_timer; + + spinlock_t lock; + + struct net_device *attached_dev; + + void (*adjust_link)(struct net_device *dev); + + void (*adjust_state)(struct net_device *dev); +}; +#define to_phy_device(d) container_of(d, struct phy_device, dev) + +/* struct phy_driver: Driver structure for a particular PHY type + * + * phy_id: The result of reading the UID registers of this PHY + * type, and ANDing them with the phy_id_mask. This driver + * only works for PHYs with IDs which match this field + * name: The friendly name of this PHY type + * phy_id_mask: Defines the important bits of the phy_id + * features: A list of features (speed, duplex, etc) supported + * by this PHY + * flags: A bitfield defining certain other features this PHY + * supports (like interrupts) + * + * The drivers must implement config_aneg and read_status. All + * other functions are optional. Note that none of these + * functions should be called from interrupt time. The goal is + * for the bus read/write functions to be able to block when the + * bus transaction is happening, and be freed up by an interrupt + * (The MPC85xx has this ability, though it is not currently + * supported in the driver). + */ +struct phy_driver { + u32 phy_id; + char *name; + unsigned int phy_id_mask; + u32 features; + u32 flags; + + /* Called to initialize the PHY, + * including after a reset */ + int (*config_init)(struct phy_device *phydev); + + /* Called during discovery. Used to set + * up device-specific structures, if any */ + int (*probe)(struct phy_device *phydev); + + /* PHY Power Management */ + int (*suspend)(struct phy_device *phydev); + int (*resume)(struct phy_device *phydev); + + /* Configures the advertisement and resets + * autonegotiation if phydev->autoneg is on, + * forces the speed to the current settings in phydev + * if phydev->autoneg is off */ + int (*config_aneg)(struct phy_device *phydev); + + /* Determines the negotiated speed and duplex */ + int (*read_status)(struct phy_device *phydev); + + /* Clears any pending interrupts */ + int (*ack_interrupt)(struct phy_device *phydev); + + /* Enables or disables interrupts */ + int (*config_intr)(struct phy_device *phydev); + + /* Clears up any memory if needed */ + void (*remove)(struct phy_device *phydev); + + struct device_driver driver; +}; +#define to_phy_driver(d) container_of(d, struct phy_driver, driver) + +int phy_read(struct phy_device *phydev, u16 regnum); +int phy_write(struct phy_device *phydev, u16 regnum, u16 val); +struct phy_device* get_phy_device(struct mii_bus *bus, int addr); +int phy_clear_interrupt(struct phy_device *phydev); +int phy_config_interrupt(struct phy_device *phydev, u32 interrupts); +struct phy_device * phy_attach(struct net_device *dev, + const char *phy_id, u32 flags); +struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, + void (*handler)(struct net_device *), u32 flags); +void phy_disconnect(struct phy_device *phydev); +void phy_detach(struct phy_device *phydev); +void phy_start(struct phy_device *phydev); +void phy_stop(struct phy_device *phydev); +int phy_start_aneg(struct phy_device *phydev); + +int mdiobus_register(struct mii_bus *bus); +void mdiobus_unregister(struct mii_bus *bus); +void phy_sanitize_settings(struct phy_device *phydev); +int phy_stop_interrupts(struct phy_device *phydev); + +static inline int phy_read_status(struct phy_device *phydev) { + return phydev->drv->read_status(phydev); +} + +int genphy_config_advert(struct phy_device *phydev); +int genphy_setup_forced(struct phy_device *phydev); +int genphy_restart_aneg(struct phy_device *phydev); +int genphy_config_aneg(struct phy_device *phydev); +int genphy_update_link(struct phy_device *phydev); +int genphy_read_status(struct phy_device *phydev); +void phy_driver_unregister(struct phy_driver *drv); +int phy_driver_register(struct phy_driver *new_driver); +void phy_prepare_link(struct phy_device *phydev, + void (*adjust_link)(struct net_device *)); +void phy_start_machine(struct phy_device *phydev, + void (*handler)(struct net_device *)); +void phy_stop_machine(struct phy_device *phydev); +int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd); +int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd); +int phy_mii_ioctl(struct phy_device *phydev, + struct mii_ioctl_data *mii_data, int cmd); +int phy_start_interrupts(struct phy_device *phydev); +void phy_print_status(struct phy_device *phydev); + +extern struct bus_type mdio_bus_type; +#endif /* __PHY_H */ diff --git a/include/linux/serialP.h b/include/linux/serialP.h index 2b2f35a64d7..2b9e6b9554d 100644 --- a/include/linux/serialP.h +++ b/include/linux/serialP.h @@ -140,44 +140,4 @@ struct rs_multiport_struct { #define ALPHA_KLUDGE_MCR 0 #endif -/* - * Definitions for PCI support. - */ -#define SPCI_FL_BASE_MASK 0x0007 -#define SPCI_FL_BASE0 0x0000 -#define SPCI_FL_BASE1 0x0001 -#define SPCI_FL_BASE2 0x0002 -#define SPCI_FL_BASE3 0x0003 -#define SPCI_FL_BASE4 0x0004 -#define SPCI_FL_GET_BASE(x) (x & SPCI_FL_BASE_MASK) - -#define SPCI_FL_IRQ_MASK (0x0007 << 4) -#define SPCI_FL_IRQBASE0 (0x0000 << 4) -#define SPCI_FL_IRQBASE1 (0x0001 << 4) -#define SPCI_FL_IRQBASE2 (0x0002 << 4) -#define SPCI_FL_IRQBASE3 (0x0003 << 4) -#define SPCI_FL_IRQBASE4 (0x0004 << 4) -#define SPCI_FL_GET_IRQBASE(x) ((x & SPCI_FL_IRQ_MASK) >> 4) - -/* Use successive BARs (PCI base address registers), - else use offset into some specified BAR */ -#define SPCI_FL_BASE_TABLE 0x0100 - -/* Use successive entries in the irq resource table */ -#define SPCI_FL_IRQ_TABLE 0x0200 - -/* Use the irq resource table instead of dev->irq */ -#define SPCI_FL_IRQRESOURCE 0x0400 - -/* Use the Base address register size to cap number of ports */ -#define SPCI_FL_REGION_SZ_CAP 0x0800 - -/* Do not use irq sharing for this device */ -#define SPCI_FL_NO_SHIRQ 0x1000 - -/* This is a PNP device */ -#define SPCI_FL_ISPNP 0x2000 - -#define SPCI_FL_PNPDEFAULT (SPCI_FL_IRQRESOURCE|SPCI_FL_ISPNP) - #endif /* _LINUX_SERIAL_H */ diff --git a/include/net/ax25.h b/include/net/ax25.h index 828a3a93dda..3696f988a9f 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -139,11 +139,25 @@ enum { #define AX25_DEF_DS_TIMEOUT (3 * 60 * HZ) /* DAMA timeout 3 minutes */ typedef struct ax25_uid_assoc { - struct ax25_uid_assoc *next; + struct hlist_node uid_node; + atomic_t refcount; uid_t uid; ax25_address call; } ax25_uid_assoc; +#define ax25_uid_for_each(__ax25, node, list) \ + hlist_for_each_entry(__ax25, node, list, uid_node) + +#define ax25_uid_hold(ax25) \ + atomic_inc(&((ax25)->refcount)) + +static inline void ax25_uid_put(ax25_uid_assoc *assoc) +{ + if (atomic_dec_and_test(&assoc->refcount)) { + kfree(assoc); + } +} + typedef struct { ax25_address calls[AX25_MAX_DIGIS]; unsigned char repeated[AX25_MAX_DIGIS]; @@ -376,7 +390,7 @@ extern unsigned long ax25_display_timer(struct timer_list *); /* ax25_uid.c */ extern int ax25_uid_policy; -extern ax25_address *ax25_findbyuid(uid_t); +extern ax25_uid_assoc *ax25_findbyuid(uid_t); extern int ax25_uid_ioctl(int, struct sockaddr_ax25 *); extern struct file_operations ax25_uid_fops; extern void ax25_uid_free(void); diff --git a/include/net/sock.h b/include/net/sock.h index a1042d08bec..e9b1dbab90d 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -384,6 +384,11 @@ enum sock_flags { SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */ }; +static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) +{ + nsk->sk_flags = osk->sk_flags; +} + static inline void sock_set_flag(struct sock *sk, enum sock_flags flag) { __set_bit(flag, &sk->sk_flags); diff --git a/include/sound/core.h b/include/sound/core.h index 38b357fc895..f72b3ef515e 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -360,11 +360,13 @@ int snd_device_free_all(snd_card_t *card, snd_device_cmd_t cmd); /* isadma.c */ +#ifdef CONFIG_ISA_DMA_API #define DMA_MODE_NO_ENABLE 0x0100 void snd_dma_program(unsigned long dma, unsigned long addr, unsigned int size, unsigned short mode); void snd_dma_disable(unsigned long dma); unsigned int snd_dma_pointer(unsigned long dma, unsigned int size); +#endif /* misc.c */ diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 21a4e3b2cbd..8ab1b4e518b 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -627,6 +627,14 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial) * Call with cpuset_sem held. May nest a call to the * lock_cpu_hotplug()/unlock_cpu_hotplug() pair. */ + +/* + * Hack to avoid 2.6.13 partial node dynamic sched domain bug. + * Disable letting 'cpu_exclusive' cpusets define dynamic sched + * domains, until the sched domain can handle partial nodes. + * Remove this #if hackery when sched domains fixed. + */ +#if 0 static void update_cpu_domains(struct cpuset *cur) { struct cpuset *c, *par = cur->parent; @@ -667,6 +675,11 @@ static void update_cpu_domains(struct cpuset *cur) partition_sched_domains(&pspan, &cspan); unlock_cpu_hotplug(); } +#else +static void update_cpu_domains(struct cpuset *cur) +{ +} +#endif static int update_cpumask(struct cpuset *cs, char *buf) { diff --git a/kernel/sched.c b/kernel/sched.c index a646e4f36c4..5f889d0cbfc 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3378,8 +3378,8 @@ EXPORT_SYMBOL(set_user_nice); */ int can_nice(const task_t *p, const int nice) { - /* convert nice value [19,-20] to rlimit style value [0,39] */ - int nice_rlim = 19 - nice; + /* convert nice value [19,-20] to rlimit style value [1,40] */ + int nice_rlim = 20 - nice; return (nice_rlim <= p->signal->rlim[RLIMIT_NICE].rlim_cur || capable(CAP_SYS_NICE)); } diff --git a/kernel/timer.c b/kernel/timer.c index f2a11887a72..5377f40723f 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1023,7 +1023,7 @@ asmlinkage long sys_getppid(void) parent = me->group_leader->real_parent; for (;;) { pid = parent->tgid; -#ifdef CONFIG_SMP +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) { struct task_struct *old = parent; diff --git a/lib/idr.c b/lib/idr.c index c5be889de44..6415d053e2b 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -207,7 +207,7 @@ build_up: } /** - * idr_get_new_above - allocate new idr entry above a start id + * idr_get_new_above - allocate new idr entry above or equal to a start id * @idp: idr handle * @ptr: pointer you want associated with the ide * @start_id: id to start search at diff --git a/lib/vsprintf.c b/lib/vsprintf.c index a9bda0a361f..e4e9031dd9c 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -269,6 +269,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) int qualifier; /* 'h', 'l', or 'L' for integer fields */ /* 'z' support added 23/7/1999 S.H. */ /* 'z' changed to 'Z' --davidm 1/25/99 */ + /* 't' added for ptrdiff_t */ /* Reject out-of-range values early */ if (unlikely((int) size < 0)) { @@ -339,7 +340,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) /* get the conversion qualifier */ qualifier = -1; if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || - *fmt =='Z' || *fmt == 'z') { + *fmt =='Z' || *fmt == 'z' || *fmt == 't') { qualifier = *fmt; ++fmt; if (qualifier == 'l' && *fmt == 'l') { @@ -467,6 +468,8 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) num = (signed long) num; } else if (qualifier == 'Z' || qualifier == 'z') { num = va_arg(args, size_t); + } else if (qualifier == 't') { + num = va_arg(args, ptrdiff_t); } else if (qualifier == 'h') { num = (unsigned short) va_arg(args, int); if (flags & SIGN) diff --git a/mm/shmem.c b/mm/shmem.c index e64fa726a79..5a81b1ee4f7 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1773,32 +1773,27 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s return 0; } -static int shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd) +static void *shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd) { nd_set_link(nd, (char *)SHMEM_I(dentry->d_inode)); - return 0; + return NULL; } -static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd) +static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd) { struct page *page = NULL; int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL); nd_set_link(nd, res ? ERR_PTR(res) : kmap(page)); - return 0; + return page; } -static void shmem_put_link(struct dentry *dentry, struct nameidata *nd) +static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) { if (!IS_ERR(nd_get_link(nd))) { - struct page *page; - - page = find_get_page(dentry->d_inode->i_mapping, 0); - if (!page) - BUG(); + struct page *page = cookie; kunmap(page); mark_page_accessed(page); page_cache_release(page); - page_cache_release(page); } } diff --git a/net/802/tr.c b/net/802/tr.c index a755e880f4b..1bb7dc1b85c 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -251,10 +251,11 @@ void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,struct net_device * unsigned int hash; struct rif_cache *entry; unsigned char *olddata; + unsigned long flags; static const unsigned char mcast_func_addr[] = {0xC0,0x00,0x00,0x04,0x00,0x00}; - spin_lock_bh(&rif_lock); + spin_lock_irqsave(&rif_lock, flags); /* * Broadcasts are single route as stated in RFC 1042 @@ -323,7 +324,7 @@ printk("source routing for %02X:%02X:%02X:%02X:%02X:%02X\n",trh->daddr[0], else slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8); olddata = skb->data; - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); skb_pull(skb, slack); memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack); @@ -337,10 +338,11 @@ printk("source routing for %02X:%02X:%02X:%02X:%02X:%02X\n",trh->daddr[0], static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev) { unsigned int hash, rii_p = 0; + unsigned long flags; struct rif_cache *entry; - spin_lock_bh(&rif_lock); + spin_lock_irqsave(&rif_lock, flags); /* * Firstly see if the entry exists @@ -378,7 +380,7 @@ printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", if(!entry) { printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n"); - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); return; } @@ -420,7 +422,7 @@ printk("updating rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", } entry->last_used=jiffies; } - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); } /* @@ -430,9 +432,9 @@ printk("updating rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", static void rif_check_expire(unsigned long dummy) { int i; - unsigned long next_interval = jiffies + sysctl_tr_rif_timeout/2; + unsigned long flags, next_interval = jiffies + sysctl_tr_rif_timeout/2; - spin_lock_bh(&rif_lock); + spin_lock_irqsave(&rif_lock, flags); for(i =0; i < RIF_TABLE_SIZE; i++) { struct rif_cache *entry, **pentry; @@ -454,7 +456,7 @@ static void rif_check_expire(unsigned long dummy) } } - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); mod_timer(&rif_timer, next_interval); @@ -485,7 +487,7 @@ static struct rif_cache *rif_get_idx(loff_t pos) static void *rif_seq_start(struct seq_file *seq, loff_t *pos) { - spin_lock_bh(&rif_lock); + spin_lock_irq(&rif_lock); return *pos ? rif_get_idx(*pos - 1) : SEQ_START_TOKEN; } @@ -516,7 +518,7 @@ static void *rif_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void rif_seq_stop(struct seq_file *seq, void *v) { - spin_unlock_bh(&rif_lock); + spin_unlock_irq(&rif_lock); } static int rif_seq_show(struct seq_file *seq, void *v) diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 707097deac3..a5c94f11547 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -875,12 +875,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) sk->sk_sndbuf = osk->sk_sndbuf; sk->sk_state = TCP_ESTABLISHED; sk->sk_sleep = osk->sk_sleep; - - if (sock_flag(osk, SOCK_DBG)) - sock_set_flag(sk, SOCK_DBG); - - if (sock_flag(osk, SOCK_ZAPPED)) - sock_set_flag(sk, SOCK_ZAPPED); + sock_copy_flags(sk, osk); oax25 = ax25_sk(osk); @@ -1007,7 +1002,8 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct sock *sk = sock->sk; struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; ax25_dev *ax25_dev = NULL; - ax25_address *call; + ax25_uid_assoc *user; + ax25_address call; ax25_cb *ax25; int err = 0; @@ -1026,9 +1022,15 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr->fsa_ax25.sax25_family != AF_AX25) return -EINVAL; - call = ax25_findbyuid(current->euid); - if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN)) { - return -EACCES; + user = ax25_findbyuid(current->euid); + if (user) { + call = user->call; + ax25_uid_put(user); + } else { + if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) + return -EACCES; + + call = addr->fsa_ax25.sax25_call; } lock_sock(sk); @@ -1039,10 +1041,7 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) goto out; } - if (call == NULL) - ax25->source_addr = addr->fsa_ax25.sax25_call; - else - ax25->source_addr = *call; + ax25->source_addr = call; /* * User already set interface with SO_BINDTODEVICE diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c index 44b99b1ff9f..c288526da4c 100644 --- a/net/ax25/ax25_route.c +++ b/net/ax25/ax25_route.c @@ -422,8 +422,8 @@ static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat) */ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) { + ax25_uid_assoc *user; ax25_route *ax25_rt; - ax25_address *call; int err; if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL) @@ -434,16 +434,18 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr) goto put; } - if ((call = ax25_findbyuid(current->euid)) == NULL) { + user = ax25_findbyuid(current->euid); + if (user) { + ax25->source_addr = user->call; + ax25_uid_put(user); + } else { if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) { err = -EPERM; goto put; } - call = (ax25_address *)ax25->ax25_dev->dev->dev_addr; + ax25->source_addr = *(ax25_address *)ax25->ax25_dev->dev->dev_addr; } - ax25->source_addr = *call; - if (ax25_rt->digipeat != NULL) { if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { err = -ENOMEM; diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c index cea6b7d1972..a8b3822f3ee 100644 --- a/net/ax25/ax25_uid.c +++ b/net/ax25/ax25_uid.c @@ -28,6 +28,7 @@ #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/interrupt.h> +#include <linux/list.h> #include <linux/notifier.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> @@ -41,38 +42,41 @@ * Callsign/UID mapper. This is in kernel space for security on multi-amateur machines. */ -static ax25_uid_assoc *ax25_uid_list; +HLIST_HEAD(ax25_uid_list); static DEFINE_RWLOCK(ax25_uid_lock); int ax25_uid_policy = 0; -ax25_address *ax25_findbyuid(uid_t uid) +ax25_uid_assoc *ax25_findbyuid(uid_t uid) { - ax25_uid_assoc *ax25_uid; - ax25_address *res = NULL; + ax25_uid_assoc *ax25_uid, *res = NULL; + struct hlist_node *node; read_lock(&ax25_uid_lock); - for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { + ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) { if (ax25_uid->uid == uid) { - res = &ax25_uid->call; + ax25_uid_hold(ax25_uid); + res = ax25_uid; break; } } read_unlock(&ax25_uid_lock); - return NULL; + return res; } int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) { - ax25_uid_assoc *s, *ax25_uid; + ax25_uid_assoc *ax25_uid; + struct hlist_node *node; + ax25_uid_assoc *user; unsigned long res; switch (cmd) { case SIOCAX25GETUID: res = -ENOENT; read_lock(&ax25_uid_lock); - for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { + ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) { if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) { res = ax25_uid->uid; break; @@ -85,19 +89,22 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) case SIOCAX25ADDUID: if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (ax25_findbyuid(sax->sax25_uid)) + user = ax25_findbyuid(sax->sax25_uid); + if (user) { + ax25_uid_put(user); return -EEXIST; + } if (sax->sax25_uid == 0) return -EINVAL; if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL) return -ENOMEM; + atomic_set(&ax25_uid->refcount, 1); ax25_uid->uid = sax->sax25_uid; ax25_uid->call = sax->sax25_call; write_lock(&ax25_uid_lock); - ax25_uid->next = ax25_uid_list; - ax25_uid_list = ax25_uid; + hlist_add_head(&ax25_uid->uid_node, &ax25_uid_list); write_unlock(&ax25_uid_lock); return 0; @@ -106,34 +113,21 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) if (!capable(CAP_NET_ADMIN)) return -EPERM; + ax25_uid = NULL; write_lock(&ax25_uid_lock); - for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { - if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) { + ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) { + if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) break; - } } if (ax25_uid == NULL) { write_unlock(&ax25_uid_lock); return -ENOENT; } - if ((s = ax25_uid_list) == ax25_uid) { - ax25_uid_list = s->next; - write_unlock(&ax25_uid_lock); - kfree(ax25_uid); - return 0; - } - while (s != NULL && s->next != NULL) { - if (s->next == ax25_uid) { - s->next = ax25_uid->next; - write_unlock(&ax25_uid_lock); - kfree(ax25_uid); - return 0; - } - s = s->next; - } + hlist_del_init(&ax25_uid->uid_node); + ax25_uid_put(ax25_uid); write_unlock(&ax25_uid_lock); - return -ENOENT; + return 0; default: return -EINVAL; @@ -147,13 +141,11 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos) { struct ax25_uid_assoc *pt; - int i = 1; + struct hlist_node *node; + int i = 0; read_lock(&ax25_uid_lock); - if (*pos == 0) - return SEQ_START_TOKEN; - - for (pt = ax25_uid_list; pt != NULL; pt = pt->next) { + ax25_uid_for_each(pt, node, &ax25_uid_list) { if (i == *pos) return pt; ++i; @@ -164,8 +156,9 @@ static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos) static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) { ++*pos; - return (v == SEQ_START_TOKEN) ? ax25_uid_list : - ((struct ax25_uid_assoc *) v)->next; + + return hlist_entry(((ax25_uid_assoc *)v)->uid_node.next, + ax25_uid_assoc, uid_node); } static void ax25_uid_seq_stop(struct seq_file *seq, void *v) @@ -179,7 +172,6 @@ static int ax25_uid_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "Policy: %d\n", ax25_uid_policy); else { struct ax25_uid_assoc *pt = v; - seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(&pt->call)); } @@ -213,16 +205,13 @@ struct file_operations ax25_uid_fops = { */ void __exit ax25_uid_free(void) { - ax25_uid_assoc *s, *ax25_uid; + ax25_uid_assoc *ax25_uid; + struct hlist_node *node; write_lock(&ax25_uid_lock); - ax25_uid = ax25_uid_list; - while (ax25_uid != NULL) { - s = ax25_uid; - ax25_uid = ax25_uid->next; - - kfree(s); + ax25_uid_for_each(ax25_uid, node, &ax25_uid_list) { + hlist_del_init(&ax25_uid->uid_node); + ax25_uid_put(ax25_uid); } - ax25_uid_list = NULL; write_unlock(&ax25_uid_lock); } diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index a701405fab0..45efd5f4741 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1333,9 +1333,9 @@ err:; } static inline int check_leaf(struct trie *t, struct leaf *l, t_key key, int *plen, const struct flowi *flp, - struct fib_result *res, int *err) + struct fib_result *res) { - int i; + int err, i; t_key mask; struct leaf_info *li; struct hlist_head *hhead = &l->list; @@ -1348,18 +1348,18 @@ static inline int check_leaf(struct trie *t, struct leaf *l, t_key key, int *pl if (l->key != (key & mask)) continue; - if (((*err) = fib_semantic_match(&li->falh, flp, res, l->key, mask, i)) == 0) { + if ((err = fib_semantic_match(&li->falh, flp, res, l->key, mask, i)) <= 0) { *plen = i; #ifdef CONFIG_IP_FIB_TRIE_STATS t->stats.semantic_match_passed++; #endif - return 1; + return err; } #ifdef CONFIG_IP_FIB_TRIE_STATS t->stats.semantic_match_miss++; #endif } - return 0; + return 1; } static int @@ -1386,7 +1386,7 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result /* Just a leaf? */ if (IS_LEAF(n)) { - if (check_leaf(t, (struct leaf *)n, key, &plen, flp, res, &ret)) + if ((ret = check_leaf(t, (struct leaf *)n, key, &plen, flp, res)) <= 0) goto found; goto failed; } @@ -1508,7 +1508,7 @@ fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result continue; } if (IS_LEAF(n)) { - if (check_leaf(t, (struct leaf *)n, key, &plen, flp, res, &ret)) + if ((ret = check_leaf(t, (struct leaf *)n, key, &plen, flp, res)) <= 0) goto found; } backtrace: diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 3d78464f64e..badfc584997 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -349,12 +349,12 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, { struct sk_buff *skb; - ip_append_data(icmp_socket->sk, icmp_glue_bits, icmp_param, - icmp_param->data_len+icmp_param->head_len, - icmp_param->head_len, - ipc, rt, MSG_DONTWAIT); - - if ((skb = skb_peek(&icmp_socket->sk->sk_write_queue)) != NULL) { + if (ip_append_data(icmp_socket->sk, icmp_glue_bits, icmp_param, + icmp_param->data_len+icmp_param->head_len, + icmp_param->head_len, + ipc, rt, MSG_DONTWAIT) < 0) + ip_flush_pending_frames(icmp_socket->sk); + else if ((skb = skb_peek(&icmp_socket->sk->sk_write_queue)) != NULL) { struct icmphdr *icmph = skb->h.icmph; unsigned int csum = 0; struct sk_buff *skb1; diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 95473953c40..ab18a853d7c 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -450,10 +450,13 @@ static void peer_check_expire(unsigned long dummy) /* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime * interval depending on the total number of entries (more entries, * less interval). */ - peer_periodic_timer.expires = jiffies - + inet_peer_gc_maxtime - - (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ * - peer_total / inet_peer_threshold * HZ; + if (peer_total >= inet_peer_threshold) + peer_periodic_timer.expires = jiffies + inet_peer_gc_mintime; + else + peer_periodic_timer.expires = jiffies + + inet_peer_gc_maxtime + - (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ * + peer_total / inet_peer_threshold * HZ; add_timer(&peer_periodic_timer); } diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 2065944fd9e..7ded6e60f43 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -358,7 +358,7 @@ static struct crypto_tfm **ipcomp_alloc_tfms(const char *alg_name) int cpu; /* This can be any valid CPU ID so we don't need locking. */ - cpu = smp_processor_id(); + cpu = raw_smp_processor_id(); list_for_each_entry(pos, &ipcomp_tfms_list, list) { struct crypto_tfm *tfm; diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index eda1fba431a..c6baa817438 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -214,6 +214,12 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) break; case IPQ_COPY_PACKET: + if (entry->skb->ip_summed == CHECKSUM_HW && + (*errp = skb_checksum_help(entry->skb, + entry->info->outdev == NULL))) { + read_unlock_bh(&queue_lock); + return NULL; + } if (copy_range == 0 || copy_range > entry->skb->len) data_len = entry->skb->len; else @@ -385,6 +391,7 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) if (!skb_ip_make_writable(&e->skb, v->data_len)) return -ENOMEM; memcpy(e->skb->data, v->payload, v->data_len); + e->skb->ip_summed = CHECKSUM_NONE; e->skb->nfcache |= NFC_ALTERED; /* diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index ada9911118e..94a0ce1c1c9 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c @@ -61,16 +61,20 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward) if (!tcph) return 0; - if (!(einfo->operation & IPT_ECN_OP_SET_ECE - || tcph->ece == einfo->proto.tcp.ece) - && (!(einfo->operation & IPT_ECN_OP_SET_CWR - || tcph->cwr == einfo->proto.tcp.cwr))) + if ((!(einfo->operation & IPT_ECN_OP_SET_ECE) || + tcph->ece == einfo->proto.tcp.ece) && + ((!(einfo->operation & IPT_ECN_OP_SET_CWR) || + tcph->cwr == einfo->proto.tcp.cwr))) return 1; if (!skb_ip_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph))) return 0; tcph = (void *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl*4; + if ((*pskb)->ip_summed == CHECKSUM_HW && + skb_checksum_help(*pskb, inward)) + return 0; + diffs[0] = ((u_int16_t *)tcph)[6]; if (einfo->operation & IPT_ECN_OP_SET_ECE) tcph->ece = einfo->proto.tcp.ece; @@ -79,13 +83,10 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward) diffs[1] = ((u_int16_t *)tcph)[6]; diffs[0] = diffs[0] ^ 0xFFFF; - if ((*pskb)->ip_summed != CHECKSUM_HW) + if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) tcph->check = csum_fold(csum_partial((char *)diffs, sizeof(diffs), tcph->check^0xFFFF)); - else - if (skb_checksum_help(*pskb, inward)) - return 0; (*pskb)->nfcache |= NFC_ALTERED; return 1; } diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c index 1049050b2bf..7b84a254440 100644 --- a/net/ipv4/netfilter/ipt_TCPMSS.c +++ b/net/ipv4/netfilter/ipt_TCPMSS.c @@ -61,6 +61,10 @@ ipt_tcpmss_target(struct sk_buff **pskb, if (!skb_ip_make_writable(pskb, (*pskb)->len)) return NF_DROP; + if ((*pskb)->ip_summed == CHECKSUM_HW && + skb_checksum_help(*pskb, out == NULL)) + return NF_DROP; + iph = (*pskb)->nh.iph; tcplen = (*pskb)->len - iph->ihl*4; @@ -186,9 +190,6 @@ ipt_tcpmss_target(struct sk_buff **pskb, newmss); retmodified: - /* We never hw checksum SYN packets. */ - BUG_ON((*pskb)->ip_summed == CHECKSUM_HW); - (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED; return IPT_CONTINUE; } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index ddb6ce4ecff..69b1fcf7007 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -584,7 +584,7 @@ static inline void skb_entail(struct sock *sk, struct tcp_sock *tp, sk_charge_skb(sk, skb); if (!sk->sk_send_head) sk->sk_send_head = skb; - else if (tp->nonagle&TCP_NAGLE_PUSH) + if (tp->nonagle & TCP_NAGLE_PUSH) tp->nonagle &= ~TCP_NAGLE_PUSH; } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 5d91213d34c..67c670886c1 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -242,9 +242,14 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum) tcp_port_rover = rover; spin_unlock(&tcp_portalloc_lock); - /* Exhausted local port range during search? */ + /* Exhausted local port range during search? It is not + * possible for us to be holding one of the bind hash + * locks if this test triggers, because if 'remaining' + * drops to zero, we broke out of the do/while loop at + * the top level, not from the 'break;' statement. + */ ret = 1; - if (remaining <= 0) + if (unlikely(remaining <= 0)) goto fail; /* OK, here is the one we will use. HEAD is diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 566045e5843..dd30dd137b7 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -925,10 +925,6 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_ limit = min(send_win, cong_win); - /* If sk_send_head can be sent fully now, just do it. */ - if (skb->len <= limit) - return 0; - if (sysctl_tcp_tso_win_divisor) { u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache); diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 423feb46ccc..135383ef538 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -354,7 +354,7 @@ static struct crypto_tfm **ipcomp6_alloc_tfms(const char *alg_name) int cpu; /* This can be any valid CPU ID so we don't need locking. */ - cpu = smp_processor_id(); + cpu = raw_smp_processor_id(); list_for_each_entry(pos, &ipcomp6_tfms_list, list) { struct crypto_tfm *tfm; diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 5493180f0d4..a16df5b27c8 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -211,6 +211,12 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) break; case IPQ_COPY_PACKET: + if (entry->skb->ip_summed == CHECKSUM_HW && + (*errp = skb_checksum_help(entry->skb, + entry->info->outdev == NULL))) { + read_unlock_bh(&queue_lock); + return NULL; + } if (copy_range == 0 || copy_range > entry->skb->len) data_len = entry->skb->len; else @@ -381,6 +387,7 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) if (!skb_ip_make_writable(&e->skb, v->data_len)) return -ENOMEM; memcpy(e->skb->data, v->payload, v->data_len); + e->skb->ip_summed = CHECKSUM_NONE; e->skb->nfcache |= NFC_ALTERED; /* diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index f6e288dc116..ef29cfd936d 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -158,9 +158,14 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum) tcp_port_rover = rover; spin_unlock(&tcp_portalloc_lock); - /* Exhausted local port range during search? */ + /* Exhausted local port range during search? It is not + * possible for us to be holding one of the bind hash + * locks if this test triggers, because if 'remaining' + * drops to zero, we broke out of the do/while loop at + * the top level, not from the 'break;' statement. + */ ret = 1; - if (remaining <= 0) + if (unlikely(remaining <= 0)) goto fail; /* OK, here is the one we will use. */ diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 31ed4a9a1d0..162a85fed15 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -459,12 +459,7 @@ static struct sock *nr_make_new(struct sock *osk) sk->sk_sndbuf = osk->sk_sndbuf; sk->sk_state = TCP_ESTABLISHED; sk->sk_sleep = osk->sk_sleep; - - if (sock_flag(osk, SOCK_ZAPPED)) - sock_set_flag(sk, SOCK_ZAPPED); - - if (sock_flag(osk, SOCK_DBG)) - sock_set_flag(sk, SOCK_DBG); + sock_copy_flags(sk, osk); skb_queue_head_init(&nr->ack_queue); skb_queue_head_init(&nr->reseq_queue); @@ -541,7 +536,8 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct nr_sock *nr = nr_sk(sk); struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr; struct net_device *dev; - ax25_address *user, *source; + ax25_uid_assoc *user; + ax25_address *source; lock_sock(sk); if (!sock_flag(sk, SOCK_ZAPPED)) { @@ -580,16 +576,19 @@ static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) } else { source = &addr->fsa_ax25.sax25_call; - if ((user = ax25_findbyuid(current->euid)) == NULL) { + user = ax25_findbyuid(current->euid); + if (user) { + nr->user_addr = user->call; + ax25_uid_put(user); + } else { if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) { release_sock(sk); dev_put(dev); return -EPERM; } - user = source; + nr->user_addr = *source; } - nr->user_addr = *user; nr->source_addr = *source; } @@ -609,7 +608,8 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr, struct sock *sk = sock->sk; struct nr_sock *nr = nr_sk(sk); struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr; - ax25_address *user, *source = NULL; + ax25_address *source = NULL; + ax25_uid_assoc *user; struct net_device *dev; lock_sock(sk); @@ -650,16 +650,19 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr, } source = (ax25_address *)dev->dev_addr; - if ((user = ax25_findbyuid(current->euid)) == NULL) { + user = ax25_findbyuid(current->euid); + if (user) { + nr->user_addr = user->call; + ax25_uid_put(user); + } else { if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) { dev_put(dev); release_sock(sk); return -EPERM; } - user = source; + nr->user_addr = *source; } - nr->user_addr = *user; nr->source_addr = *source; nr->device = dev; diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 7eb6a5bf93e..5480caf8ccc 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -556,12 +556,7 @@ static struct sock *rose_make_new(struct sock *osk) sk->sk_sndbuf = osk->sk_sndbuf; sk->sk_state = TCP_ESTABLISHED; sk->sk_sleep = osk->sk_sleep; - - if (sock_flag(osk, SOCK_ZAPPED)) - sock_set_flag(sk, SOCK_ZAPPED); - - if (sock_flag(osk, SOCK_DBG)) - sock_set_flag(sk, SOCK_DBG); + sock_copy_flags(sk, osk); init_timer(&rose->timer); init_timer(&rose->idletimer); @@ -631,7 +626,8 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct rose_sock *rose = rose_sk(sk); struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr; struct net_device *dev; - ax25_address *user, *source; + ax25_address *source; + ax25_uid_assoc *user; int n; if (!sock_flag(sk, SOCK_ZAPPED)) @@ -656,14 +652,17 @@ static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) source = &addr->srose_call; - if ((user = ax25_findbyuid(current->euid)) == NULL) { + user = ax25_findbyuid(current->euid); + if (user) { + rose->source_call = user->call; + ax25_uid_put(user); + } else { if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) return -EACCES; - user = source; + rose->source_call = *source; } rose->source_addr = addr->srose_addr; - rose->source_call = *user; rose->device = dev; rose->source_ndigis = addr->srose_ndigis; @@ -690,8 +689,8 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le struct rose_sock *rose = rose_sk(sk); struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr; unsigned char cause, diagnostic; - ax25_address *user; struct net_device *dev; + ax25_uid_assoc *user; int n; if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { @@ -741,12 +740,14 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le if ((dev = rose_dev_first()) == NULL) return -ENETUNREACH; - if ((user = ax25_findbyuid(current->euid)) == NULL) + user = ax25_findbyuid(current->euid); + if (!user) return -EINVAL; memcpy(&rose->source_addr, dev->dev_addr, ROSE_ADDR_LEN); - rose->source_call = *user; + rose->source_call = user->call; rose->device = dev; + ax25_uid_put(user); rose_insert_socket(sk); /* Finish the bind */ } diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index ff73ebb912b..25da6f699fd 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -994,8 +994,10 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) * 1. The frame isn't for us, * 2. It isn't "owned" by any existing route. */ - if (frametype != ROSE_CALL_REQUEST) /* XXX */ - return 0; + if (frametype != ROSE_CALL_REQUEST) { /* XXX */ + res = 0; + goto out; + } len = (((skb->data[3] >> 4) & 0x0F) + 1) / 2; len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2; diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 8edefd5d095..0d066c96534 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -438,6 +438,7 @@ struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops) if (!ops->init || ops->init(sch, NULL) == 0) return sch; + qdisc_destroy(sch); errout: return NULL; } diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 98d49ec9b74..b74f7772b57 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -57,6 +57,7 @@ static struct snmp_mib sctp_snmp_list[] = { SNMP_MIB_ITEM("SctpReasmUsrMsgs", SCTP_MIB_REASMUSRMSGS), SNMP_MIB_ITEM("SctpOutSCTPPacks", SCTP_MIB_OUTSCTPPACKS), SNMP_MIB_ITEM("SctpInSCTPPacks", SCTP_MIB_INSCTPPACKS), + SNMP_MIB_SENTINEL }; /* Return the current value of a particular entry in the mib by adding its diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 24c21f2a33a..5a7265aeaf8 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -185,9 +185,7 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, sg->page = body->pages[i]; sg->offset = offset; sg->length = thislen; - kmap(sg->page); /* XXX kmap_atomic? */ crypto_digest_update(tfm, sg, 1); - kunmap(sg->page); len -= thislen; i++; offset = 0; diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 9b9f94c915d..09ffca54b37 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -359,11 +359,16 @@ handle_modversions(struct module *mod, struct elf_info *info, /* ignore __this_module, it will be resolved shortly */ if (strcmp(symname, MODULE_SYMBOL_PREFIX "__this_module") == 0) break; -#ifdef STT_REGISTER +/* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */ +#if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER) +/* add compatibility with older glibc */ +#ifndef STT_SPARC_REGISTER +#define STT_SPARC_REGISTER STT_REGISTER +#endif if (info->hdr->e_machine == EM_SPARC || info->hdr->e_machine == EM_SPARCV9) { /* Ignore register directives. */ - if (ELF_ST_TYPE(sym->st_info) == STT_REGISTER) + if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER) break; } #endif diff --git a/sound/Kconfig b/sound/Kconfig index ee794ae0604..b65ee4701f9 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -77,7 +77,7 @@ source "sound/parisc/Kconfig" endmenu menu "Open Sound System" - depends on SOUND!=n && (BROKEN || (!SPARC32 && !SPARC64)) + depends on SOUND!=n config SOUND_PRIME tristate "Open Sound System (DEPRECATED)" diff --git a/sound/core/Makefile b/sound/core/Makefile index 764ac184b22..969d75528bd 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -5,7 +5,7 @@ snd-objs := sound.o init.o memory.o info.o control.o misc.o \ device.o wrappers.o -ifeq ($(CONFIG_ISA),y) +ifeq ($(CONFIG_ISA_DMA_API),y) snd-objs += isadma.o endif ifeq ($(CONFIG_SND_OSSEMUL),y) diff --git a/sound/core/sound.c b/sound/core/sound.c index 7612884f530..3271e924549 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -432,7 +432,7 @@ EXPORT_SYMBOL(snd_device_new); EXPORT_SYMBOL(snd_device_register); EXPORT_SYMBOL(snd_device_free); /* isadma.c */ -#ifdef CONFIG_ISA +#ifdef CONFIG_ISA_DMA_API EXPORT_SYMBOL(snd_dma_program); EXPORT_SYMBOL(snd_dma_disable); EXPORT_SYMBOL(snd_dma_pointer); diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 148a856a43a..be4ea60a367 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -1,7 +1,7 @@ # ALSA ISA drivers menu "ISA devices" - depends on SND!=n && ISA + depends on SND!=n && ISA && ISA_DMA_API config SND_AD1848_LIB tristate diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index 7bd95ceab7c..953e5f3ea03 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -6,7 +6,7 @@ # Prompt user for primary drivers. config SOUND_BT878 tristate "BT878 audio dma" - depends on SOUND_PRIME + depends on SOUND_PRIME && PCI ---help--- Audio DMA support for bt878 based grabber boards. As you might have already noticed, bt878 is listed with two functions in /proc/pci. @@ -80,14 +80,14 @@ config SOUND_EMU10K1 config MIDI_EMU10K1 bool "Creative SBLive! MIDI (EXPERIMENTAL)" - depends on SOUND_EMU10K1 && EXPERIMENTAL + depends on SOUND_EMU10K1 && EXPERIMENTAL && ISA_DMA_API help Say Y if you want to be able to use the OSS /dev/sequencer interface. This code is still experimental. config SOUND_FUSION tristate "Crystal SoundFusion (CS4280/461x)" - depends on SOUND_PRIME + depends on SOUND_PRIME && PCI help This module drives the Crystal SoundFusion devices (CS4280/46xx series) when wired as native sound drivers with AC97 codecs. If @@ -95,7 +95,7 @@ config SOUND_FUSION config SOUND_CS4281 tristate "Crystal Sound CS4281" - depends on SOUND_PRIME + depends on SOUND_PRIME && PCI help Picture and feature list at <http://www.pcbroker.com/crystal4281.html>. @@ -179,7 +179,7 @@ config SOUND_HARMONY config SOUND_SONICVIBES tristate "S3 SonicVibes" - depends on SOUND_PRIME + depends on SOUND_PRIME && PCI help Say Y or M if you have a PCI sound card utilizing the S3 SonicVibes chipset. To find out if your sound card uses a @@ -226,7 +226,7 @@ config SOUND_AU1550_AC97 config SOUND_TRIDENT tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core" - depends on SOUND_PRIME + depends on SOUND_PRIME && PCI ---help--- Say Y or M if you have a PCI sound card utilizing the Trident 4DWave-DX/NX chipset or your mother board chipset has SiS 7018 @@ -503,7 +503,7 @@ config SOUND_VIA82CXXX config MIDI_VIA82CXXX bool "VIA 82C686 MIDI" - depends on SOUND_VIA82CXXX + depends on SOUND_VIA82CXXX && ISA_DMA_API help Answer Y to use the MIDI interface of the Via686. You may need to enable this in the BIOS before it will work. This is for connection @@ -512,7 +512,7 @@ config MIDI_VIA82CXXX config SOUND_OSS tristate "OSS sound modules" - depends on SOUND_PRIME + depends on SOUND_PRIME && ISA_DMA_API help OSS is the Open Sound System suite of sound card drivers. They make sound programming easier since they provide a common API. Say Y or diff --git a/sound/oss/Makefile b/sound/oss/Makefile index db9afb61d6f..9bf3ee544d8 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -80,7 +80,7 @@ obj-$(CONFIG_SOUND_ALI5455) += ali5455.o ac97_codec.o obj-$(CONFIG_SOUND_IT8172) += ite8172.o ac97_codec.o obj-$(CONFIG_SOUND_FORTE) += forte.o ac97_codec.o -obj-$(CONFIG_SOUND_AD1980) += ac97_plugin_ad1980.o +obj-$(CONFIG_SOUND_AD1980) += ac97_plugin_ad1980.o ac97_codec.o obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o ifeq ($(CONFIG_MIDI_EMU10K1),y) diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c index 7e9f667cf7a..b9a640fe48b 100644 --- a/sound/oss/i810_audio.c +++ b/sound/oss/i810_audio.c @@ -3430,9 +3430,9 @@ out_iospace: release_mem_region(card->iobase_mmio_phys, 256); } out_pio: - release_region(card->iobase, 64); -out_region2: release_region(card->ac97base, 256); +out_region2: + release_region(card->iobase, 64); out_region1: pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH, card->channel, card->chandma); diff --git a/sound/oss/vidc.h b/sound/oss/vidc.h index bab7044572d..d5b8064dc56 100644 --- a/sound/oss/vidc.h +++ b/sound/oss/vidc.h @@ -10,10 +10,6 @@ * VIDC sound function prototypes */ -/* vidc.c */ - -extern int vidc_busy; - /* vidc_fill.S */ /* diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 6d7a00f34d8..26b42bb20a0 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -314,7 +314,7 @@ config SND_YMFPCI config SND_ALS4000 tristate "Avance Logic ALS4000" - depends on SND + depends on SND && ISA_DMA_API select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM |